fix(tests): fix veto bug preventing disputed state, add manager notification and dispute-resolution routing
This commit is contained in:
@@ -414,7 +414,7 @@ def test_dual_validation_blue_rejects_first(mock_log):
|
||||
|
||||
@patch("app.services.test_workflow_service.log_action")
|
||||
def test_dual_validation_red_approves_blue_rejects(mock_log):
|
||||
"""Red approves, then blue rejects -> rejected."""
|
||||
"""Red approves, then blue rejects -> genuine conflict -> disputed."""
|
||||
test = _make_test(TestState.in_review)
|
||||
red_lead = _make_user("red_lead")
|
||||
blue_lead = _make_user("blue_lead")
|
||||
@@ -424,7 +424,7 @@ def test_dual_validation_red_approves_blue_rejects(mock_log):
|
||||
assert test.state == TestState.in_review # waiting for blue
|
||||
|
||||
validate_as_blue_lead(db, test, blue_lead, "rejected", "Bad detection")
|
||||
assert test.state == TestState.rejected
|
||||
assert test.state == TestState.disputed
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
@@ -687,6 +687,85 @@ class TestReviewDecisions:
|
||||
assert result.system_gaps == "Missing EDR agent on host X"
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# 12c. resolve_dispute — flip approver's vote to reject, route to a team
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
class TestResolveDispute:
|
||||
@patch("app.services.test_workflow_service.log_action")
|
||||
def test_red_lead_approver_flips_to_red_queue(self, mock_log):
|
||||
test = _make_test(
|
||||
TestState.disputed,
|
||||
red_validation_status="approved",
|
||||
blue_validation_status="rejected",
|
||||
)
|
||||
red_lead = _make_user("red_lead")
|
||||
db = _make_db()
|
||||
|
||||
from app.services.test_workflow_service import resolve_dispute
|
||||
result = resolve_dispute(db, test, red_lead, "red", notes="redo the attack")
|
||||
|
||||
assert result.state == TestState.red_executing
|
||||
assert result.red_validation_status is None
|
||||
assert result.blue_validation_status is None
|
||||
|
||||
@patch("app.services.test_workflow_service.log_action")
|
||||
def test_blue_lead_approver_flips_to_blue_queue(self, mock_log):
|
||||
test = _make_test(
|
||||
TestState.disputed,
|
||||
blue_validation_status="approved",
|
||||
red_validation_status="rejected",
|
||||
)
|
||||
blue_lead = _make_user("blue_lead")
|
||||
db = _make_db()
|
||||
|
||||
from app.services.test_workflow_service import resolve_dispute
|
||||
result = resolve_dispute(db, test, blue_lead, "blue")
|
||||
|
||||
assert result.state == TestState.blue_evaluating
|
||||
|
||||
def test_non_approver_cannot_resolve_dispute(self):
|
||||
test = _make_test(
|
||||
TestState.disputed,
|
||||
red_validation_status="rejected",
|
||||
blue_validation_status="approved",
|
||||
)
|
||||
red_lead = _make_user("red_lead") # red_lead REJECTED, didn't approve
|
||||
db = _make_db()
|
||||
|
||||
from app.services.test_workflow_service import resolve_dispute
|
||||
with pytest.raises(InvalidOperationError):
|
||||
resolve_dispute(db, test, red_lead, "red")
|
||||
|
||||
def test_invalid_target_team_rejected(self):
|
||||
test = _make_test(
|
||||
TestState.disputed,
|
||||
red_validation_status="approved",
|
||||
blue_validation_status="rejected",
|
||||
)
|
||||
red_lead = _make_user("red_lead")
|
||||
db = _make_db()
|
||||
|
||||
from app.services.test_workflow_service import resolve_dispute
|
||||
with pytest.raises(InvalidOperationError):
|
||||
resolve_dispute(db, test, red_lead, "purple")
|
||||
|
||||
@patch("app.services.test_workflow_service.log_action")
|
||||
def test_admin_can_resolve_dispute_regardless_of_vote(self, mock_log):
|
||||
test = _make_test(
|
||||
TestState.disputed,
|
||||
red_validation_status="approved",
|
||||
blue_validation_status="rejected",
|
||||
)
|
||||
admin = _make_user("admin")
|
||||
db = _make_db()
|
||||
|
||||
from app.services.test_workflow_service import resolve_dispute
|
||||
result = resolve_dispute(db, test, admin, "red")
|
||||
assert result.state == TestState.red_executing
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# 13. select_reviewer — load-balanced reviewer assignment
|
||||
# ===========================================================================
|
||||
|
||||
Reference in New Issue
Block a user