"""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"