DFiP_Budget_planing/perf/tests/test_run_all.py
Andrey Epifancev 05d1586006 perf: исправления run-all по ревью (раунд 1)
- C1: trace только на повторе 0 при числе повторов > 1 (lib/trace.ts
  shouldTrace) в scroll и scroll-coauthor: admin-контроль, control4x и
  PERF_S2_REPEATS=1 больше не теряют единственную запись (traced=1).
- I1: масштаб 2 - PERF_LOAD_TIMEOUT_MS=40 мин и PERF_TEST_TIMEOUT_MS=90 мин,
  если не заданы.
- I2: шаг aggregate падает при сбое perfkit.aggregate/копирования и если
  summary.json не создан; тесты run-all (perf/tests/test_run_all.py).
- M2: после modals_profiling останавливается preview :8081.
- README, design.md: решения раунда.

Refs #202

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 03:12:40 +04:00

89 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""run-all.sh: сухой режим и шаг aggregate (стенд не нужен: aggregate работает только с файлами)."""
import json
import os
import shutil
import subprocess
import uuid
import pytest
from perfkit import PERF_DIR, REPORT_DATA_DIR, RESULTS_DIR
SCRIPT = PERF_DIR / "run-all.sh"
def _run(**env):
e = {k: v for k, v in os.environ.items() if not k.startswith("PERF_")}
e.update(env)
return subprocess.run(["bash", str(SCRIPT)], env=e, capture_output=True, text=True, timeout=120, stdin=subprocess.DEVNULL)
def _step_line(out: str, scale: int, step: str) -> str:
block = out.split(f"=== масштаб {scale},", 1)[1].split("ИТОГО масштаб", 1)[0]
return next(l for l in block.splitlines() if l.strip().startswith(step + " "))
def test_dry_run_plan_and_s2_load_timeout():
p = _run(PERF_DRY_RUN="1", PERF_RUN_TAG="t")
assert p.returncode == 0, p.stderr
assert "ИТОГО масштаб 1" in p.stdout and "ИТОГО масштаб 2" in p.stdout
# свод 2 на масштабе 2 (~150-190 МБ): ожидание загрузки 40 мин, если не задано пользователем
assert "PERF_LOAD_TIMEOUT_MS=2400000" in _step_line(p.stdout, 2, "scroll")
assert "PERF_LOAD_TIMEOUT_MS" not in _step_line(p.stdout, 1, "scroll")
p2 = _run(PERF_DRY_RUN="1", PERF_RUN_TAG="t", PERF_SCALES="2", PERF_LOAD_TIMEOUT_MS="123")
assert "PERF_LOAD_TIMEOUT_MS=123" in _step_line(p2.stdout, 2, "scroll")
def test_dry_run_modals_profiling_stops_web_profiling():
p = _run(PERF_DRY_RUN="1", PERF_RUN_TAG="t", PERF_SCALES="1", PERF_STEPS="modals_profiling")
line = _step_line(p.stdout, 1, "modals_profiling")
assert "web-profiling.pid" in line and "kill" in line
@pytest.fixture
def run_id():
rid = f"pytest-runall-{uuid.uuid4().hex[:8]}"
yield rid
shutil.rmtree(RESULTS_DIR / rid, ignore_errors=True)
shutil.rmtree(REPORT_DATA_DIR / rid, ignore_errors=True)
def _write(rid: str, text: str):
d = RESULTS_DIR / rid
d.mkdir(parents=True)
(d / "scroll.jsonl").write_text(text, encoding="utf-8")
def _status(rid: str) -> dict:
return json.loads((RESULTS_DIR / rid / "run-all.status.json").read_text(encoding="utf-8"))["steps"]
def test_aggregate_step_fails_when_aggregate_fails(run_id):
_write(run_id, "не json\n")
(REPORT_DATA_DIR / run_id).mkdir(parents=True) # возобновление: каталог report-data уже есть от прошлого aggregate
p = _run(PERF_SCALES="1", PERF_SKIP_RESET="1", PERF_STEPS="aggregate", PERF_RUN_ID_S1=run_id)
assert p.returncode == 1, p.stdout
assert _status(run_id)["aggregate"]["status"] == "FAIL"
def test_aggregate_step_ok_and_summary_in_report_data(run_id):
rec = {"run_id": run_id, "scenario": "scroll", "target": "x@y", "role": "rf", "scale": 1, "cpu_rate": 1, "repeat": 1,
"metrics": {"main_thread_ms": 10.0}, "artifacts": [], "incomplete": False, "ts": "x"}
_write(run_id, json.dumps(rec) + "\n")
p = _run(PERF_SCALES="1", PERF_SKIP_RESET="1", PERF_STEPS="aggregate", PERF_RUN_ID_S1=run_id)
assert p.returncode == 0, p.stdout
assert _status(run_id)["aggregate"]["status"] == "OK"
assert (REPORT_DATA_DIR / run_id / "summary.json").exists()
def test_aggregate_step_fails_without_summary(run_id, monkeypatch):
"""Если aggregate не создал summary.json (например, отработал «пусто» не туда), шаг - FAIL."""
_write(run_id, "")
(REPORT_DATA_DIR / run_id).mkdir(parents=True)
fake = RESULTS_DIR / run_id / "fakepy"
fake.write_text("#!/bin/sh\nexit 0\n")
fake.chmod(0o755)
p = _run(PERF_SCALES="1", PERF_SKIP_RESET="1", PERF_STEPS="aggregate", PERF_RUN_ID_S1=run_id, PERF_PY=str(fake))
assert p.returncode == 1, p.stdout
assert _status(run_id)["aggregate"]["status"] == "FAIL"