88 lines
4 KiB
Python
88 lines
4 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""e-261003094628 (повтор e-261001082241): guard мусорных заголовков задач (hermetic).
|
||
|
||
Запуск: ./venv/bin/python tests/test_submit_title_guard.py
|
||
|
||
Первопричина серии 'list': LLM-тик нижнего уровня звал
|
||
`cli.py task list` / `cli.py task <id>` (хотел доску/детали задачи), а
|
||
`task` принимает позиционный title → argparse молча подсунул слово
|
||
'list' / чужой id как заголовок и подал мусорную задачу. Min-уровень
|
||
закрыл их как no-op и эскалировал — дважды.
|
||
|
||
Проверяет: submit_task режет субкомандо-подобные заголовки и чужие id
|
||
задач БЕЗ деталей (ValueError), пропускает нормальные подачи, одно слово
|
||
с деталями, обычные слова не из стоп-листа; CLI `task list` → exit 1 с
|
||
ERROR, а не тихая подача.
|
||
"""
|
||
import os
|
||
import subprocess
|
||
import sys
|
||
|
||
# ── изоляция: своя БД в /tmp (prod не трогаем) ──
|
||
_DST = "/tmp/simbiot-test-title-guard.db"
|
||
for p in (_DST, _DST + "-wal", _DST + "-shm"):
|
||
if os.path.exists(p):
|
||
os.unlink(p)
|
||
os.environ["SIMBIOT_DB"] = _DST
|
||
sys.path.insert(0, "/root/simbiot-harness")
|
||
|
||
from harness import commands
|
||
|
||
commands.es.init_db()
|
||
|
||
fails = []
|
||
|
||
|
||
def check(name, cond, extra=""):
|
||
print(("PASS" if cond else "FAIL"), name, ("| " + str(extra)) if not cond else "")
|
||
if not cond:
|
||
fails.append(name)
|
||
|
||
|
||
# ── 1. Субкомандо-подобные заголовки без деталей — режутся ──
|
||
for bad in ("list", "tasks", "status", "events", "help", "LIST", " Complete "):
|
||
try:
|
||
commands.submit_task(bad, "", minutes=5)
|
||
check(f"мусорный заголовок {bad!r} отвергнут", False, "подача прошла")
|
||
except ValueError:
|
||
check(f"мусорный заголовок {bad!r} отвергнут", True)
|
||
|
||
# ── 2. Чужой id задачи как заголовок без деталей — режется ──
|
||
try:
|
||
commands.submit_task("t-261003094008-ed226f", "", minutes=5)
|
||
check("id задачи как заголовок отвергнут", False, "подача прошла")
|
||
except ValueError:
|
||
check("id задачи как заголовок отвергнут", True)
|
||
|
||
# ── 3. Нормальные подачи — проходят ──
|
||
for title, details in (
|
||
("Разбор голосового m-973940607 + HTML-страница", "транскрипт в docs/"),
|
||
("list", "собрать список всех ключей в реестре"), # слово из стоп-листа, но с деталями
|
||
("фикс деплоя", ""),
|
||
):
|
||
try:
|
||
tid, size = commands.submit_task(title, details, minutes=5)
|
||
ok = bool(tid) and size == "S"
|
||
except ValueError as e:
|
||
ok, tid = False, str(e)
|
||
check(f"нормальная подача {title[:30]!r} прошла", ok, tid)
|
||
|
||
# ── 4. CLI: `cli.py task list` — ошибка, а не тихая мусорная задача ──
|
||
env = dict(os.environ, SIMBIOT_DB=_DST)
|
||
r = subprocess.run(
|
||
["./venv/bin/python", "cli.py", "task", "list"],
|
||
capture_output=True, text=True, cwd="/root/simbiot-harness", env=env,
|
||
)
|
||
out = (r.stdout + r.stderr).strip()
|
||
check("CLI task list → exit 1", r.returncode == 1, f"rc={r.returncode} out={out!r}")
|
||
check("CLI task list → ERROR с подсказкой", "ERROR" in out and "tasks" in out, out)
|
||
model = commands.es.run_projections()
|
||
check("мусорной задачи 'list' в сторе нет",
|
||
not any(t.get("title", "").strip().lower() == "list" and not t.get("details")
|
||
for t in model["tasks"].values()))
|
||
|
||
print()
|
||
if fails:
|
||
print(f"FAILED: {len(fails)}")
|
||
sys.exit(1)
|
||
print("OK: все проверки прошли")
|