kol-insight/backend/tests/test_yuntu_api_params.py
zfc 70ba2f1868 feat(frontend): 优化前端性能与修复文字选择问题
- VideoAnalysis 组件性能优化:使用 memo/useMemo/useCallback,添加详情缓存和虚拟滚动
- 修复 Ant Design Modal/Descriptions/Table 内文字无法复制的问题
- 新增 AntdProvider 组件,解决 layout.tsx 不能加 'use client' 的问题
- 添加云图 API 参数测试,更新 CLAUDE.md 文档

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 12:04:47 +08:00

317 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
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"