75 lines
2.5 KiB
Python
75 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
import io
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from gyxx_flow.catalog import WorkflowCatalog
|
|
from gyxx_flow.cli import EXIT_USAGE, build_parser, main
|
|
from gyxx_flow.core.config import Settings
|
|
from gyxx_flow.workflow import WorkflowDefinition
|
|
from gyxx_flow.workflow.registry import WorkflowRegistry
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def test_schedule_cli_exposes_only_project_owned_service_commands() -> None:
|
|
parser = build_parser()
|
|
command_action = next(action for action in parser._actions if action.dest == "command")
|
|
schedule_parser = command_action.choices["schedule"]
|
|
schedule_action = next(
|
|
action for action in schedule_parser._actions if action.dest == "schedule_command"
|
|
)
|
|
|
|
assert set(schedule_action.choices) == {"run", "status"}
|
|
|
|
|
|
def test_run_rejects_implicit_scheduled_execution(tmp_path: Path) -> None:
|
|
catalog = WorkflowCatalog.load(PROJECT_ROOT / "config")
|
|
registry = WorkflowRegistry(catalog)
|
|
registry.register(WorkflowDefinition("product.daily", ()))
|
|
output = io.StringIO()
|
|
|
|
exit_code = main(
|
|
["run", "product.daily", "--scheduled"],
|
|
registry=registry,
|
|
settings=Settings(project_root=PROJECT_ROOT, data_root=tmp_path),
|
|
stdout=output,
|
|
stderr=io.StringIO(),
|
|
)
|
|
|
|
assert exit_code == EXIT_USAGE
|
|
assert output.getvalue() == ""
|
|
|
|
|
|
def test_python_scheduler_status_is_project_owned_and_cross_platform(tmp_path: Path) -> None:
|
|
output = io.StringIO()
|
|
settings = Settings(project_root=PROJECT_ROOT, data_root=tmp_path / "data")
|
|
|
|
exit_code = main(
|
|
["schedule", "status"], settings=settings,
|
|
stdout=output, stderr=io.StringIO(),
|
|
)
|
|
|
|
assert exit_code == 0
|
|
payload = json.loads(output.getvalue())
|
|
assert payload["timezone"] == "Asia/Shanghai"
|
|
assert payload["scheduled_count"] == 23
|
|
assert payload["state"]["schema_version"] == 1
|
|
|
|
|
|
def test_python_scheduler_dry_run_never_launches_or_writes_state(tmp_path: Path) -> None:
|
|
output = io.StringIO()
|
|
settings = Settings(project_root=PROJECT_ROOT, data_root=tmp_path / "data")
|
|
|
|
exit_code = main(
|
|
["schedule", "run", "--dry-run", "--once", "--misfire-grace-seconds", "3456000"],
|
|
settings=settings, stdout=output, stderr=io.StringIO(),
|
|
)
|
|
|
|
assert exit_code == 0
|
|
payload = json.loads(output.getvalue())
|
|
assert payload["mode"] == "dry-run"
|
|
assert "product.market_rank" in payload["due_or_started"]
|
|
assert not (settings.data_root / "state" / "scheduler" / "state.json").exists()
|