""" Tests for Yuntu API Parameter Format (T-027) 根据 doc/temp 的正确格式: 1. 日期格式: YYYYMMDD (如 20251014),不是 YYYY-MM-DD 2. Cookie 头: 直接使用 auth_token 完整值 3. industry_id: 字符串格式 ["20"],不是整数 4. Cookie 获取: 随机选取任意一组 aadvid/auth_token """ import pytest from datetime import datetime, date from unittest.mock import AsyncMock, patch, MagicMock import httpx class TestYuntuAPIParameterFormat: """验证 API 调用参数格式正确性 (T-027)""" async def test_date_format_yyyymmdd(self): """日期格式必须为 YYYYMMDD,不是 YYYY-MM-DD""" from app.services.yuntu_api import call_yuntu_api mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"status": 0, "data": {"a3_increase_cnt": "100"}} mock_client = AsyncMock() mock_client.post.return_value = mock_response mock_client.__aenter__.return_value = mock_client mock_client.__aexit__.return_value = None with patch("httpx.AsyncClient", return_value=mock_client): await call_yuntu_api( item_id="video_001", publish_time=datetime(2025, 10, 14), industry_id="12", aadvid="1648829117232140", auth_token="sessionid=f9dfd57df6935afd1255bdc8f0dd0e4b", ) call_args = mock_client.post.call_args json_data = call_args.kwargs["json"] # 关键验证:日期格式是 YYYYMMDD assert json_data["start_date"] == "20251014", f"Expected '20251014', got '{json_data['start_date']}'" assert json_data["end_date"] == "20251113", f"Expected '20251113', got '{json_data['end_date']}'" async def test_cookie_header_uses_auth_token_directly(self): """Cookie 头应直接使用 auth_token 完整值""" from app.services.yuntu_api import call_yuntu_api mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"status": 0, "data": {}} mock_client = AsyncMock() mock_client.post.return_value = mock_response mock_client.__aenter__.return_value = mock_client mock_client.__aexit__.return_value = None auth_token = "sessionid=f9dfd57df6935afd1255bdc8f0dd0e4b" with patch("httpx.AsyncClient", return_value=mock_client): await call_yuntu_api( item_id="video_001", publish_time=datetime(2025, 10, 14), industry_id="12", aadvid="1648829117232140", auth_token=auth_token, ) call_args = mock_client.post.call_args headers = call_args.kwargs["headers"] # 关键验证:Cookie 直接使用 auth_token 完整值 assert headers["Cookie"] == auth_token, f"Expected Cookie='{auth_token}', got '{headers['Cookie']}'" async def test_industry_id_as_string_array(self): """industry_id_list 应为字符串数组 ["12"],不是整数""" from app.services.yuntu_api import call_yuntu_api mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"status": 0, "data": {}} mock_client = AsyncMock() mock_client.post.return_value = mock_response mock_client.__aenter__.return_value = mock_client mock_client.__aexit__.return_value = None with patch("httpx.AsyncClient", return_value=mock_client): await call_yuntu_api( item_id="video_001", publish_time=datetime(2025, 10, 14), industry_id="12", # 字符串 aadvid="1648829117232140", auth_token="sessionid=xxx", ) call_args = mock_client.post.call_args json_data = call_args.kwargs["json"] # 关键验证:industry_id_list 是字符串数组 assert json_data["industry_id_list"] == ["12"], f"Expected ['12'], got {json_data['industry_id_list']}" async def test_url_contains_aadvid(self): """URL 必须包含 aadvid 参数""" from app.services.yuntu_api import call_yuntu_api mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"status": 0, "data": {}} mock_client = AsyncMock() mock_client.post.return_value = mock_response mock_client.__aenter__.return_value = mock_client mock_client.__aexit__.return_value = None aadvid = "1648829117232140" with patch("httpx.AsyncClient", return_value=mock_client): await call_yuntu_api( item_id="video_001", publish_time=datetime(2025, 10, 14), industry_id="12", aadvid=aadvid, auth_token="sessionid=xxx", ) call_args = mock_client.post.call_args url = call_args.args[0] # 关键验证:URL 包含 aadvid assert f"aadvid={aadvid}" in url, f"URL should contain 'aadvid={aadvid}', got '{url}'" async def test_fixed_parameters(self): """验证固定参数值正确""" from app.services.yuntu_api import call_yuntu_api mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"status": 0, "data": {}} mock_client = AsyncMock() mock_client.post.return_value = mock_response mock_client.__aenter__.return_value = mock_client mock_client.__aexit__.return_value = None with patch("httpx.AsyncClient", return_value=mock_client): await call_yuntu_api( item_id="video_001", publish_time=datetime(2025, 10, 14), industry_id="12", aadvid="1648829117232140", auth_token="sessionid=xxx", ) call_args = mock_client.post.call_args json_data = call_args.kwargs["json"] # 验证固定参数 assert json_data["is_my_video"] == "0" assert json_data["object_type"] == 2 assert json_data["assist_type"] == 3 assert json_data["assist_video_type"] == 3 assert json_data["trigger_point_id_list"] == ["610000", "610300", "610301"] async def test_end_date_is_start_plus_30_days(self): """end_date 应为 start_date + 30 天""" from app.services.yuntu_api import call_yuntu_api mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"status": 0, "data": {}} mock_client = AsyncMock() mock_client.post.return_value = mock_response mock_client.__aenter__.return_value = mock_client mock_client.__aexit__.return_value = None # 测试日期:2025-01-15,+30天 = 2025-02-14 with patch("httpx.AsyncClient", return_value=mock_client): await call_yuntu_api( item_id="video_001", publish_time=datetime(2025, 1, 15), industry_id="12", aadvid="123", auth_token="sessionid=xxx", ) call_args = mock_client.post.call_args json_data = call_args.kwargs["json"] assert json_data["start_date"] == "20250115" assert json_data["end_date"] == "20250214" async def test_parse_a3_metrics_as_strings(self): """API 返回的 A3 指标是字符串类型,需正确解析""" from app.services.yuntu_api import parse_analysis_response # 实际 API 响应示例(A3 是字符串) response = { "status": 0, "msg": "ok", "data": { "object_id": "7560751618711457062", "cost": 785000, "ad_a3_increase_cnt": "36902", "natural_a3_increase_cnt": "1652169", "a3_increase_cnt": "1689071", } } result = parse_analysis_response(response) # 解析后应转为整数 assert result["a3_increase_cnt"] == 1689071 assert result["ad_a3_increase_cnt"] == 36902 assert result["natural_a3_increase_cnt"] == 1652169 assert result["cost"] == 785000 class TestSessionPoolRandomSelection: """验证 Cookie 池随机选取逻辑 (T-027)""" async def test_get_random_config(self): """应随机选取任意一组配置,不按 brand_id 匹配""" from app.services.session_pool import SessionPool, CookieConfig pool = SessionPool() # 模拟刷新后的数据 pool._configs = [ CookieConfig( brand_id="533661", aadvid="1648829117232140", auth_token="sessionid=aaa", industry_id=20, brand_name="Test1", ), CookieConfig( brand_id="10186612", aadvid="1234567890", auth_token="sessionid=bbb", industry_id=30, brand_name="Test2", ), ] # 调用随机获取 config = pool.get_random_config() # 应返回一个有效配置 assert config is not None assert "aadvid" in config assert "auth_token" in config class TestIntegrationWithRealFormat: """集成测试:验证完整调用流程""" async def test_full_api_call_format(self): """完整验证 API 调用格式""" from app.services.yuntu_api import call_yuntu_api mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = { "status": 0, "msg": "ok", "data": { "object_id": "7560751618711457062", "cost": 785000, "ad_a3_increase_cnt": "36902", "natural_a3_increase_cnt": "1652169", "a3_increase_cnt": "1689071", } } mock_client = AsyncMock() mock_client.post.return_value = mock_response mock_client.__aenter__.return_value = mock_client mock_client.__aexit__.return_value = None with patch("httpx.AsyncClient", return_value=mock_client): result = await call_yuntu_api( item_id="7560751618711457062", publish_time=datetime(2025, 10, 14), industry_id="12", aadvid="1648829117232140", auth_token="sessionid=f9dfd57df6935afd1255bdc8f0dd0e4b", ) # 验证调用参数 call_args = mock_client.post.call_args url = call_args.args[0] json_data = call_args.kwargs["json"] headers = call_args.kwargs["headers"] # 1. URL 包含 aadvid assert "aadvid=1648829117232140" in url # 2. 日期格式 YYYYMMDD assert json_data["start_date"] == "20251014" assert json_data["end_date"] == "20251113" # 3. industry_id 字符串数组 assert json_data["industry_id_list"] == ["12"] # 4. Cookie 直接使用 auth_token assert headers["Cookie"] == "sessionid=f9dfd57df6935afd1255bdc8f0dd0e4b" # 验证返回结果 assert result["status"] == 0 assert result["data"]["a3_increase_cnt"] == "1689071"