agent: Implemented the explicit persisted webhook state machine.
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
from dataclasses import FrozenInstanceError
|
||||
|
||||
import pytest
|
||||
|
||||
from agentci.domain.events import (
|
||||
CommandReceived,
|
||||
CommentLinked,
|
||||
JobCompleted,
|
||||
JobStarted,
|
||||
PermissionGranted,
|
||||
ServiceRestarted,
|
||||
)
|
||||
from agentci.domain.models import JobKind, JobStatus
|
||||
from agentci.domain.state_machine import InvalidTransition, next_state, render_job_comment
|
||||
|
||||
|
||||
def received(body: str = "/agent plan message"):
|
||||
return next_state(
|
||||
None,
|
||||
CommandReceived(
|
||||
job_id="job",
|
||||
delivery_id="delivery",
|
||||
receive_sequence=1,
|
||||
command_body=body,
|
||||
target_key="org/repo:issue:1",
|
||||
repo_owner="org",
|
||||
repo_name="repo",
|
||||
issue_number=1,
|
||||
pr_number=None,
|
||||
requester="alice",
|
||||
comment_id=4,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_permission_parses_and_queues_execution() -> None:
|
||||
transition = next_state(received().state, PermissionGranted(job_id="job"))
|
||||
assert transition.state.status is JobStatus.QUEUED
|
||||
assert transition.state.kind is JobKind.PLAN
|
||||
assert transition.state.message == "message"
|
||||
assert [(item.listener, item.queue) for item in transition.notifications] == [
|
||||
("execute", "jobs"),
|
||||
("reconcile_comment", "control"),
|
||||
]
|
||||
|
||||
|
||||
def test_invalid_syntax_is_rejected_after_permission() -> None:
|
||||
transition = next_state(received("/agent nonsense").state, PermissionGranted(job_id="job"))
|
||||
assert transition.state.status is JobStatus.REJECTED
|
||||
assert "Unknown" in (transition.state.error or "")
|
||||
|
||||
|
||||
def test_running_completion_and_restart_are_explicit() -> None:
|
||||
queued = next_state(received().state, PermissionGranted(job_id="job")).state
|
||||
running = next_state(queued, JobStarted(job_id="job")).state
|
||||
completed = next_state(running, JobCompleted(job_id="job", comment_body="# Result")).state
|
||||
assert completed.status is JobStatus.SUCCEEDED
|
||||
assert "# Result" in render_job_comment(completed)
|
||||
assert next_state(completed, ServiceRestarted(job_id="job")).state == completed
|
||||
|
||||
|
||||
def test_comment_link_is_allowed_on_terminal_state() -> None:
|
||||
queued = next_state(received().state, PermissionGranted(job_id="job")).state
|
||||
running = next_state(queued, JobStarted(job_id="job")).state
|
||||
completed = next_state(running, JobCompleted(job_id="job", comment_body="ok")).state
|
||||
linked = next_state(completed, CommentLinked(job_id="job", comment_id=9)).state
|
||||
assert linked.accepted_comment_id == 9
|
||||
|
||||
|
||||
def test_state_is_immutable_and_invalid_transitions_fail() -> None:
|
||||
state = received().state
|
||||
with pytest.raises(FrozenInstanceError):
|
||||
state.stage = "changed" # type: ignore[misc]
|
||||
with pytest.raises(InvalidTransition):
|
||||
next_state(state, JobStarted(job_id="job"))
|
||||
Reference in New Issue
Block a user