DFiP_Budget_planing/perf/tests/test_sqlstats.py
Andrey Epifancev 29867535b0 perf: полный прогон run-all.sh и правки по ревью
- perf/run-all.sh: масштабы 1 и 2, шаги reset -> gen -> verify -> stand ->
  preflight -> scroll -> coauthor -> grow -> modals -> modals_profiling ->
  memory -> memtrend -> [control4x] -> bench -> aggregate; лог и
  run-all.status.json, возобновление (PERF_STEPS, PERF_SKIP_RESET),
  сухой режим с оценкой длительности, PERF_S2_REPEATS/PERF_S2_TARGETS,
  контроль CPU 4x (PERF_CONTROL_TARGETS).
- Основная метрика: main_thread_ms и main_thread_ms_per_step в скролле
  (CDP TaskDuration), frame_excess_ms; в summary.md первыми строками.
- SQL-статистика по шагам: PERF_SQLSTATS_TAG -> sql/<шаг>/ (sqlstats --out).
- netlog: тела /auth/ не пишутся, поля password/token/secret вырезаются.
- scroll.spec: уникальные имена целей (лист ССП с суффиксом /ssp, год в
  отчёте проекта) - иначе Playwright не запускал файл из-за дублей.
- PERF_TRACE=0 для прогонов с одним повтором.
- README: scroll-coauthor, run-all, возобновление, без CPU 4/6 в матрицах.
- design.md: уточнена формулировка R-2, решения Task 10a.

Refs #202

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

70 lines
2.7 KiB
Python

from perfkit import sqlstats
from perfkit.sqlstats import explain_candidates, v3_functions, is_explainable, pick_params
def row(q, total=1.0):
return {"query": q, "total_exec_time": total}
def test_v3_functions_extracts_names():
assert v3_functions("SELECT * FROM v3.v_sheet_rows($1, $2)") == ["v_sheet_rows"]
assert v3_functions("select v3.upd_cell($1,$2)") == ["upd_cell"]
assert v3_functions("SELECT 1") == []
def test_is_explainable_select_and_read_functions():
assert is_explainable("SELECT * FROM v3.v_sheet_rows($1)")
assert is_explainable(" select a from t where id = $1")
assert is_explainable("WITH x AS (SELECT 1) SELECT * FROM x")
def test_is_explainable_rejects_dml_and_writers():
assert not is_explainable("UPDATE t SET a = $1")
assert not is_explainable("INSERT INTO t VALUES ($1)")
assert not is_explainable("DELETE FROM t")
assert not is_explainable("SELECT * FROM v3.add_line($1)")
assert not is_explainable("SELECT v3.upd_cell($1, $2)")
assert not is_explainable("SELECT v3.del_line($1)")
assert not is_explainable("SELECT * FROM t FOR UPDATE")
assert not is_explainable("SELECT set_config('a', $1, false)")
assert not is_explainable("SELECT pg_stat_statements_reset()")
assert not is_explainable("EXPLAIN SELECT 1")
def test_explain_candidates_top5_by_total_in_order():
rows = [row("UPDATE t SET a=$1", 100)] + [row(f"SELECT {i} FROM t WHERE a=$1", i) for i in range(10)]
got = explain_candidates(rows, n=5)
assert [r["total_exec_time"] for r in got] == [9, 8, 7, 6, 5]
def test_pick_params_uses_sample_when_given():
assert pick_params("SELECT $1, $2", {"SELECT $1, $2": [1, "a"]}) == [1, "a"]
assert pick_params("SELECT $1", {}) is None
def test_dump_out_dir_passed_to_dump(monkeypatch, tmp_path):
"""--out: sql_top.json/explain пишутся в отдельный каталог шага (run-all), сетевой лог читается из run_dir."""
seen = {}
async def fake(run_dir, top, out_dir):
seen.update(run_dir=run_dir, top=top, out_dir=out_dir)
return {"explained": 0, "skipped": 0}
monkeypatch.setattr(sqlstats, "_dump", fake)
out = tmp_path / "sql" / "scroll"
assert sqlstats.main(["dump", str(tmp_path), "--top", "7", "--out", str(out)]) == 0
assert seen == {"run_dir": tmp_path, "top": 7, "out_dir": out}
assert out.is_dir()
def test_dump_without_out_writes_to_run_dir(monkeypatch, tmp_path):
seen = {}
async def fake(run_dir, top, out_dir):
seen.update(out_dir=out_dir)
return {"explained": 0, "skipped": 0}
monkeypatch.setattr(sqlstats, "_dump", fake)
assert sqlstats.main(["dump", str(tmp_path)]) == 0
assert seen["out_dir"] == tmp_path