from __future__ import annotations from datetime import datetime from zoneinfo import ZoneInfo from supply_infra.config import InfraSettings from supply_infra.pipeline.dates import ( build_date_snapshot, deadline_for_trigger, next_daily_deadline_china, next_schedule_china, resolve_biz_dt, ) def _settings() -> InfraSettings: return InfraSettings( _env_file=None, SCHEDULER_TIMEZONE="Asia/Shanghai", SCHEDULER_CRON_HOUR=15, SCHEDULER_CRON_MINUTE=0, ) def test_date_snapshot_is_frozen_from_biz_dt() -> None: assert build_date_snapshot("20260727") == { "biz_dt": "20260727", "global_tree_partition": "20260726", "demand_pool_partition": "20260727", "video_decode_partition": "20260726", } def test_resolve_biz_dt_uses_scheduler_timezone() -> None: now = datetime(2026, 7, 27, 1, 2, tzinfo=ZoneInfo("Asia/Shanghai")) assert resolve_biz_dt(None, settings=_settings(), now=now) == "20260727" def test_deadline_is_next_scheduler_start() -> None: now = datetime(2026, 7, 27, 15, 1, tzinfo=ZoneInfo("Asia/Shanghai")) deadline = next_schedule_china(settings=_settings(), now=now) assert deadline.isoformat() == "2026-07-28T15:00:00" def test_scheduled_daily_deadline_is_always_next_local_day() -> None: before_cron = datetime(2026, 7, 27, 14, 0, tzinfo=ZoneInfo("Asia/Shanghai")) after_cron = datetime(2026, 7, 27, 16, 0, tzinfo=ZoneInfo("Asia/Shanghai")) assert next_daily_deadline_china( settings=_settings(), now=before_cron, ).isoformat() == "2026-07-28T15:00:00" assert next_daily_deadline_china( settings=_settings(), now=after_cron, ).isoformat() == "2026-07-28T15:00:00" def test_only_scheduled_triggers_receive_a_deadline() -> None: now = datetime(2026, 7, 27, 15, 0, tzinfo=ZoneInfo("Asia/Shanghai")) assert deadline_for_trigger( "cron", settings=_settings(), now=now, ).isoformat() == "2026-07-28T15:00:00" assert deadline_for_trigger( "reconcile", settings=_settings(), now=now, ).isoformat() == "2026-07-28T15:00:00" assert deadline_for_trigger("api", settings=_settings(), now=now) is None assert deadline_for_trigger("cli", settings=_settings(), now=now) is None