"""Нагрузочный тест: массовый прогон run_pipeline (сотни контрактов × допников). Создаёт N контрактов × M допников, прогоняет полный конвейер сверки с Fake LLM (без сети), реально нагружает SQLite: apply_ops + clear_current + reset. Проверка: full_replace НЕ дублирует строки в масштабе (у каждого контракта ровно SERVICES строк, а не SERVICES × M_SUPPS). """ import os import time import pytest from db import contracts, documents, supplements, spec_current from db.connection import query from services import process pytestmark = pytest.mark.load N_CONTRACTS = int(os.getenv("LOAD_CONTRACTS", "100")) M_SUPPS = int(os.getenv("LOAD_SUPPS", "20")) SERVICES = int(os.getenv("LOAD_SERVICES", "10")) def _seed(): cids = [] for ci in range(N_CONTRACTS): c = contracts.insert(f"03700_{ci}") for mi in range(M_SUPPS): d = documents.insert(f"d{ci}_{mi}.docx", "application/octet-stream", "raw", batch_id=f"b{ci}") documents.set_parsed(d["id"], [{"type": "paragraph", "text": f"услуга {mi}"}]) supplements.insert(c["id"], d["id"], "initial" if mi == 0 else "additional") cids.append(c["id"]) return cids def _fake_llm(): def fake_call(current_spec, doc_text, build_prompt_fn, llm_client=None): ops = [ {"action": "ADD", "new_row": {"name": f"услуга {i}", "price": 100 + i, "qty": 1, "sum": 100 + i}} for i in range(SERVICES) ] return ({"mode": "full_replace", "ops": ops}, "pid") return fake_call def test_mass_pipeline(db, monkeypatch): cids = _seed() monkeypatch.setattr("services.llm.call_llm", _fake_llm()) t0 = time.time() for cid in cids: list(process.run_pipeline(cid, "", lambda cur, txt: ("p", "pid"))) elapsed = time.time() - t0 # Целостность: у каждого контракта ровно SERVICES строк (full_replace без дублей) bad = 0 for cid in cids: if len(spec_current.list_by_contract(cid)) != SERVICES: bad += 1 assert bad == 0, f"{bad} контрактов с неверным числом строк" total_events = query("SELECT count(*) AS c FROM spec_events", ()) print( f"\n[load] контрактов={N_CONTRACTS} допников={M_SUPPS} услуг={SERVICES} " f"событий={total_events[0]['c']} время={elapsed:.1f}с" )