Files
site_aegisone/py_service/tests/test_00_discover_routes.py
T
angel bd048ea23d v1.5.4: test infrastructure + bug fixes + CI/CD + deploy gate
- 6 new test files: route discovery, strict permissions, role switch,
  CRUD operations, 500 error protection
- permission_config.py: central permission definitions for all 110+ routes
- Bug fixes: is_active checkbox in users_edit, int(id) 500 crash,
  missing validation in users_create/users_delete
- Pre-commit hooks: lint + static routing tests
- GitHub Actions CI: full pytest suite on push
- Deploy gate: pytest runs before deploy, aborts on failure
- All 3 deploy scripts: --skip-tests flag support
2026-05-22 20:45:27 +03:00

63 lines
2.4 KiB
Python

"""Auto-discover all routes and verify they're covered in permission_config.
This test runs without a server — it inspects the FastAPI app directly.
When a new route is added, this test will FAIL until it's added to
permission_config.ROUTE_PERMISSIONS.
"""
from tests.permission_config import ROUTE_PERMISSIONS, DYNAMIC_ROUTES, EXCLUDED_ROUTES
def collect_app_routes():
"""Return set of (method, path) from the main app and all routers."""
from app.main import app
routes = set()
for route in app.routes:
if hasattr(route, "methods") and hasattr(route, "path"):
for method in route.methods:
method = method.upper()
if method in ("GET", "POST", "PUT", "DELETE", "PATCH"):
routes.add((method, route.path))
return routes
def test_all_routes_covered():
"""Every app route must have a permission entry."""
app_routes = collect_app_routes() - EXCLUDED_ROUTES
config_routes = set(ROUTE_PERMISSIONS.keys())
missing = app_routes - config_routes
assert not missing, (
f"Routes missing from permission_config.ROUTE_PERMISSIONS:\n"
+ "\n".join(f" {m} {p}" for m, p in sorted(missing))
+ "\n\nAdd them to py_service/tests/permission_config.py"
)
def test_no_stale_permissions():
"""No stale entries in permission config."""
app_routes = collect_app_routes() - EXCLUDED_ROUTES
config_routes = set(ROUTE_PERMISSIONS.keys())
stale = config_routes - app_routes
assert not stale, (
f"ROUTE_PERMISSIONS has stale entries (route no longer exists):\n"
+ "\n".join(f" {m} {p}" for m, p in sorted(stale))
)
def test_dynamic_routes_also_covered():
"""All DYNAMIC_ROUTES must also be in ROUTE_PERMISSIONS."""
for entry in DYNAMIC_ROUTES:
assert entry in ROUTE_PERMISSIONS, (
f"{entry[0]} {entry[1]} is in DYNAMIC_ROUTES but missing from ROUTE_PERMISSIONS"
)
def test_all_roles_valid():
"""Allowed roles must be one of: owner, engineer, technician, anonymous, authenticated."""
valid_roles = {"owner", "engineer", "technician", "anonymous", "authenticated"}
for (method, path), allowed_roles in ROUTE_PERMISSIONS.items():
for role in allowed_roles:
assert role in valid_roles, (
f"{method} {path}: invalid role '{role}' (valid: {valid_roles})"
)