from __future__ import annotations from collections import Counter from pathlib import Path import pytest from gyxx_flow.catalog import CatalogError, WorkflowCatalog PROJECT_ROOT = Path(__file__).resolve().parents[1] def test_catalog_maps_exactly_21_current_scheduled_tasks() -> None: catalog = WorkflowCatalog.load(PROJECT_ROOT / "config") scheduled = catalog.scheduled_workflows() assert len(scheduled) == 21 assert len({item.source_task_name for item in scheduled}) == 21 assert Counter(item.module for item in scheduled) == { "content_marketing": 9, "product_commerce": 7, "shop_intelligence": 2, "supply_chain": 3, } def test_catalog_keeps_known_manual_or_unregistered_workflows_unscheduled() -> None: catalog = WorkflowCatalog.load(PROJECT_ROOT / "config") assert { "content.mapping.refresh", "content.retry_failed", "product.backfill", "product.market_rank", "product.review_collection", "supply.purchase_order_update", }.issubset({item.workflow_id for item in catalog.manual_workflows()}) assert "product.weekly_aggregate.documented_missing" in { item.workflow_id for item in catalog.unavailable_workflows() } def test_every_scheduled_workflow_has_one_valid_asia_shanghai_schedule() -> None: catalog = WorkflowCatalog.load(PROJECT_ROOT / "config") assert catalog.timezone == "Asia/Shanghai" assert len(catalog.schedules) == 21 for workflow in catalog.scheduled_workflows(): schedule = catalog.schedule_for(workflow.workflow_id) assert schedule.workflow_id == workflow.workflow_id assert schedule.kind in {"daily", "weekly", "monthly", "interval_days"} assert schedule.at.count(":") == 1 def test_catalog_rejects_duplicate_workflow_ids(tmp_path: Path) -> None: (tmp_path / "workflows.json").write_text( '{"schema_version":2,"workflows":[' '{"id":"a.one","module":"content_marketing","trigger":"manual",' '"execution":{"entry":"run.py"}},' '{"id":"a.one","module":"content_marketing","trigger":"manual",' '"execution":{"entry":"other.py"}}]}', encoding="utf-8", ) (tmp_path / "schedules.json").write_text( '{"schema_version":1,"timezone":"Asia/Shanghai","schedules":[]}', encoding="utf-8", ) with pytest.raises(CatalogError, match="duplicate workflow id"): WorkflowCatalog.load(tmp_path) def test_catalog_rejects_absolute_execution_entry(tmp_path: Path) -> None: (tmp_path / "workflows.json").write_text( '{"schema_version":2,"workflows":[' '{"id":"a.one","module":"content_marketing","trigger":"manual",' '"execution":{"entry":"D:/old/run.py"}}]}', encoding="utf-8", ) (tmp_path / "schedules.json").write_text( '{"schema_version":1,"timezone":"Asia/Shanghai","schedules":[]}', encoding="utf-8", ) with pytest.raises(CatalogError, match="relative"): WorkflowCatalog.load(tmp_path)