Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
"""Dashboard mutation-boundary coverage for ``on_kanban_task_updated``.
|
||||
|
||||
The dashboard plugin API's priority/title/body editors write task rows with
|
||||
direct SQL, bypassing every ``kanban_db`` mutator — the exact gap the RFC
|
||||
#58548 mutation-boundary review called out. These tests verify each
|
||||
direct-SQL write path (single-task PATCH and bulk POST) reports through
|
||||
``kanban_db.notify_task_updated`` with the right ``changed_fields``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from hermes_cli import kanban_db as kb
|
||||
from hermes_cli.plugins import get_plugin_manager
|
||||
|
||||
|
||||
def _load_plugin_router():
|
||||
repo_root = Path(__file__).resolve().parents[2]
|
||||
plugin_file = repo_root / "plugins" / "kanban" / "dashboard" / "plugin_api.py"
|
||||
assert plugin_file.exists(), f"plugin file missing: {plugin_file}"
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"hermes_dashboard_plugin_kanban_task_updated_test", plugin_file,
|
||||
)
|
||||
assert spec is not None and spec.loader is not None
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
sys.modules[spec.name] = mod
|
||||
spec.loader.exec_module(mod)
|
||||
return mod.router
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def kanban_home(tmp_path, monkeypatch):
|
||||
home = tmp_path / ".hermes"
|
||||
home.mkdir()
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
monkeypatch.setattr(Path, "home", lambda: tmp_path)
|
||||
kb.init_db()
|
||||
return home
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client(kanban_home):
|
||||
app = FastAPI()
|
||||
app.include_router(_load_plugin_router(), prefix="/api/plugins/kanban")
|
||||
return TestClient(app)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def captured_updates():
|
||||
mgr = get_plugin_manager()
|
||||
events: list[dict] = []
|
||||
saved = {k: list(v) for k, v in mgr._hooks.items()}
|
||||
mgr._hooks.setdefault("on_kanban_task_updated", []).append(
|
||||
lambda **kw: events.append(kw)
|
||||
)
|
||||
try:
|
||||
yield events
|
||||
finally:
|
||||
mgr._hooks = saved
|
||||
|
||||
|
||||
def _make_task(title="t"):
|
||||
conn = kb.connect()
|
||||
try:
|
||||
return kb.create_task(conn, title=title, assignee="alice")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def test_patch_priority_fires_task_updated(client, captured_updates):
|
||||
tid = _make_task()
|
||||
captured_updates.clear()
|
||||
r = client.patch(f"/api/plugins/kanban/tasks/{tid}", json={"priority": 5})
|
||||
assert r.status_code == 200
|
||||
assert len(captured_updates) == 1
|
||||
kw = captured_updates[0]
|
||||
assert kw["task_id"] == tid
|
||||
assert kw["changed_fields"] == ["priority"]
|
||||
assert kw["board"]
|
||||
|
||||
def test_bulk_priority_fires_task_updated_per_task(client, captured_updates):
|
||||
tid1 = _make_task("a")
|
||||
tid2 = _make_task("b")
|
||||
captured_updates.clear()
|
||||
r = client.post(
|
||||
"/api/plugins/kanban/tasks/bulk",
|
||||
json={"ids": [tid1, tid2], "priority": 3},
|
||||
)
|
||||
assert r.status_code == 200
|
||||
assert all(entry["ok"] for entry in r.json()["results"])
|
||||
fired = {kw["task_id"]: kw for kw in captured_updates}
|
||||
assert set(fired) == {tid1, tid2}
|
||||
assert all(kw["changed_fields"] == ["priority"] for kw in fired.values())
|
||||
Reference in New Issue
Block a user