Files
orchestrator/tests/test_status_comment_authorship.py

123 lines
4.1 KiB
Python

"""ORCH-016 / TC-19 + AC-1..AC-5 authorship: status comments use per-agent bots.
When a status comment is posted by AgentLauncher._post_usage_comments, the
underlying plane_sync.add_comment must be invoked with ``author=<agent>`` so
plane_sync._headers_for(<agent>) picks the agent's bot token
(PLANE_BOT_TOKENS[role]) — falling back to PLANE_HEADERS when the bot token
is empty / role unknown. Comment FORMAT changes (ORCH-016) must not affect
that authorship contract.
"""
import os
import tempfile
os.environ.setdefault("ORCH_PLANE_API_TOKEN", "test-token")
os.environ.setdefault("ORCH_GITEA_TOKEN", "test-token")
_test_db = os.path.join(tempfile.gettempdir(), "test_orch016_authorship.db")
os.environ["ORCH_DB_PATH"] = _test_db
import pytest # noqa: E402
from src import db as db_module # noqa: E402
from src.db import init_db, get_db # noqa: E402
from src.agents.launcher import AgentLauncher # noqa: E402
REPO = "enduro-trails"
BRANCH = "feature/ET-016-x"
WID = "ET-016"
@pytest.fixture
def db(monkeypatch):
monkeypatch.setattr(db_module.settings, "db_path", _test_db, raising=False)
if os.path.exists(_test_db):
os.unlink(_test_db)
init_db()
conn = get_db()
conn.execute(
"INSERT INTO tasks (id, repo, branch, stage, work_item_id) "
"VALUES (1, ?, ?, 'review', ?)",
(REPO, BRANCH, WID),
)
conn.commit()
conn.close()
yield
if os.path.exists(_test_db):
os.unlink(_test_db)
@pytest.fixture
def fake_wt(monkeypatch, tmp_path):
base = tmp_path / "wt"
(base / "docs" / "work-items" / WID).mkdir(parents=True)
monkeypatch.setattr("src.git_worktree.get_worktree_path", lambda r, b: str(base))
return base
@pytest.fixture
def capture(monkeypatch):
posts = []
def _spy(work_item_id, body, author=None, **kwargs):
posts.append({"wid": work_item_id, "body": body, "author": author})
monkeypatch.setattr("src.agents.launcher.plane_add_comment", _spy)
return posts
@pytest.mark.parametrize("agent", ["architect", "developer", "reviewer", "tester"])
def test_tc19_status_comment_carries_agent_author(agent, db, fake_wt, capture):
"""Each agent's status comment must be POST-ed under that agent's bot."""
AgentLauncher()._post_usage_comments(
run_id=1, agent=agent, repo=REPO, branch=BRANCH,
usage=None, duration_s=10,
)
assert len(capture) >= 1
assert capture[0]["author"] == agent, (
f"Expected author={agent!r}, got {capture[0]['author']!r}"
)
def test_tc19_deployer_status_and_summary_both_authored_by_deployer(db, fake_wt, capture):
"""Deployer posts TWO comments (status + per-task summary) — both ``author='deployer'``."""
conn = get_db()
conn.execute("UPDATE tasks SET stage='deploy' WHERE id=1")
conn.commit()
conn.close()
AgentLauncher()._post_usage_comments(
run_id=2, agent="deployer", repo=REPO, branch=BRANCH,
usage=None, duration_s=10,
)
assert len(capture) == 2
assert {c["author"] for c in capture} == {"deployer"}
def test_tc19_headers_for_unknown_role_falls_back(monkeypatch):
"""Ensure plane_sync._headers_for handles unknown agents (fallback contract)."""
from src import plane_sync
h = plane_sync._headers_for("unknown_role_xyz")
# PLANE_HEADERS fallback uses settings.plane_api_token (set to 'test-token').
assert isinstance(h, dict) and "X-API-Key" in h
def test_tc19_status_comment_format_preserves_author_contract(db, fake_wt, capture):
"""The ORCH-016 format change must not strip the author= kw from the call site."""
(fake_wt / "docs" / "work-items" / WID / "12-review.md").write_text(
"---\nverdict: APPROVE\n---\n",
)
AgentLauncher()._post_usage_comments(
run_id=3, agent="reviewer", repo=REPO, branch=BRANCH,
usage={"input_tokens": 0, "output_tokens": 0, "cost_usd": 0.0},
duration_s=180,
)
assert len(capture) == 1
post = capture[0]
assert post["author"] == "reviewer"
# And the new format is present in the body (sanity).
assert "\U0001f50e Reviewer" in post["body"]
assert "Verdict: APPROVE" in post["body"]
assert "Длительность: 3m 00s" in post["body"]