refactor: reuse routing and remove unused analysis helpers
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
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)]
|
||||
@@ -1,3 +1,4 @@
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
from uuid import uuid4
|
||||
@@ -8,6 +9,32 @@ import pytest
|
||||
from scripts.run_operational_worker import CredentialProvider, OperationalWorker, WorkerSettings
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_parallel_worker_requests_share_cold_and_expired_token_refresh(monkeypatch):
|
||||
clock = [100.0]
|
||||
requests = []
|
||||
monkeypatch.setattr("scripts.run_operational_worker.time.monotonic", lambda: clock[0])
|
||||
|
||||
async def handler(request):
|
||||
requests.append(request)
|
||||
await asyncio.sleep(0)
|
||||
return httpx.Response(200, json={"access_token": f"TEST_ONLY_{len(requests)}", "expires_in": 60})
|
||||
|
||||
provider = CredentialProvider(WorkerSettings(
|
||||
"http://server.test", "http://agent.test", str(uuid4()),
|
||||
token_url="https://identity.test/token", client_id="fixture", client_secret="TEST_ONLY",
|
||||
))
|
||||
async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as client:
|
||||
first = await asyncio.gather(provider.headers(client), provider.headers(client))
|
||||
assert first[0] == first[1]
|
||||
assert len(requests) == 1
|
||||
clock[0] = 146.0
|
||||
second = await asyncio.gather(provider.headers(client), provider.headers(client))
|
||||
assert second[0] == second[1]
|
||||
assert second[0] != first[0]
|
||||
assert len(requests) == 2
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def anyio_backend():
|
||||
return "asyncio"
|
||||
|
||||
Reference in New Issue
Block a user