sdlc-hub/tests/test_queue_core.py
Andrey Epifancev 3f4c9183b8 Очередь, релиз и статус по агенту модуля (#91)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 00:59:49 +04:00

85 lines
3.6 KiB
Python

"""Ядро очереди на модуле-заглушке: механика не знает типов команд jira (hub-modules, решение 4)."""
import os
import time
from dataclasses import replace
import pytest
from jira_hub.core import files, queue, registry
from jira_hub.core.errors import CommandError
from jira_hub.core.modules import CommandHooks, Module
from jira_hub.modules import jira
SHA = "a" * 64
def _validate(cmds):
return [{"type": c["type"], "params": c.get("params") or {}} for c in cmds]
def make_stub(events, refs=()):
hooks = CommandHooks(
types=frozenset({"w", "r"}), read_types=frozenset({"r"}), validate=_validate,
check_batch=lambda conn, cmds, project, files_dir: cmds,
tail=lambda cmds: {"type": "r", "params": {}} if any(c["type"] == "w" for c in cmds) else None,
pause=lambda conn, ctype: 7, deliver_params=lambda conn, cmd, files_dir: cmd["params"],
temp_definer=None, temp_keys_used=lambda cmd: [], substitute=lambda t, p, m: p,
drop_unresolved=lambda cmd, unresolved: unresolved, retry_params=lambda cmd: cmd["params"],
check_confirmed=lambda conn, cmd: (False, None), on_claim=lambda *a: None, on_failed=lambda *a: None,
check_result=lambda conn, cmd, status, result, files_dir: (status, None),
on_result=lambda conn, cmd, status, *a: events.append(("on_result", cmd["type"], status)),
after_result=lambda conn, cmd, status: events.append(("after_result", cmd["type"], status)),
on_late_result=lambda *a: False)
return Module(name="t", commands=hooks, file_refs=lambda conn: set(refs))
@pytest.fixture
def stub(monkeypatch):
events = []
monkeypatch.setattr(registry, "_cache", [jira.MODULE, make_stub(events)])
return events
def test_tail_and_estimate(open_db, stub):
conn = open_db()
b = queue.create_batch(conn, "x", "claude", [{"type": "w", "params": {}}])
assert [c["type"] for c in queue.batch_view(conn, b["id"])["commands"]] == ["w", "r"]
assert b["estimate_seconds"] == 14 and queue.estimate(conn, ["w", "r"]) == 14
def test_mixed_modules(open_db, stub):
conn = open_db()
with pytest.raises(CommandError, match="команды разных модулей в одном пакете"):
queue.create_batch(conn, "x", "claude", [{"type": "w"}, {"type": "refresh", "params": {"jql": "x"}}])
def test_on_result_called(tmp_path, open_db, stub):
path = tmp_path / "hub.sqlite"
conn = open_db(path)
queue.create_batch(conn, "x", "claude", [{"type": "w", "params": {}}])
cmd = queue.claim(conn, "t")
seen = {}
real = stub.append
def after(conn_, cmd_, status):
other = open_db(path) # новое соединение видит зафиксированное
seen["status"] = other.execute("SELECT status FROM command WHERE id = ?", (cmd_["id"],)).fetchone()["status"]
real(("after_result", cmd_["type"], status))
hooks = replace(registry.module("t").commands, after_result=after)
registry._cache[1] = replace(registry.module("t"), commands=hooks)
queue.report_result(conn, cmd["id"], "done", {})
assert ("on_result", "w", "done") in stub and ("after_result", "w", "done") in stub
assert seen["status"] == "done"
def test_sweep_uses_file_refs(tmp_path, open_db, monkeypatch):
monkeypatch.setattr(registry, "_cache", [jira.MODULE, make_stub([], refs={SHA})])
root = tmp_path / "files"
root.mkdir()
(root / SHA).write_bytes(b"x")
old = time.time() - 40 * 86400
os.utime(root / SHA, (old, old))
assert files.sweep(open_db(), root) == []
assert (root / SHA).exists()