Ctrl K
ComunidadGuías…

tests/test_route_table.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""The enumeration the auth and MCP-parity guards are built on must not go quiet.

Both guards compare `live_routes - expected`, which is empty — and therefore
PASSES — when `live_routes` is empty. FastAPI 0.140 made exactly that happen by
changing `include_router` to leave an opaque `_IncludedRouter` in `app.routes`
instead of flattening the endpoints. The suite reported one loud failure and two
silent degradations. These tests pin the enumeration itself so the next upstream
change to route plumbing fails here, in one obvious place.
"""

from __future__ import annotations

from fastapi import APIRouter, FastAPI

from tests.route_table import broker_route_set


def _app_with_included_router(prefix: str = "") -> FastAPI:
    app = FastAPI()
    router = APIRouter()

    @router.get("/thing")
    def _get_thing():  # pragma: no cover - never called, only enumerated
        return {}

    @router.post("/thing/{ident}")
    def _post_thing(ident: str):  # pragma: no cover
        return {}

    app.include_router(router, prefix=prefix) if prefix else app.include_router(router)
    return app


def test_endpoints_behind_include_router_are_found():
    """The regression itself: every broker endpoint lives behind a router."""
    routes = broker_route_set(_app_with_included_router())
    assert "GET /thing" in routes
    assert "POST /thing/{ident}" in routes


def test_include_prefix_is_resolved_not_dropped():
    """`original_router.routes` would report the PRE-include path here, which is
    why this reads the OpenAPI schema instead."""
    routes = broker_route_set(_app_with_included_router(prefix="/v2"))
    assert "GET /v2/thing" in routes
    assert "GET /thing" not in routes


def test_directly_registered_routes_still_appear():
    app = FastAPI()

    @app.get("/direct")
    def _direct():  # pragma: no cover
        return {}

    assert "GET /direct" in broker_route_set(app)


def test_docs_and_schema_endpoints_are_excluded():
    routes = broker_route_set(_app_with_included_router())
    assert not [r for r in routes if "/openapi" in r or "/docs" in r or "/redoc" in r]


def test_the_real_broker_exposes_a_substantial_route_table(
    tmp_path, sample_projects_yaml, sample_profiles_yaml, sample_classifier_yaml
):
    """The floor that makes 'silently empty' impossible to miss. The broker had
    ~30 routes when this landed; 15 leaves room to delete a few without
    tripping, and no room to enumerate nothing."""
    from jobd.app import build_app

    app = build_app(
        db_url=f"sqlite:///{tmp_path}/rt.db",
        projects_path=sample_projects_yaml,
        profiles_path=sample_profiles_yaml,
        classifier_path=sample_classifier_yaml,
        logs_path=tmp_path / "logs",
    )
    routes = broker_route_set(app)
    assert len(routes) >= 15, f"only {len(routes)} routes enumerated: {sorted(routes)}"
    # Spot-check one endpoint from each router module the Stage-3 split created.
    for expected in ("GET /livez", "POST /submit", "GET /workers", "POST /events"):
        assert expected in routes, f"{expected} missing from {sorted(routes)}"