41ca082022
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Failing after 13s
CI / quality (pull_request) Successful in 17s
CI / build (pull_request) Successful in 17s
CI / typecheck (pull_request) Successful in 34s
CI / security (pull_request) Successful in 33s
CI / coverage (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Has been skipped
CI / integration_tests (pull_request) Successful in 2m31s
CI / unit_tests (pull_request) Successful in 6m43s
CI / docker (pull_request) Has been skipped
245 lines
13 KiB
Gherkin
245 lines
13 KiB
Gherkin
@phase2 @correction @coverage
|
|
Feature: CorrectionService comprehensive coverage
|
|
As a developer
|
|
I want thorough unit tests for the CorrectionService
|
|
So that every method and branch has coverage
|
|
|
|
# ── request_correction ───────────────────────────────────────
|
|
|
|
Scenario: Create a revert correction with valid parameters
|
|
Given a fresh correction service instance
|
|
When I create a correction for plan "PX1" targeting "DX1" in revert mode
|
|
Then the new correction should be stored in the service
|
|
And the new correction plan_id should equal "PX1"
|
|
And the new correction target_decision_id should equal "DX1"
|
|
And the new correction mode should equal "revert"
|
|
And the new correction status should equal "pending"
|
|
And the new correction dry_run should be false
|
|
|
|
Scenario: Create correction with empty plan_id raises ValidationError
|
|
Given a fresh correction service instance
|
|
When I attempt to create a correction with an empty plan_id
|
|
Then a service ValidationError should have been raised
|
|
|
|
Scenario: Create correction with empty target_decision_id raises ValidationError
|
|
Given a fresh correction service instance
|
|
When I attempt to create a correction with an empty target_decision_id
|
|
Then a service ValidationError should have been raised
|
|
|
|
Scenario: Create correction with guidance and dry_run flag
|
|
Given a fresh correction service instance
|
|
When I create a correction for plan "PX1" targeting "DX1" in append mode with guidance "Refactor auth" and dry_run true
|
|
Then the new correction guidance should equal "Refactor auth"
|
|
And the new correction dry_run should be true
|
|
And the new correction mode should equal "append"
|
|
|
|
# ── analyze_impact ───────────────────────────────────────────
|
|
|
|
Scenario: Analyze impact with no children yields single node and low risk
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "DX1"
|
|
When I analyze impact with an empty decision tree
|
|
Then the impact affected decisions should be exactly "DX1"
|
|
And the impact risk level should equal "low"
|
|
And the impact rollback tier should equal "full"
|
|
And the impact estimated cost should equal 1.5
|
|
And the impact artifacts to archive should be exactly "DX1.artifact"
|
|
And the impact affected files should be exactly "DX1.py"
|
|
|
|
Scenario: Analyze impact with deep BFS tree traversal
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "A"
|
|
When I analyze impact with tree "A->B,C;B->D,E;C->F"
|
|
Then the impact affected decisions should be exactly "A,B,C,D,E,F"
|
|
And the impact risk level should equal "medium"
|
|
|
|
Scenario: Analyze impact with medium risk subtree of 4 nodes
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "R"
|
|
When I analyze impact with tree "R->C1,C2,C3,C4"
|
|
Then the impact risk level should equal "medium"
|
|
And the impact affected decisions count should be 5
|
|
|
|
Scenario: Analyze impact with high risk subtree of 11 or more nodes
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "R"
|
|
When I analyze impact with a chain tree of 12 nodes rooted at "R"
|
|
Then the impact risk level should equal "high"
|
|
And the impact affected decisions count should be 12
|
|
|
|
Scenario: Analyze impact with non-existent correction raises ResourceNotFoundError
|
|
Given a fresh correction service instance
|
|
When I attempt to analyze impact for correction "bogus-id-999"
|
|
Then a service ResourceNotFoundError should have been raised
|
|
|
|
Scenario: Analyze impact sets status to analyzing
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "DX1"
|
|
When I analyze impact with an empty decision tree
|
|
Then the stored correction status should be "analyzing"
|
|
|
|
Scenario: Analyze impact for append mode yields append_only rollback tier
|
|
Given a fresh correction service instance
|
|
And a stored append correction for plan "PX1" targeting "DX1"
|
|
When I analyze impact with an empty decision tree
|
|
Then the impact rollback tier should equal "append_only"
|
|
|
|
# ── generate_dry_run_report ──────────────────────────────────
|
|
|
|
Scenario: Dry-run report for revert with high risk includes high-risk warning
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "R"
|
|
When I generate a dry-run report with a chain tree of 15 nodes rooted at "R"
|
|
Then the dry-run report mode should equal "revert"
|
|
And the dry-run report warnings should include "High risk"
|
|
And the dry-run report warnings should include "Revert will invalidate"
|
|
And the dry-run report decisions to invalidate should not be empty
|
|
And the dry-run report estimated recompute time should be 30.0
|
|
|
|
Scenario: Dry-run report for revert with medium risk includes medium-risk warning
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "R"
|
|
When I generate a dry-run report with a chain tree of 7 nodes rooted at "R"
|
|
Then the dry-run report warnings should include "Medium risk"
|
|
And the dry-run report warnings should include "Revert will invalidate"
|
|
|
|
Scenario: Dry-run report for append has empty decisions to invalidate
|
|
Given a fresh correction service instance
|
|
And a stored append correction for plan "PX1" targeting "DX1"
|
|
When I generate a dry-run report with an empty decision tree
|
|
Then the dry-run report decisions to invalidate should be empty
|
|
And the dry-run report mode should equal "append"
|
|
|
|
# ── execute_revert ───────────────────────────────────────────
|
|
|
|
Scenario: Execute revert with simple tree returns applied result
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "DX1"
|
|
When I execute revert with tree "DX1->DX2"
|
|
Then the revert result status should equal "applied"
|
|
And the revert result reverted decisions should include "DX1"
|
|
And the revert result reverted decisions should include "DX2"
|
|
And the revert result archived artifacts should include "DX1.artifact"
|
|
And the revert result archived artifacts should include "DX2.artifact"
|
|
|
|
Scenario: Execute revert records a successful attempt with completed_at
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "DX1"
|
|
When I execute revert with an empty decision tree
|
|
Then the service attempts for the correction should have 1 entry
|
|
And the first attempt should have success true
|
|
And the first attempt completed_at should not be none
|
|
|
|
# ── execute_append ───────────────────────────────────────────
|
|
|
|
Scenario: Execute append creates a child plan and new decision
|
|
Given a fresh correction service instance
|
|
And a stored append correction for plan "PX1" targeting "DX1"
|
|
When I execute append for the stored correction
|
|
Then the append result status should equal "applied"
|
|
And the append result spawned_child_plan_id should not be none
|
|
And the append result new decisions should not be empty
|
|
|
|
# ── execute_correction dispatch ──────────────────────────────
|
|
|
|
Scenario: Execute correction dispatches to revert for REVERT mode
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "DX1"
|
|
When I execute correction via the dispatch method with tree "DX1->DX2"
|
|
Then the dispatched result status should equal "applied"
|
|
And the dispatched result reverted decisions should include "DX1"
|
|
|
|
Scenario: Execute correction dispatches to append for APPEND mode
|
|
Given a fresh correction service instance
|
|
And a stored append correction for plan "PX1" targeting "DX1"
|
|
When I execute correction via the dispatch method with no tree
|
|
Then the dispatched result status should equal "applied"
|
|
And the dispatched result spawned_child_plan_id should not be none
|
|
|
|
# ── get_correction ───────────────────────────────────────────
|
|
|
|
Scenario: Get correction with valid id returns the request
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "DX1"
|
|
When I get the stored correction by its id
|
|
Then the retrieved correction plan_id should equal "PX1"
|
|
And the retrieved correction target_decision_id should equal "DX1"
|
|
|
|
Scenario: Get correction with invalid id raises ResourceNotFoundError
|
|
Given a fresh correction service instance
|
|
When I attempt to get correction with id "nonexistent-xyz"
|
|
Then a service ResourceNotFoundError should have been raised
|
|
|
|
# ── list_corrections ─────────────────────────────────────────
|
|
|
|
Scenario: List corrections without filter returns all corrections
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "DX1"
|
|
And a stored append correction for plan "PX2" targeting "DX2"
|
|
When I list all service corrections without filter
|
|
Then the service corrections list should have 2 items
|
|
|
|
Scenario: List corrections with plan_id filter returns only matching
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "DX1"
|
|
And a stored append correction for plan "PX1" targeting "DX2"
|
|
And a stored revert correction for plan "PX2" targeting "DX3"
|
|
When I list service corrections for plan "PX1"
|
|
Then the service corrections list should have 2 items
|
|
When I list service corrections for plan "PX2"
|
|
Then the service corrections list should have 1 items
|
|
|
|
# ── list_attempts ────────────────────────────────────────────
|
|
|
|
Scenario: List attempts for a valid correction returns attempts
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "DX1"
|
|
And the stored correction has been reverted with an empty tree
|
|
When I list attempts for the stored correction
|
|
Then the attempts list should have 1 entry
|
|
|
|
# ── cancel_correction ────────────────────────────────────────
|
|
|
|
Scenario: Cancel correction in pending status succeeds
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "DX1"
|
|
When I cancel the stored correction
|
|
Then the stored correction status should be "cancelled"
|
|
|
|
Scenario: Cancel correction in applied status raises ValidationError
|
|
Given a fresh correction service instance
|
|
And a stored revert correction for plan "PX1" targeting "DX1"
|
|
And the stored correction has been reverted with an empty tree
|
|
When I attempt to cancel the stored correction
|
|
Then a service ValidationError should have been raised
|
|
|
|
# ── _classify_risk boundary tests ────────────────────────────
|
|
|
|
Scenario: Classify risk at exact boundary values
|
|
Given a fresh correction service instance
|
|
Then classifying risk for 0 affected nodes should return "low"
|
|
And classifying risk for 1 affected nodes should return "low"
|
|
And classifying risk for 3 affected nodes should return "low"
|
|
And classifying risk for 4 affected nodes should return "medium"
|
|
And classifying risk for 10 affected nodes should return "medium"
|
|
And classifying risk for 11 affected nodes should return "high"
|
|
And classifying risk for 100 affected nodes should return "high"
|
|
|
|
# ── _compute_affected_subtree BFS order ──────────────────────
|
|
|
|
Scenario: Compute affected subtree follows BFS order
|
|
Given a fresh correction service instance
|
|
When I compute affected subtree for "A" with tree "A->B,C;B->D;C->E"
|
|
Then the affected subtree should be exactly "A,B,C,D,E" in order
|
|
|
|
Scenario: Compute affected subtree with no children returns only root
|
|
Given a fresh correction service instance
|
|
When I compute affected subtree for "LEAF" with an empty tree
|
|
Then the affected subtree should be exactly "LEAF" in order
|
|
|
|
Scenario: Compute affected subtree with wide tree
|
|
Given a fresh correction service instance
|
|
When I compute affected subtree for "R" with tree "R->A,B,C,D,E"
|
|
Then the affected subtree should be exactly "R,A,B,C,D,E" in order
|
|
And the affected subtree count should be 6
|