from contextlib import asynccontextmanager from types import SimpleNamespace from unittest.mock import AsyncMock from uuid import uuid4 import pytest from app.auth.project_dependencies import ProjectContext from app.infra.db.metadb.repositories.metadata_repository import MetadataRepository, ProjectDbRouting from app.infra.db.project_routing import get_active_project_routing from app.mcp import scope @pytest.mark.anyio async def test_mcp_scope_reads_routing_once_and_refreshes_it_on_the_next_request(monkeypatch): project = ProjectContext(uuid4(), "fixture", uuid4(), "member") session = SimpleNamespace(commit=AsyncMock()) connections = [] current_dsn = ["dbname=first"] async def metadata_session(): yield session async def read_routing(_repo, project_id, role): assert project_id == project.project_id and role == "biz_data" return ProjectDbRouting(project_id, role, "postgresql", current_dsn[0], 1, 4) @asynccontextmanager async def connection(project_id, role, dsn, minimum, maximum): assert session.commit.await_count > 0 connections.append((project_id, role, dsn, minimum, maximum)) yield object() read = AsyncMock(side_effect=read_routing) monkeypatch.setattr(scope, "get_metadata_session", metadata_session) monkeypatch.setattr(scope, "get_current_metadata_user", AsyncMock(return_value=object())) monkeypatch.setattr(scope, "resolve_project_context", AsyncMock(return_value=project)) # Patch at the repository boundary so both real routing resolvers are exercised. async def repository_read(self, project_id, role): return await read(self, project_id, role) monkeypatch.setattr(MetadataRepository, "get_project_db_routing", repository_read) monkeypatch.setattr("app.auth.project_dependencies.project_connection_manager.pg_connection", connection) for dsn in ("dbname=first", "dbname=second"): current_dsn[0] = dsn async with scope.project_scope(SimpleNamespace(claims={"sub": "fixture"}), str(project.project_id)) as value: assert value.routing.business_dsn == dsn assert get_active_project_routing() is value.routing assert get_active_project_routing() is None assert read.await_count == 2 assert [row[2:] for row in connections] == [("dbname=first", 1, 4), ("dbname=second", 1, 4)]