Files
werkrevisor/tests/test_red_rounds.py
claude-code 6b0a631119
werkator build succeeded after 00:09
werkator/werkrevisor-statistics build succeeded after 00:28
werkrevisor 0.29.0: after three rounds of RED, werkrevisor asks a human (#62)
Co-authored-by: claude-code <claude-code@javagil.de>
2026-10-08 21:35:58 +02:00

70 lines
3.1 KiB
Python

import unittest
from tests.fakes import BOT, FakeGitea, FakeModel, config, diff_for, gitea_file
from tests.test_flow import run
from tests.test_open_questions import DOC, doc_bytes
from werkrevisor.verdict import Verdict
GATE = {"yellow_gate": "approval", "human_reviewers": ["alice"], "max_red_rounds": 3}
def result_comment(sha, verdict):
return {"id": hash(sha) % 10000, "user": {"login": BOT},
"body": f"<!-- werkrevisor:{sha} -->\n<!-- werkrevisor-verdict:{verdict} -->\n## werkrevisor: {verdict}"}
def red_run(earlier):
"""The new head has an open question in its PR document, so its review is RED."""
comments = [result_comment(f"{i:040x}", v) for i, v in enumerate(earlier, 1)]
gitea = FakeGitea(files=[gitea_file(DOC)], diff=diff_for(DOC, added=["x"]), comments=comments)
gitea.raw_files[DOC] = doc_bytes(1)
outcome, _ = run(gitea, FakeModel(prompt_files=[DOC]), cfg=config(gate=GATE))
return outcome, gitea
def codes(outcome):
return [r.code for r in outcome.result.reasons]
class RedRoundsTest(unittest.TestCase):
def test_the_fourth_red_in_a_row_asks_a_human(self):
"""Scenario#62.01"""
outcome, gitea = red_run(["RED", "RED", "RED"])
self.assertIs(outcome.result.verdict, Verdict.RED)
reason = next(r for r in outcome.result.reasons if r.code == "red_escalated")
self.assertEqual(reason.text, "RED after 3 rounds of new commits: the automatic rounds end, "
"and a human decides how to go on")
self.assertEqual(gitea.requested, ["alice"])
def test_fewer_rounds_give_red_as_before(self):
"""Scenario#62.02"""
outcome, gitea = red_run(["RED", "RED"])
self.assertIs(outcome.result.verdict, Verdict.RED)
self.assertNotIn("red_escalated", codes(outcome))
self.assertEqual(gitea.requested, [])
def test_a_head_without_red_starts_the_count_anew(self):
"""Scenario#62.03"""
outcome, gitea = red_run(["RED", "RED", "RED", "GREEN"])
self.assertNotIn("red_escalated", codes(outcome))
self.assertEqual(gitea.requested, [])
def test_without_the_approval_gate_the_escalation_is_named_too(self):
comments = [result_comment(f"{i:040x}", "RED") for i in range(1, 4)]
gitea = FakeGitea(files=[gitea_file(DOC)], diff=diff_for(DOC, added=["x"]), comments=comments)
gitea.raw_files[DOC] = doc_bytes(1)
outcome, _ = run(gitea, FakeModel(prompt_files=[DOC]), cfg=config(gate={**GATE, "yellow_gate": "block"}))
self.assertEqual(gitea.requested, ["alice"])
self.assertEqual(outcome.result.gate_note, "escalated to alice")
def test_zero_never_escalates(self):
comments = [result_comment(f"{i:040x}", "RED") for i in range(1, 6)]
gitea = FakeGitea(files=[gitea_file(DOC)], diff=diff_for(DOC, added=["x"]), comments=comments)
gitea.raw_files[DOC] = doc_bytes(1)
outcome, _ = run(gitea, FakeModel(prompt_files=[DOC]), cfg=config(gate={**GATE, "max_red_rounds": 0}))
self.assertNotIn("red_escalated", codes(outcome))
if __name__ == "__main__":
unittest.main()