"""真实 MySQL 只读验证:fin_* 只读查询层可执行,且只发出 SELECT。 不写入任何 fin_* 表(模型层本身也不提供写能力)。 """ from typing import Any import pytest from sqlalchemy import event from app.infrastructure.db import SessionFactory, engine from app.repository.fund_query_repository import ( CustomerScope, FundQueryRepository, PageRequest, ) # 依赖真实 MySQL:必须打 integration marker,否则按 marker 过滤时会漏测这批用例。 pytestmark = pytest.mark.integration async def test_fund_query_repository_only_issues_select_on_real_mysql() -> None: statements: list[str] = [] def record( conn: Any, cursor: Any, statement: str, parameters: Any, context: Any, executemany: bool ) -> None: statements.append(statement.strip().split()[0].upper()) event.listen(engine.sync_engine, "before_cursor_execute", record) try: async with SessionFactory() as session: repository = FundQueryRepository(session, scope=CustomerScope.unrestricted()) pages = [ await repository.products(page=PageRequest(limit=5)), await repository.market_prices(), await repository.nav_history(), await repository.fee_rules(), await repository.accounts(), await repository.cash_ledger(), await repository.capital_flows(), await repository.orders(), await repository.transactions(), await repository.holdings(), await repository.customer_profiles(), await repository.risk_assessments(), await repository.risk_alerts(), await repository.risk_notifications(), ] finally: event.remove(engine.sync_engine, "before_cursor_execute", record) assert len(pages) == 14 assert pages[0].limit == 5 assert statements assert set(statements) == {"SELECT"} async def test_denied_scope_returns_no_customer_rows_on_real_mysql() -> None: async with SessionFactory() as session: repository = FundQueryRepository(session, scope=CustomerScope.denied()) holdings = await repository.holdings() transactions = await repository.transactions() assert holdings.items == () assert transactions.items == () assert holdings.has_more is False