epic-12: after epic audit and init commit
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.core.events.types.TransitionId
|
||||
import com.correx.core.transitions.graph.StageConfig
|
||||
import com.correx.core.transitions.graph.TransitionEdge
|
||||
import com.correx.core.transitions.graph.WorkflowGraph
|
||||
import com.correx.core.transitions.resolution.TransitionOrdering
|
||||
import com.correx.core.validation.approval.ApprovalTrigger
|
||||
import com.correx.core.validation.graph.GraphValidator
|
||||
import com.correx.core.validation.model.ValidationContext
|
||||
import com.correx.core.validation.pipeline.ValidationOutcome
|
||||
import com.correx.core.validation.pipeline.ValidationPipeline
|
||||
import com.correx.core.validation.semantic.SemanticValidator
|
||||
import com.correx.core.validation.semantic.rules.CyclePolicyBindingRule
|
||||
import com.correx.core.validation.transition.TransitionValidator
|
||||
import com.correx.testing.fixtures.CycleFixtures
|
||||
import com.correx.testing.fixtures.WorkflowFixtures
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertInstanceOf
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class ValidationPipelineIntegrationTest {
|
||||
|
||||
private val pipeline = ValidationPipeline(
|
||||
validators = listOf(
|
||||
GraphValidator(),
|
||||
TransitionValidator(TransitionOrdering.comparator),
|
||||
SemanticValidator(
|
||||
rules = listOf(
|
||||
CyclePolicyBindingRule(requirePolicyForCycles = true),
|
||||
),
|
||||
),
|
||||
),
|
||||
approvalTrigger = ApprovalTrigger()
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `full validation pipeline returns NeedsApproval when cycles are unbound`() {
|
||||
|
||||
val graph = WorkflowFixtures.simpleGraph()
|
||||
|
||||
val cycles = listOf(CycleFixtures.simpleCycle())
|
||||
|
||||
val context = ValidationContext(
|
||||
graph = graph,
|
||||
detectedCycles = cycles,
|
||||
cyclePolicies = emptySet(),
|
||||
)
|
||||
|
||||
val outcome = pipeline.validate(context)
|
||||
|
||||
assertInstanceOf(ValidationOutcome.NeedsApproval::class.java, outcome)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `rejected outcome retryable is false — set by validator, not orchestrator`() {
|
||||
// A dangling transition triggers GraphValidator ERROR → Rejected(retryable=false).
|
||||
// Ownership rule: the validator sets retryable; the orchestrator must only read it.
|
||||
val a = StageId("A")
|
||||
val ghost = StageId("GHOST")
|
||||
val graphWithDanglingTransition = WorkflowGraph(
|
||||
stages = mapOf(a to StageConfig()),
|
||||
transitions = setOf(TransitionEdge(TransitionId("t1"), from = a, to = ghost) { true }),
|
||||
start = a,
|
||||
)
|
||||
val pipeline = ValidationPipeline(validators = listOf(GraphValidator()), approvalTrigger = null)
|
||||
val outcome = pipeline.validate(ValidationContext(graph = graphWithDanglingTransition))
|
||||
|
||||
assertInstanceOf(ValidationOutcome.Rejected::class.java, outcome)
|
||||
assertFalse((outcome as ValidationOutcome.Rejected).retryable)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user