test_formal_state_models.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. from __future__ import annotations
  2. from uuid import uuid4
  3. import pytest
  4. from pydantic import ValidationError
  5. from app.schemas import (
  6. AcquisitionRunSummarySchema,
  7. CandidateItemSchema,
  8. ErrorResponse,
  9. Page,
  10. )
  11. from core.config import CreationDbConfig
  12. from decode_content.models import (
  13. IngestRecord,
  14. KnowledgeParticle,
  15. PayloadDraft,
  16. ReadResult,
  17. ScopeResult,
  18. )
  19. from pipeline.models import PipelineJob, PipelineRun, ResumeCursor
  20. def test_creation_db_config_reads_ck_db_without_open_aigc(tmp_path):
  21. env_file = tmp_path / ".env"
  22. env_file.write_text(
  23. "\n".join(
  24. [
  25. "OPEN_AIGC_PG_HOST=wrong-open-aigc",
  26. "OPEN_AIGC_PG_USER=wrong-user",
  27. "CK_DB_HOST=127.0.0.1",
  28. "CK_DB_PORT=6543",
  29. "CK_DB_NAME=creation_knowledge_prod",
  30. "CK_DB_USER=ck_app",
  31. "CK_DB_PASSWORD=secret",
  32. "CK_DB_SCHEMA=creation_knowledge",
  33. "CK_DB_POOL_MIN=2",
  34. "CK_DB_POOL_MAX=8",
  35. ]
  36. ),
  37. encoding="utf-8",
  38. )
  39. cfg = CreationDbConfig.from_env(env_file)
  40. assert cfg.host == "127.0.0.1"
  41. assert cfg.port == 6543
  42. assert cfg.user == "ck_app"
  43. assert cfg.database == "creation_knowledge_prod"
  44. assert cfg.schema == "creation_knowledge"
  45. assert cfg.pool_min == 2
  46. assert cfg.pool_max == 8
  47. def test_decode_content_models_are_contract_shaped():
  48. item_id = uuid4()
  49. read = ReadResult(
  50. text="一条创作判断",
  51. cards=[{"index": 1, "kind": "image", "content": "构图说明"}],
  52. media={"platform": "xiaohongshu"},
  53. )
  54. knowledge = KnowledgeParticle(
  55. item_id=item_id,
  56. particle_type="how",
  57. title="先定受众再写脚本",
  58. content={"steps": [{"input": "目标受众", "directive": "收窄", "output": "脚本方向"}]},
  59. )
  60. scope = ScopeResult(
  61. item_id=item_id,
  62. particle_id=uuid4(),
  63. scope_type="意图",
  64. scope_value="吸引注意",
  65. is_reused=True,
  66. )
  67. payload = PayloadDraft(item_id=item_id, particle_id=knowledge.id, payload={"kind": "how"})
  68. ingest = IngestRecord(
  69. payload_draft_id=payload.id,
  70. target_system="creation-knowledge-db",
  71. target_id="remote-1",
  72. )
  73. assert read.cards[0].content == "构图说明"
  74. assert knowledge.particle_type == "how"
  75. assert scope.scope_value == "吸引注意"
  76. assert payload.review_status == "pending"
  77. assert ingest.status == "pending"
  78. def test_decode_content_rejects_unknown_particle_type():
  79. with pytest.raises(ValidationError):
  80. KnowledgeParticle(particle_type="idea", title="错误类型")
  81. def test_pipeline_models_capture_resume_boundary():
  82. run_id = uuid4()
  83. run = PipelineRun(id=run_id, run_key="formal-run", current_stage="decode")
  84. job = PipelineJob(run_id=run_id, stage="decode", target_id=uuid4())
  85. cursor = ResumeCursor(stage="decode", last_successful_job_id=job.id)
  86. assert run.status == "pending"
  87. assert job.status == "pending"
  88. assert cursor.stage == "decode"
  89. def test_app_schemas_cover_formal_workbench_shapes():
  90. run_id = uuid4()
  91. item_id = uuid4()
  92. summary = AcquisitionRunSummarySchema(
  93. id=run_id,
  94. status="running",
  95. query_count=3,
  96. job_count=9,
  97. candidate_count=21,
  98. creation_hit_count=5,
  99. )
  100. item = CandidateItemSchema(
  101. id=item_id,
  102. platform="douyin",
  103. title="短视频脚本创作",
  104. status="candidate",
  105. )
  106. page = Page(total=1, items=[{"id": str(item_id)}])
  107. error = ErrorResponse(code="not_found", message="missing")
  108. assert summary.creation_hit_count == 5
  109. assert item.media_assets == []
  110. assert page.total == 1
  111. assert error.detail == {}