"""Ядро очереди на модуле-заглушке: механика не знает типов команд jira (hub-modules, решение 4).""" import os import time from dataclasses import replace import pytest from sdlc_hub.core import files, queue, registry from sdlc_hub.core.errors import CommandError from sdlc_hub.core.modules import CommandHooks, Module from sdlc_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()