Three low-severity findings from Codex on the 1.0.0-37 split:
1. Trim dead package-level imports in routes/__init__.py — only
`poller` was actually used; auth/burnin/mailer/settings_store
were the exact shadowing footgun the absolute sub-router
imports work around. Reword the comment block to match.
2. Thread `operator` through smart_start + smart_cancel.
Previously the JS client sent it but the server ignored it;
add audit_events rows (smart_test_start / smart_test_cancel)
so the field is actually meaningful.
3. New tests/test_routes_resolution.py — guards two historical
regressions: /api/v1/burnin/export.csv must register before
/{job_id} (FastAPI int-coerce 422 trap) and the mailer
back-compat shim `from app.routes import _fetch_drives_for_template`
must keep importing. Plus a sub-router enumeration test that
catches missed include_router calls in future splits.
79 lines
3 KiB
Python
79 lines
3 KiB
Python
"""Route-resolution invariants for the routes/ package.
|
|
|
|
Guards two historical regressions Codex flagged were untested:
|
|
|
|
1. /api/v1/burnin/export.csv must resolve to the CSV export, not to
|
|
/api/v1/burnin/{job_id} with int("export.csv") → 422. FastAPI's
|
|
path matching tries declarations in registration order, so the
|
|
literal must be declared before the parameterized route.
|
|
|
|
2. app.mailer reaches into app.routes for _fetch_drives_for_template
|
|
(back-compat from before the routes/ split). The shim re-export
|
|
in app/routes/__init__.py must remain importable.
|
|
|
|
Run inside the container image so app deps are present.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import unittest
|
|
|
|
|
|
class TestRouteResolution(unittest.TestCase):
|
|
|
|
def test_export_csv_declared_before_job_id(self):
|
|
"""Route order in burnin.py: /export.csv must come before
|
|
/{job_id} or FastAPI will int-coerce 'export.csv' and 422.
|
|
"""
|
|
from app.routes import burnin as burnin_routes
|
|
|
|
paths = [r.path for r in burnin_routes.router.routes]
|
|
self.assertIn("/api/v1/burnin/export.csv", paths)
|
|
self.assertIn("/api/v1/burnin/{job_id}", paths)
|
|
self.assertLess(
|
|
paths.index("/api/v1/burnin/export.csv"),
|
|
paths.index("/api/v1/burnin/{job_id}"),
|
|
"/export.csv must be registered before /{job_id} or FastAPI "
|
|
"will try to int-coerce 'export.csv' and return 422",
|
|
)
|
|
|
|
def test_mailer_backcompat_shim(self):
|
|
"""app.mailer imports _fetch_drives_for_template from app.routes
|
|
(NOT app.routes._drives_helpers) — the shim re-export in
|
|
routes/__init__.py keeps that working post-split.
|
|
"""
|
|
from app.routes import _fetch_drives_for_template
|
|
self.assertTrue(callable(_fetch_drives_for_template))
|
|
|
|
def test_all_subrouters_included(self):
|
|
"""Sanity check: every sub-router in app.routes.* is wired into
|
|
the package-level router.include_router calls. If a future split
|
|
adds a new file but forgets the include, this catches it.
|
|
"""
|
|
import importlib
|
|
import pkgutil
|
|
import app.routes as routes_pkg
|
|
|
|
sub_modules = [
|
|
name for _, name, _ in pkgutil.iter_modules(routes_pkg.__path__)
|
|
if not name.startswith("_") # skip _helpers, _drives_helpers
|
|
]
|
|
|
|
registered_paths = {r.path for r in routes_pkg.router.routes}
|
|
for mod_name in sub_modules:
|
|
mod = importlib.import_module(f"app.routes.{mod_name}")
|
|
sub_router = getattr(mod, "router", None)
|
|
self.assertIsNotNone(
|
|
sub_router,
|
|
f"app.routes.{mod_name} has no `router` attribute",
|
|
)
|
|
for r in sub_router.routes:
|
|
self.assertIn(
|
|
r.path, registered_paths,
|
|
f"{mod_name}.router has {r.path} but the package "
|
|
"router didn't include it",
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|