"""共享真实 ASGI 生命周期与隔离库;通过 portal 驱动同一个消费者,避免测试另写简化业务。""" import os from pathlib import Path import tempfile import sys import pytest sys.path.insert(0, str(Path(__file__).resolve().parents[1])) os.environ['DATA_DIR'] = tempfile.mkdtemp(prefix='agent-audit-test-') os.environ['DATABASE_URL'] = '' os.environ['WORKER_ENABLED'] = 'false' os.environ['SEED_DEMO'] = 'true' os.environ['DEMO_PASSWORD'] = 'Demo@2026!' os.environ['RATE_LIMIT_PER_MINUTE'] = '10000' os.environ['APP_ENV'] = 'development' os.environ['JWT_SECRET'] = 'test-only-random-independent-secret-32' for name in ('LLM_BASE_URL', 'VLM_BASE_URL', 'EMBEDDING_BASE_URL', 'RERANK_BASE_URL', 'LLM_MODEL', 'VLM_MODEL'): os.environ[name] = '' from fastapi.testclient import TestClient from main import app from app.domain.models import Base from app.infrastructure.database import engine, transaction from app.application.seed import seed from app.application.worker import worker @pytest.fixture(scope='session') def client(): with TestClient(app) as instance: yield instance @pytest.fixture(autouse=True) def isolated(client): async def reset(): async with engine.begin() as connection: await connection.run_sync(Base.metadata.drop_all) await connection.run_sync(Base.metadata.create_all) async with transaction() as session: await seed(session) client.portal.call(reset) @pytest.fixture def headers(client): result = {} for name in ('alice', 'bob', 'carol', 'dave', 'erin'): response = client.post('/api/v1/auth/login', json={'username': name, 'password': 'Demo@2026!'}) assert response.status_code == 200, response.text result[name] = {'Authorization': 'Bearer ' + response.json()['data']['access_token']} return result @pytest.fixture def drain(client): def process(): for _ in range(20): if not client.portal.call(worker.process_one): return raise AssertionError('消费者没有在20个事件内收敛') return process