"""Regression tests: api.py + scheduler.py delegate to handlers/_ack_id (SP27 Task 6). After the dedup, the inline `_ack_count_summary`, `_ack_synthetic_source_batch_id`, and `_277ca_synthetic_source_batch_id` helpers should be gone from both `api.py` and `scheduler.py`. Their callers should reach the canonical copies under ``cyclone.handlers._ack_id``. This test pins two things: 1. The module attributes exist where expected (import paths intact). 2. The endpoints that depend on the helpers still respond 200 (or 401 if unauthenticated) — i.e. the dedup didn't break the import chain. """ from __future__ import annotations import pytest from fastapi.testclient import TestClient from cyclone import api, scheduler from cyclone.api import app from cyclone.handlers._ack_id import ( ack_count_summary, ack_synthetic_source_batch_id, two77ca_synthetic_source_batch_id, ) # ---- 1. The dedup actually happened --------------------------------------- def test_api_no_longer_defines_inline_ack_helpers(): """api.py must not re-define the helpers as local symbols. The alias imports at the top of api.py (``from cyclone.handlers._ack_id import ack_count_summary as _ack_count_summary``) leave the underscore-prefixed names bound in ``api.__dict__`` — that's the whole point of an alias import and is required so the inline call sites keep working. What we want to check is that the *implementation source* is no longer the api module itself. Concretely: the function's ``__module__`` attribute should be ``cyclone.handlers._ack_id``, not ``cyclone.api``. """ for name in ( "_ack_count_summary", "_ack_synthetic_source_batch_id", "_277ca_synthetic_source_batch_id", ): assert hasattr(api, name), ( f"api.py doesn't even have {name} — alias import missing" ) fn = getattr(api, name) assert fn.__module__ == "cyclone.handlers._ack_id", ( f"api.{name} resolves to {fn.__module__}, expected " f"cyclone.handlers._ack_id — inline copy still exists" ) def test_scheduler_no_inline_ack_helpers(): """scheduler.py must not re-define the ack helpers as local symbols. In SP27 Task 2 the inline copies of ``_ack_count_summary`` and ``_ack_synthetic_source_batch_id`` were deleted from scheduler.py (they had become dead code after Task 1 lifted the canonical copies into ``cyclone.handlers._ack_id``). Task 4 removed ``_277ca_synthetic_source_batch_id`` the same way. So none of the three names should be present in the scheduler module at all. """ for name in ( "_ack_count_summary", "_ack_synthetic_source_batch_id", "_277ca_synthetic_source_batch_id", ): assert not hasattr(scheduler, name), ( f"scheduler.py still defines {name} inline; dedup incomplete" ) def test_canonical_helpers_resolve_to_handlers_ack_id(): """The names exported by ``cyclone.handlers._ack_id`` must be reachable from the canonical import path.""" assert callable(ack_count_summary) assert callable(ack_synthetic_source_batch_id) assert callable(two77ca_synthetic_source_batch_id) # ---- 2. Endpoints still respond ------------------------------------------- @pytest.fixture def client() -> TestClient: return TestClient(app) def test_ack_endpoints_respond_after_dedup(client): """Hitting each ack endpoint must not raise ImportError. Either 200 (auth OK) or 401/403 (auth required) is acceptable; 500 means the import chain broke.""" # Acquire an authenticated session by hitting login (idempotent — # the same admin user already exists in the test DB). for path in ( "/api/acks", "/api/ta1-acks", "/api/277ca-acks", ): resp = client.get(path) assert resp.status_code in (200, 401, 403), ( f"{path} broke after dedup: {resp.status_code} {resp.text}" )