Files
agentci/tests/test_code_review.py
T
2026-07-19 12:21:26 +02:00

122 lines
3.2 KiB
Python

from pathlib import Path
from types import SimpleNamespace
from agentci.domain.models import (
AgentResult,
Job,
JobKind,
ReviewFinding,
ReviewReport,
ReviewSeverity,
Workflow,
WorkflowKind,
)
from agentci.workflows.code_review import CodeReviewLoop
def serious_report() -> ReviewReport:
return ReviewReport(
summary="Needs work",
findings=[
ReviewFinding(
severity=ReviewSeverity.MAJOR,
title="Missing check",
detail="A check is absent.",
recommendation="Add it.",
)
],
)
class FakeCodex:
def __init__(self, reports: list[ReviewReport]) -> None:
self.reports = iter(reports)
self.reviews = 0
self.revisions = 0
async def start(self, **_kwargs):
self.reviews += 1
return "reviewer", next(self.reports)
async def resume(self, **kwargs):
if kwargs["result_type"] is ReviewReport:
self.reviews += 1
return next(self.reports)
self.revisions += 1
return AgentResult(summary_markdown=f"revision {self.revisions}", tests=[])
class FakeStorage:
async def update_job(self, *_args, **_kwargs):
return None
async def update_workflow(self, *_args, **_kwargs):
return None
class FakePrompts:
def render(self, name, **_kwargs):
return name
def objects(rounds: int, reports: list[ReviewReport]):
codex = FakeCodex(reports)
settings = SimpleNamespace(
implement_review_rounds=rounds,
implement_model="model",
implement_reasoning="high",
)
deps = SimpleNamespace(
settings=settings,
codex=codex,
storage=FakeStorage(),
prompts=FakePrompts(),
)
workflow = Workflow(
id="flow",
kind=WorkflowKind.IMPLEMENT,
repo_owner="org",
repo_name="repo",
issue_number=1,
workspace_path=Path("."),
base_sha="abc",
primary_session_id="primary",
)
job = Job(
id="job",
kind=JobKind.IMPLEMENT,
target_key="target",
repo_owner="org",
repo_name="repo",
issue_number=1,
pr_number=None,
requester="alice",
message="",
comment_id=1,
)
return CodeReviewLoop(deps), codex, workflow, job # type: ignore[arg-type]
async def test_stops_after_clean_second_review() -> None:
clean = ReviewReport(summary="Ready", findings=[])
loop, codex, workflow, job = objects(4, [serious_report(), clean])
_, report = await loop.run(
job, workflow, "context", AgentResult(summary_markdown="initial", tests=[])
)
assert not report.has_serious_findings
assert codex.reviews == 2
assert codex.revisions == 1
async def test_does_not_make_unreviewed_final_revision() -> None:
loop, codex, workflow, job = objects(
3, [serious_report(), serious_report(), serious_report()]
)
_, report = await loop.run(
job, workflow, "context", AgentResult(summary_markdown="initial", tests=[])
)
assert report.has_serious_findings
assert codex.reviews == 3
assert codex.revisions == 2