test_api.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. from fastapi.testclient import TestClient
  2. from content_agent import api
  3. from content_agent.integrations.mock_platform import MockPlatformClient
  4. from content_agent.run_service import RunService
  5. from tests.p1_helpers import FakeDemandSource, FakeQueryVariantClient
  6. def test_api_runs_and_queries_mock_chain(tmp_path, monkeypatch):
  7. monkeypatch.setattr(
  8. api,
  9. "service",
  10. RunService(
  11. runtime_root=tmp_path / "runtime" / "v1",
  12. demand_source=FakeDemandSource(),
  13. query_variant_client=FakeQueryVariantClient(),
  14. ),
  15. )
  16. client = TestClient(api.app)
  17. response = client.post("/runs", json={"platform": "douyin", "platform_mode": "mock"})
  18. assert response.status_code == 200
  19. payload = response.json()
  20. run_id = payload["run_id"]
  21. assert payload["platform_mode"] == "mock"
  22. assert payload["policy_run_id"].startswith("policy_run_")
  23. assert payload["policy_bundle_id"] == "douyin_policy_bundle_v1"
  24. assert payload["strategy_version"] == "V1"
  25. for path in [
  26. f"/runs/{run_id}",
  27. f"/runs/{run_id}/discovered-content-items",
  28. f"/runs/{run_id}/rule-decisions",
  29. f"/runs/{run_id}/source-path-records",
  30. f"/runs/{run_id}/final-output",
  31. f"/runs/{run_id}/strategy-review",
  32. f"/runs/{run_id}/validation",
  33. ]:
  34. get_response = client.get(path)
  35. assert get_response.status_code == 200, path
  36. review = client.get(f"/runs/{run_id}/strategy-review").json()["data"]
  37. assert review["summary"]["pooled_content_count"] == 1
  38. assert review["suggestions"]
  39. validation = client.get(f"/runs/{run_id}/validation").json()
  40. assert validation["status"] == "pass"
  41. summary = client.get(f"/runs/{run_id}").json()
  42. assert summary["validation_status"] == "pass"
  43. def test_api_defaults_to_real_platform_mode_but_can_select_mock(tmp_path, monkeypatch):
  44. selected_modes = []
  45. def fake_platform_client(self, platform, platform_mode):
  46. selected_modes.append((platform, platform_mode))
  47. return MockPlatformClient()
  48. monkeypatch.setattr(RunService, "_platform_client", fake_platform_client)
  49. monkeypatch.setattr(
  50. api,
  51. "service",
  52. RunService(
  53. runtime_root=tmp_path / "runtime" / "v1",
  54. demand_source=FakeDemandSource(),
  55. query_variant_client=FakeQueryVariantClient(),
  56. ),
  57. )
  58. client = TestClient(api.app)
  59. default_response = client.post("/runs", json={})
  60. mock_response = client.post("/runs", json={"platform_mode": "mock"})
  61. assert default_response.status_code == 200
  62. assert default_response.json()["platform_mode"] == "real"
  63. assert mock_response.status_code == 200
  64. assert mock_response.json()["platform_mode"] == "mock"
  65. assert selected_modes == [("douyin", "real"), ("douyin", "mock")]
  66. def test_api_rejects_non_douyin_real_platform(tmp_path, monkeypatch):
  67. monkeypatch.setattr(
  68. api,
  69. "service",
  70. RunService(
  71. runtime_root=tmp_path / "runtime" / "v1",
  72. demand_source=FakeDemandSource(),
  73. query_variant_client=FakeQueryVariantClient(),
  74. ),
  75. )
  76. client = TestClient(api.app)
  77. response = client.post(
  78. "/runs", json={"platform": "other_platform", "platform_mode": "real"}
  79. )
  80. assert response.status_code == 400
  81. assert response.json()["detail"]["error_code"] == "INVALID_REQUEST"
  82. def test_api_returns_partial_success_as_successful_response(tmp_path, monkeypatch):
  83. service = RunService(
  84. runtime_root=tmp_path / "runtime" / "v1",
  85. demand_source=FakeDemandSource(),
  86. query_variant_client=FakeQueryVariantClient(),
  87. )
  88. service._platform_client = lambda platform, platform_mode: _PartialFailurePlatformClient()
  89. monkeypatch.setattr(api, "service", service)
  90. client = TestClient(api.app)
  91. response = client.post("/runs", json={"platform": "douyin", "platform_mode": "real"})
  92. assert response.status_code == 200
  93. payload = response.json()
  94. assert payload["status"] == "partial_success"
  95. summary = client.get(f"/runs/{payload['run_id']}").json()
  96. assert summary["status"] == "partial_success"
  97. def test_api_rejects_legacy_run_identifier_field(tmp_path, monkeypatch):
  98. monkeypatch.setattr(api, "service", RunService(runtime_root=tmp_path / "runtime" / "v1"))
  99. client = TestClient(api.app)
  100. legacy_run_key = "tr" + "ace_id"
  101. response = client.post(
  102. "/runs",
  103. json={"platform": "douyin", "platform_mode": "mock", legacy_run_key: "legacy_run_001"},
  104. )
  105. assert response.status_code == 422
  106. class _PartialFailurePlatformClient:
  107. def __init__(self) -> None:
  108. self.mock = MockPlatformClient()
  109. def search(self, search_query: dict) -> list[dict]:
  110. if search_query["search_query_id"] == "q_002":
  111. raise RuntimeError("temporary platform failure")
  112. return self.mock.search(search_query)