from __future__ import annotations import json import sys from datetime import date from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[1] if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) FIXTURES = ROOT / "tests" / "fixtures" FIXTURE_ISIN = "RU000A106169" FIXTURE_DATE = date(2026, 10, 8) @pytest.fixture def fixtures_dir() -> Path: """Сохранённые реальные ответы MOEX ISS / ЦБ (байт в байт, см. .gitattributes).""" return FIXTURES @pytest.fixture def session_local(tmp_path: Path, monkeypatch): """Временный SQLite со схемой из миграций (с сидами) вместо SessionLocal во всех модулях сервисов. Postgres не нужен.""" from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine from sqlalchemy.pool import NullPool from alembic import command from alembic.config import Config from app.core.config import settings from app.services import ( fx_rates, manual_operations, market_data, quik_import, request_log, securities, ) db_url = f"sqlite+aiosqlite:///{(tmp_path / 'drrk.db').as_posix()}" monkeypatch.setattr(settings, "DATABASE_URL", db_url) monkeypatch.setattr(settings, "DATABASE_SCHEMA", "") cfg = Config() cfg.set_main_option("script_location", str(ROOT / "alembic")) command.upgrade(cfg, "head") factory = async_sessionmaker( bind=create_async_engine(db_url, poolclass=NullPool), autoflush=False, expire_on_commit=False, ) for module in ( securities, market_data, fx_rates, request_log, quik_import, manual_operations, ): monkeypatch.setattr(module, "SessionLocal", factory) return factory @pytest.fixture def fixture_moex(fixtures_dir: Path): """Фейковый MOEX, отвечающий реальными фикстурами РЭО-02 за 08.10.2026.""" from app.integrations.moex import parse_history, parse_security from tests.unit.fakes import FakeMoex, search_hit security_payload = json.loads( (fixtures_dir / "moex_security_RU000A106169.json").read_text("utf-8") ) history_payload = json.loads( (fixtures_dir / "moex_history_RU000A106169_2026-10-08.json").read_text("utf-8") ) return FakeMoex( search={FIXTURE_ISIN: search_hit(FIXTURE_ISIN, FIXTURE_ISIN)}, securities={FIXTURE_ISIN: parse_security(security_payload)}, history={ FIXTURE_ISIN: parse_history(history_payload, FIXTURE_DATE, ["TQCB", "TQOB"]) }, )