test_dual_channel_normalization.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. """V3-M1D: dual-channel canonical isomorphism + real dispatch."""
  2. from __future__ import annotations
  3. import pytest
  4. from content_agent.errors import ContentAgentError, ErrorCode
  5. from content_agent.integrations.douyin import CrawapiDouyinClient
  6. from content_agent.integrations.kuaishou import (
  7. CrawapiKuaishouClient,
  8. _normalize_kuaishou_item,
  9. )
  10. from content_agent.integrations.shipinhao import (
  11. CrawapiShipinhaoClient,
  12. _normalize_shipinhao_item,
  13. )
  14. from content_agent.run_service import RunService
  15. _QUERY = {"search_query_id": "q_001", "search_query": "彩虹", "discovery_start_source": "pattern_itemset"}
  16. def _douyin_client():
  17. return CrawapiDouyinClient(
  18. base_url="http://crawapi.test",
  19. keyword_path="/k",
  20. blogger_path="/b",
  21. detail_path="/d",
  22. http_client=object(),
  23. )
  24. def test_douyin_shipinhao_and_kuaishou_share_required_canonical_keys():
  25. douyin_item = _douyin_client()._normalize_content_item(
  26. _QUERY,
  27. {"aweme_id": "a1", "author": {"sec_uid": "u1", "nickname": "n"}, "video": {"play_addr": {"url_list": ["http://v"]}}},
  28. 1,
  29. True,
  30. "12",
  31. )
  32. sph_item = _normalize_shipinhao_item(
  33. _QUERY,
  34. {"channel_content_id": "c1", "channel_account_id": "acc", "title": "彩虹 #彩虹", "video_url_list": [{"video_url": "http://v"}]},
  35. 1,
  36. True,
  37. "12",
  38. )
  39. ks_item = _normalize_kuaishou_item(
  40. _QUERY,
  41. {
  42. "channel_content_id": "k1",
  43. "content_link": "https://www.kuaishou.com/short-video/k1",
  44. "channel_account_id": "acc",
  45. "channel_account_name": "快手作者",
  46. "title": "彩虹 #彩虹",
  47. "video_url_list": [{"video_url": "http://v"}],
  48. },
  49. 1,
  50. False,
  51. "",
  52. )
  53. assert set(douyin_item) == set(sph_item)
  54. assert set(douyin_item).issubset(set(ks_item))
  55. assert douyin_item["platform"] == "douyin"
  56. assert sph_item["platform"] == "shipinhao"
  57. assert ks_item["platform"] == "kuaishou"
  58. assert ks_item["platform_content_url"].endswith("/k1")
  59. def test_real_dispatch_builds_registered_platform_clients(monkeypatch):
  60. monkeypatch.setattr(
  61. CrawapiDouyinClient, "from_env", classmethod(lambda cls: object.__new__(cls))
  62. )
  63. monkeypatch.setattr(
  64. CrawapiKuaishouClient, "from_env", classmethod(lambda cls: object.__new__(cls))
  65. )
  66. monkeypatch.setattr(
  67. CrawapiShipinhaoClient, "from_env", classmethod(lambda cls: object.__new__(cls))
  68. )
  69. service = object.__new__(RunService)
  70. assert isinstance(service._platform_client("douyin", "real"), CrawapiDouyinClient)
  71. assert isinstance(service._platform_client("kuaishou", "real"), CrawapiKuaishouClient)
  72. assert isinstance(service._platform_client("shipinhao", "real"), CrawapiShipinhaoClient)
  73. def test_unsupported_real_platform_raises():
  74. service = object.__new__(RunService)
  75. with pytest.raises(ContentAgentError) as exc:
  76. service._platform_client("bilibili", "real")
  77. assert exc.value.error_code == ErrorCode.INVALID_REQUEST