chore(damn): detekt, build, tests, formatting
fixed detekt issues where possible. fixed disttar failing build because tools is added twice in the server module. added workflowId where required. fixed some tests not being recognized because of runBlocking without explicit return type. formatting + imports.
This commit is contained in:
@@ -47,4 +47,4 @@ class ApprovalTriggerTest {
|
||||
|
||||
assertNull(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,4 +89,4 @@ class GrantSemanticsTest {
|
||||
val decision = engine.evaluate(req, ctx, grants, now)
|
||||
assertEquals(ApprovalOutcome.AUTO_APPROVED, decision.outcome)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,4 +52,4 @@ class TierImmutabilityTest {
|
||||
val decision = engine.evaluate(req, ctx, listOf(grant), now)
|
||||
Assertions.assertEquals(tier, decision.tier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -32,4 +32,4 @@ object ConcurrencyRunner {
|
||||
done.await()
|
||||
executor.shutdown()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,4 +9,4 @@ class DeterministicBarrier(parties: Int) {
|
||||
fun await() {
|
||||
barrier.await()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,4 +29,4 @@ class StageIdTest {
|
||||
|
||||
assertEquals(a, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -29,4 +29,4 @@ class TransitionIdTest {
|
||||
|
||||
assertEquals(a, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -26,4 +26,4 @@ class ValidationReportContractTest {
|
||||
|
||||
assertEquals(r1, r2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -17,6 +17,7 @@ class WorkflowGraphTest {
|
||||
@Test
|
||||
fun `graph stores immutable structure`() {
|
||||
val graph = WorkflowGraph(
|
||||
id = "workflow-test",
|
||||
stages = mapOf(s1 to StageConfig(), s2 to StageConfig()),
|
||||
transitions = setOf(
|
||||
TransitionEdge(
|
||||
@@ -39,6 +40,7 @@ class WorkflowGraphTest {
|
||||
val node = s1
|
||||
|
||||
val graph = WorkflowGraph(
|
||||
id = "workflow-test",
|
||||
stages = mapOf(node to StageConfig()),
|
||||
transitions = emptySet(),
|
||||
start = s1
|
||||
@@ -51,12 +53,14 @@ class WorkflowGraphTest {
|
||||
@Test
|
||||
fun `graph equality is structural`() {
|
||||
val g1 = WorkflowGraph(
|
||||
id = "workflow-test",
|
||||
stages = mapOf(s1 to StageConfig()),
|
||||
transitions = emptySet(),
|
||||
start = s1
|
||||
)
|
||||
|
||||
val g2 = WorkflowGraph(
|
||||
id = "workflow-test",
|
||||
stages = mapOf(s1 to StageConfig()),
|
||||
transitions = emptySet(),
|
||||
start = s1
|
||||
|
||||
+6
-1
@@ -14,11 +14,15 @@ import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class EventsTest {
|
||||
|
||||
private val workflowId = "workflow-test"
|
||||
|
||||
@Test
|
||||
fun `WorkflowStartedEvent survives round-trip`() {
|
||||
val event: EventPayload = WorkflowStartedEvent(
|
||||
sessionId = SessionId("s1"),
|
||||
startStageId = StageId("stage-a"),
|
||||
workflowId = workflowId,
|
||||
)
|
||||
|
||||
val json = eventJson.encodeToString(EventPayload.serializer(), event)
|
||||
@@ -33,6 +37,7 @@ class EventsTest {
|
||||
sessionId = SessionId("s1"),
|
||||
terminalStageId = StageId("stage-a"),
|
||||
totalStages = 1,
|
||||
workflowId = workflowId,
|
||||
)
|
||||
|
||||
val json = eventJson.encodeToString(EventPayload.serializer(), event)
|
||||
@@ -129,4 +134,4 @@ class EventsTest {
|
||||
|
||||
assertEquals(event, decoded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ class GraphValidatorTest {
|
||||
)
|
||||
|
||||
val graph = WorkflowGraph(
|
||||
id = "workflow-test",
|
||||
stages = mapOf(a to StageConfig(), b to StageConfig()),
|
||||
transitions = setOf(edge1, edge2),
|
||||
start = a
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import com.correx.core.context.model.CompressionMetadata
|
||||
import com.correx.core.context.model.ContextLayer
|
||||
import com.correx.core.context.model.TokenBudget
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.core.router.DefaultRouterContextBuilder
|
||||
import com.correx.core.router.model.RouterConfig
|
||||
import com.correx.core.router.model.RouterL2Entry
|
||||
@@ -9,10 +10,6 @@ import com.correx.core.router.model.RouterTurn
|
||||
import com.correx.core.router.model.StageOutcomeKind
|
||||
import com.correx.core.router.model.TurnRole
|
||||
import com.correx.core.router.model.WorkflowStatus
|
||||
import com.correx.core.events.types.ContextEntryId
|
||||
import com.correx.core.events.types.ContextPackId
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.Instant
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
@@ -537,8 +534,18 @@ class RouterContextBuilderTest {
|
||||
RouterTurn(TurnRole.ROUTER, "second reply", Instant.parse("2026-01-04T00:00:00Z")),
|
||||
),
|
||||
l2Memory = listOf(
|
||||
RouterL2Entry(StageId("s1"), "stage one done", StageOutcomeKind.SUCCESS, Instant.parse("2026-01-01T10:00:00Z")),
|
||||
RouterL2Entry(StageId("s2"), "stage two failed", StageOutcomeKind.FAILURE, Instant.parse("2026-01-02T10:00:00Z")),
|
||||
RouterL2Entry(
|
||||
StageId("s1"),
|
||||
"stage one done",
|
||||
StageOutcomeKind.SUCCESS,
|
||||
Instant.parse("2026-01-01T10:00:00Z"),
|
||||
),
|
||||
RouterL2Entry(
|
||||
StageId("s2"),
|
||||
"stage two failed",
|
||||
StageOutcomeKind.FAILURE,
|
||||
Instant.parse("2026-01-02T10:00:00Z"),
|
||||
),
|
||||
),
|
||||
)
|
||||
val pack = builder.build(state, TokenBudget(limit = 10000))
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import com.correx.core.context.model.ContextPack
|
||||
import com.correx.core.context.model.TokenBudget
|
||||
import com.correx.core.events.events.NewEvent
|
||||
import com.correx.core.events.events.SteeringNoteAddedEvent
|
||||
import com.correx.core.events.events.StoredEvent
|
||||
import com.correx.core.events.stores.EventStore
|
||||
import com.correx.core.events.types.ContextPackId
|
||||
import com.correx.core.events.types.InferenceRequestId
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.core.inference.GenerationConfig
|
||||
import com.correx.core.inference.InferenceProvider
|
||||
import com.correx.core.inference.InferenceRequest
|
||||
import com.correx.core.inference.InferenceResponse
|
||||
@@ -14,7 +15,6 @@ import com.correx.core.inference.InferenceRouter
|
||||
import com.correx.core.inference.ModelCapability
|
||||
import com.correx.core.inference.TokenUsage
|
||||
import com.correx.core.router.ChatMode
|
||||
import com.correx.core.router.DefaultRouterContextBuilder
|
||||
import com.correx.core.router.DefaultRouterFacade
|
||||
import com.correx.core.router.RouterContextBuilder
|
||||
import com.correx.core.router.RouterFacade
|
||||
@@ -24,18 +24,13 @@ import com.correx.core.router.model.RouterResponse
|
||||
import com.correx.core.router.model.RouterState
|
||||
import com.correx.core.router.model.TurnRole
|
||||
import com.correx.core.router.model.WorkflowStatus
|
||||
import com.correx.core.context.model.ContextPack
|
||||
import com.correx.core.events.types.ContextPackId
|
||||
import com.correx.core.events.types.ContextEntryId
|
||||
import com.correx.core.context.model.ContextEntry
|
||||
import com.correx.core.context.model.ContextLayer
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertNotNull
|
||||
import org.junit.jupiter.api.Assertions.assertNull
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
class RouterFacadeTest {
|
||||
|
||||
@@ -44,7 +39,7 @@ class RouterFacadeTest {
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
@Test
|
||||
fun `CHAT mode returns inference response content`() = runBlocking {
|
||||
fun `CHAT mode returns inference response content`(): Unit = runBlocking {
|
||||
val mockStore = mockEventStore()
|
||||
val facade = facadeWithMocks(eventStore = mockStore, chatMode = ChatMode.CHAT)
|
||||
val response = facade.onUserInput(sessionId = SessionId("test-session"), input = "Hello, world!")
|
||||
@@ -52,7 +47,7 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CHAT mode sets steeringEmitted to false`() = runBlocking {
|
||||
fun `CHAT mode sets steeringEmitted to false`(): Unit = runBlocking {
|
||||
val mockStore = mockEventStore()
|
||||
val facade = facadeWithMocks(eventStore = mockStore, chatMode = ChatMode.CHAT)
|
||||
val response = facade.onUserInput(sessionId = SessionId("test-session"), input = "Hello!")
|
||||
@@ -60,7 +55,7 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CHAT mode does not append to EventStore`() = runBlocking {
|
||||
fun `CHAT mode does not append to EventStore`(): Unit = runBlocking {
|
||||
val mockStore = mockEventStore()
|
||||
val facade = facadeWithMocks(eventStore = mockStore, chatMode = ChatMode.CHAT)
|
||||
facade.onUserInput(sessionId = SessionId("test-session"), input = "Hello!")
|
||||
@@ -72,7 +67,7 @@ class RouterFacadeTest {
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
@Test
|
||||
fun `STEERING mode sets steeringEmitted to true`() = runBlocking {
|
||||
fun `STEERING mode sets steeringEmitted to true`(): Unit = runBlocking {
|
||||
val mockStore = mockEventStore()
|
||||
val facade = facadeWithMocks(eventStore = mockStore, chatMode = ChatMode.STEERING)
|
||||
val response = facade.onUserInput(sessionId = SessionId("test-session"), input = "Hello!")
|
||||
@@ -80,7 +75,7 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `STEERING mode appends SteeringNoteAddedEvent with correct session id and user input`() = runBlocking {
|
||||
fun `STEERING mode appends SteeringNoteAddedEvent with correct session id and user input`(): Unit = runBlocking {
|
||||
val mockStore = mockEventStore()
|
||||
val facade = facadeWithMocks(eventStore = mockStore, chatMode = ChatMode.STEERING)
|
||||
facade.onUserInput(sessionId = SessionId("session-xyz"), input = "steer this way")
|
||||
@@ -93,13 +88,17 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `STEERING mode appends SteeringNoteAddedEvent with stageId from state`() = runBlocking {
|
||||
fun `STEERING mode appends SteeringNoteAddedEvent with stageId from state`(): Unit = runBlocking {
|
||||
val mockStore = mockEventStore()
|
||||
val stageId = StageId("stage-A")
|
||||
val facade = DefaultRouterFacade(
|
||||
routerRepository = object : RouterRepository {
|
||||
override suspend fun getRouterState(sessionId: SessionId): RouterState =
|
||||
RouterState(sessionId = sessionId, workflowStatus = WorkflowStatus.RUNNING, currentStageId = stageId)
|
||||
RouterState(
|
||||
sessionId = sessionId,
|
||||
workflowStatus = WorkflowStatus.RUNNING,
|
||||
currentStageId = stageId,
|
||||
)
|
||||
},
|
||||
routerContextBuilder = object : RouterContextBuilder {
|
||||
override fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
||||
@@ -114,7 +113,7 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `STEERING mode appends SteeringNoteAddedEvent with null stageId when state has none`() = runBlocking {
|
||||
fun `STEERING mode appends SteeringNoteAddedEvent with null stageId when state has none`(): Unit = runBlocking {
|
||||
val mockStore = mockEventStore()
|
||||
val facade = DefaultRouterFacade(
|
||||
routerRepository = object : RouterRepository {
|
||||
@@ -138,12 +137,16 @@ class RouterFacadeTest {
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
@Test
|
||||
fun `conversation history grows per call — user and router turns appended`() = runBlocking {
|
||||
fun `conversation history grows per call - user and router turns appended`(): Unit = runBlocking {
|
||||
val capturedStates = mutableListOf<RouterState>()
|
||||
val facade = DefaultRouterFacade(
|
||||
routerRepository = object : RouterRepository {
|
||||
override suspend fun getRouterState(sessionId: SessionId): RouterState =
|
||||
RouterState(sessionId = sessionId, workflowStatus = WorkflowStatus.RUNNING, currentStageId = StageId("s1"))
|
||||
RouterState(
|
||||
sessionId = sessionId,
|
||||
workflowStatus = WorkflowStatus.RUNNING,
|
||||
currentStageId = StageId("s1"),
|
||||
)
|
||||
},
|
||||
routerContextBuilder = object : RouterContextBuilder {
|
||||
override fun build(state: RouterState, budget: TokenBudget): ContextPack {
|
||||
@@ -171,7 +174,7 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `conversation history is session-scoped — different sessions do not share history`() = runBlocking {
|
||||
fun `conversation history is session-scoped - different sessions do not share history`(): Unit = runBlocking {
|
||||
val capturedStates = mutableListOf<RouterState>()
|
||||
val facade = DefaultRouterFacade(
|
||||
routerRepository = object : RouterRepository {
|
||||
@@ -204,7 +207,7 @@ class RouterFacadeTest {
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
@Test
|
||||
fun `state is passed through to context builder`() = runBlocking {
|
||||
fun `state is passed through to context builder`(): Unit = runBlocking {
|
||||
val capturedState = mutableListOf<RouterState>()
|
||||
val mockContextBuilder = object : RouterContextBuilder {
|
||||
override fun build(state: RouterState, budget: TokenBudget): ContextPack {
|
||||
@@ -215,7 +218,11 @@ class RouterFacadeTest {
|
||||
val facade = DefaultRouterFacade(
|
||||
routerRepository = object : RouterRepository {
|
||||
override suspend fun getRouterState(sessionId: SessionId): RouterState =
|
||||
RouterState(sessionId = sessionId, workflowStatus = WorkflowStatus.RUNNING, currentStageId = StageId("s1"))
|
||||
RouterState(
|
||||
sessionId = sessionId,
|
||||
workflowStatus = WorkflowStatus.RUNNING,
|
||||
currentStageId = StageId("s1"),
|
||||
)
|
||||
},
|
||||
routerContextBuilder = mockContextBuilder,
|
||||
inferenceRouter = mockInferenceRouter("inference response"),
|
||||
@@ -229,7 +236,7 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `budget is passed through to context builder`() = runBlocking {
|
||||
fun `budget is passed through to context builder`(): Unit = runBlocking {
|
||||
val capturedBudget = mutableListOf<TokenBudget>()
|
||||
val mockContextBuilder = object : RouterContextBuilder {
|
||||
override fun build(state: RouterState, budget: TokenBudget): ContextPack {
|
||||
@@ -252,10 +259,13 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `stage ID uses state currentStageId`() = runBlocking {
|
||||
fun `stage ID uses state currentStageId`(): Unit = runBlocking {
|
||||
val capturedStageId = mutableListOf<StageId>()
|
||||
val mockInferenceRouter = object : InferenceRouter {
|
||||
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider {
|
||||
override suspend fun route(
|
||||
stageId: StageId,
|
||||
requiredCapabilities: Set<ModelCapability>,
|
||||
): InferenceProvider {
|
||||
capturedStageId.add(stageId)
|
||||
return mockProvider("response")
|
||||
}
|
||||
@@ -281,10 +291,13 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `stage ID falls back to StageId("none") when state has no currentStageId`() = runBlocking {
|
||||
fun `stage ID falls back to StageId none when state has no currentStageId`(): Unit = runBlocking {
|
||||
val capturedStageId = mutableListOf<StageId>()
|
||||
val mockInferenceRouter = object : InferenceRouter {
|
||||
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider {
|
||||
override suspend fun route(
|
||||
stageId: StageId,
|
||||
requiredCapabilities: Set<ModelCapability>,
|
||||
): InferenceProvider {
|
||||
capturedStageId.add(stageId)
|
||||
return mockProvider("response")
|
||||
}
|
||||
@@ -309,10 +322,13 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `new InferenceRequestId per call`() = runBlocking {
|
||||
fun `new InferenceRequestId per call`(): Unit = runBlocking {
|
||||
val capturedRequestIds = mutableListOf<InferenceRequestId>()
|
||||
val mockInferenceRouter = object : InferenceRouter {
|
||||
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider {
|
||||
override suspend fun route(
|
||||
stageId: StageId,
|
||||
requiredCapabilities: Set<ModelCapability>,
|
||||
): InferenceProvider {
|
||||
return mockProviderWithCapture("response", capturedRequestIds)
|
||||
}
|
||||
}
|
||||
@@ -334,10 +350,13 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GenerationConfig defaults temperature 0 7 topP 0 9 maxTokens 512`() = runBlocking {
|
||||
fun `GenerationConfig defaults temperature 0 7 topP 0 9 maxTokens 512`(): Unit = runBlocking {
|
||||
val capturedRequests = mutableListOf<InferenceRequest>()
|
||||
val mockInferenceRouter = object : InferenceRouter {
|
||||
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider {
|
||||
override suspend fun route(
|
||||
stageId: StageId,
|
||||
requiredCapabilities: Set<ModelCapability>,
|
||||
): InferenceProvider {
|
||||
return mockProviderWithRequestCapture("response", capturedRequests)
|
||||
}
|
||||
}
|
||||
@@ -360,7 +379,7 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `context pack is passed to inference provider`() = runBlocking {
|
||||
fun `context pack is passed to inference provider`(): Unit = runBlocking {
|
||||
val capturedContextPacks = mutableListOf<ContextPack>()
|
||||
val facade = DefaultRouterFacade(
|
||||
routerRepository = object : RouterRepository {
|
||||
@@ -381,7 +400,10 @@ class RouterFacadeTest {
|
||||
}
|
||||
},
|
||||
inferenceRouter = object : InferenceRouter {
|
||||
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider {
|
||||
override suspend fun route(
|
||||
stageId: StageId,
|
||||
requiredCapabilities: Set<ModelCapability>,
|
||||
): InferenceProvider {
|
||||
return object : InferenceProvider {
|
||||
override val id = com.correx.core.events.types.ProviderId("mock")
|
||||
override val name = "Mock"
|
||||
@@ -397,8 +419,10 @@ class RouterFacadeTest {
|
||||
latencyMs = 0,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun healthCheck(): com.correx.core.inference.ProviderHealth =
|
||||
com.correx.core.inference.ProviderHealth.Healthy
|
||||
|
||||
override fun capabilities(): Set<com.correx.core.inference.CapabilityScore> = emptySet()
|
||||
}
|
||||
}
|
||||
@@ -410,7 +434,7 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `responseFormat defaults to Text`() = runBlocking {
|
||||
fun `responseFormat defaults to Text`(): Unit = runBlocking {
|
||||
val capturedRequests = mutableListOf<InferenceRequest>()
|
||||
val facade = DefaultRouterFacade(
|
||||
routerRepository = object : RouterRepository {
|
||||
@@ -420,7 +444,10 @@ class RouterFacadeTest {
|
||||
override fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
||||
},
|
||||
inferenceRouter = object : InferenceRouter {
|
||||
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider {
|
||||
override suspend fun route(
|
||||
stageId: StageId,
|
||||
requiredCapabilities: Set<ModelCapability>,
|
||||
): InferenceProvider {
|
||||
return mockProviderWithRequestCapture("response", capturedRequests)
|
||||
}
|
||||
},
|
||||
@@ -433,7 +460,7 @@ class RouterFacadeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onUserInput returns RouterResponse with content and mode flag`() = runBlocking {
|
||||
fun `onUserInput returns RouterResponse with content and mode flag`(): Unit = runBlocking {
|
||||
val mockStore = mockEventStore()
|
||||
val facade = facadeWithMocks(eventStore = mockStore, chatMode = ChatMode.STEERING)
|
||||
val response = facade.onUserInput(sessionId = SessionId("test-session"), input = "Hello!")
|
||||
@@ -455,7 +482,11 @@ class RouterFacadeTest {
|
||||
): RouterFacade = DefaultRouterFacade(
|
||||
routerRepository = object : RouterRepository {
|
||||
override suspend fun getRouterState(sessionId: SessionId): RouterState =
|
||||
RouterState(sessionId = sessionId, workflowStatus = WorkflowStatus.RUNNING, currentStageId = StageId("s1"))
|
||||
RouterState(
|
||||
sessionId = sessionId,
|
||||
workflowStatus = WorkflowStatus.RUNNING,
|
||||
currentStageId = StageId("s1"),
|
||||
)
|
||||
},
|
||||
routerContextBuilder = object : RouterContextBuilder {
|
||||
override fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
||||
@@ -472,7 +503,10 @@ class RouterFacadeTest {
|
||||
|
||||
private fun mockInferenceRouter(responseText: String): InferenceRouter =
|
||||
object : InferenceRouter {
|
||||
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider =
|
||||
override suspend fun route(
|
||||
stageId: StageId,
|
||||
requiredCapabilities: Set<ModelCapability>,
|
||||
): InferenceProvider =
|
||||
mockProvider(responseText)
|
||||
}
|
||||
|
||||
@@ -488,8 +522,10 @@ class RouterFacadeTest {
|
||||
tokensUsed = TokenUsage(promptTokens = 10, completionTokens = 5),
|
||||
latencyMs = 0,
|
||||
)
|
||||
|
||||
override suspend fun healthCheck(): com.correx.core.inference.ProviderHealth =
|
||||
com.correx.core.inference.ProviderHealth.Healthy
|
||||
|
||||
override fun capabilities(): Set<com.correx.core.inference.CapabilityScore> =
|
||||
setOf(com.correx.core.inference.CapabilityScore(ModelCapability.General, 1.0))
|
||||
}
|
||||
@@ -512,8 +548,10 @@ class RouterFacadeTest {
|
||||
latencyMs = 0,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun healthCheck(): com.correx.core.inference.ProviderHealth =
|
||||
com.correx.core.inference.ProviderHealth.Healthy
|
||||
|
||||
override fun capabilities(): Set<com.correx.core.inference.CapabilityScore> = emptySet()
|
||||
}
|
||||
|
||||
@@ -535,8 +573,10 @@ class RouterFacadeTest {
|
||||
latencyMs = 0,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun healthCheck(): com.correx.core.inference.ProviderHealth =
|
||||
com.correx.core.inference.ProviderHealth.Healthy
|
||||
|
||||
override fun capabilities(): Set<com.correx.core.inference.CapabilityScore> = emptySet()
|
||||
}
|
||||
|
||||
@@ -568,16 +608,19 @@ class RouterFacadeTest {
|
||||
override suspend fun appendAll(events: List<NewEvent>): List<StoredEvent> =
|
||||
events.map { append(it) }
|
||||
|
||||
override fun read(sessionId: com.correx.core.events.types.SessionId): List<StoredEvent> =
|
||||
override fun read(sessionId: SessionId): List<StoredEvent> =
|
||||
storedEvents.values.filter { it.metadata.sessionId == sessionId }.toList()
|
||||
|
||||
override fun readFrom(sessionId: com.correx.core.events.types.SessionId, fromSequence: Long): List<StoredEvent> =
|
||||
override fun readFrom(
|
||||
sessionId: SessionId,
|
||||
fromSequence: Long,
|
||||
): List<StoredEvent> =
|
||||
read(sessionId).filter { it.sequence >= fromSequence }
|
||||
|
||||
override fun lastSequence(sessionId: com.correx.core.events.types.SessionId): Long? =
|
||||
override fun lastSequence(sessionId: SessionId): Long? =
|
||||
read(sessionId).maxOfOrNull { it.sequence }
|
||||
|
||||
override fun subscribe(sessionId: com.correx.core.events.types.SessionId): kotlinx.coroutines.flow.Flow<StoredEvent> =
|
||||
override fun subscribe(sessionId: SessionId): kotlinx.coroutines.flow.Flow<StoredEvent> =
|
||||
throw UnsupportedOperationException("subscribe not implemented for mock")
|
||||
|
||||
override fun allEvents(): Sequence<StoredEvent> =
|
||||
|
||||
@@ -7,13 +7,13 @@ import com.correx.core.events.events.ToolInvokedEvent
|
||||
import com.correx.core.events.events.WorkflowCompletedEvent
|
||||
import com.correx.core.events.events.WorkflowFailedEvent
|
||||
import com.correx.core.events.events.WorkflowStartedEvent
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.core.router.DefaultRouterReducer
|
||||
import com.correx.core.router.RouterProjector
|
||||
import com.correx.core.router.model.RouterState
|
||||
import com.correx.core.router.model.StageOutcomeKind
|
||||
import com.correx.core.router.model.WorkflowStatus
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.testing.fixtures.EventFixtures.stored
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertNull
|
||||
@@ -26,6 +26,7 @@ class RouterProjectorTest {
|
||||
private val projector = RouterProjector(reducer)
|
||||
private val sessionId = SessionId("s1")
|
||||
private val stageId = StageId("stage-1")
|
||||
private val workflowId = "workflow-test"
|
||||
|
||||
@Test
|
||||
fun `initial() returns RouterState with IDLE status and empty collections`() {
|
||||
@@ -49,7 +50,7 @@ class RouterProjectorTest {
|
||||
val state = projector.initial()
|
||||
val updated = projector.apply(
|
||||
state,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
assertEquals(sessionId, updated.sessionId)
|
||||
assertEquals(WorkflowStatus.RUNNING, updated.workflowStatus)
|
||||
@@ -60,11 +61,11 @@ class RouterProjectorTest {
|
||||
fun `apply(WorkflowCompletedEvent) delegates to reducer and sets COMPLETED`() {
|
||||
val started = projector.apply(
|
||||
projector.initial(),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
val updated = projector.apply(
|
||||
started,
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 3)),
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 3, workflowId)),
|
||||
)
|
||||
assertEquals(WorkflowStatus.COMPLETED, updated.workflowStatus)
|
||||
assertNull(updated.currentStageId)
|
||||
@@ -75,7 +76,7 @@ class RouterProjectorTest {
|
||||
fun `apply(WorkflowFailedEvent) delegates to reducer and sets FAILED`() {
|
||||
val started = projector.apply(
|
||||
projector.initial(),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
val updated = projector.apply(
|
||||
started,
|
||||
@@ -89,7 +90,7 @@ class RouterProjectorTest {
|
||||
fun `apply(OrchestrationPausedEvent) delegates to reducer and sets PAUSED`() {
|
||||
val started = projector.apply(
|
||||
projector.initial(),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
val updated = projector.apply(
|
||||
started,
|
||||
@@ -103,7 +104,7 @@ class RouterProjectorTest {
|
||||
fun `apply(OrchestrationResumedEvent) delegates to reducer and sets RUNNING`() {
|
||||
val started = projector.apply(
|
||||
projector.initial(),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
val paused = projector.apply(
|
||||
started,
|
||||
@@ -133,7 +134,7 @@ class RouterProjectorTest {
|
||||
fun `apply(StageFailedEvent) delegates to reducer and appends FAILURE entry`() {
|
||||
val state = projector.apply(
|
||||
projector.initial(),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
val updated = projector.apply(
|
||||
state,
|
||||
@@ -169,13 +170,13 @@ class RouterProjectorTest {
|
||||
fun `apply produces same result as reducer reduce for every handled event`() {
|
||||
val state = projector.initial()
|
||||
val events = listOf(
|
||||
stored(payload = WorkflowStartedEvent(sessionId, StageId("a"))),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, StageId("a"))),
|
||||
stored(payload = StageCompletedEvent(sessionId, StageId("a"), StageId("t1"))),
|
||||
stored(payload = OrchestrationPausedEvent(sessionId, StageId("a"), "hold")),
|
||||
stored(payload = OrchestrationResumedEvent(sessionId, StageId("a"))),
|
||||
stored(payload = StageCompletedEvent(sessionId, StageId("b"), StageId("t2"))),
|
||||
stored(payload = StageFailedEvent(sessionId, StageId("b"), StageId("t3"), "error")),
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, StageId("c"), 3)),
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, StageId("c"), 3, workflowId)),
|
||||
)
|
||||
|
||||
var projected = state
|
||||
@@ -193,7 +194,7 @@ class RouterProjectorTest {
|
||||
|
||||
state = projector.apply(
|
||||
state,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, StageId("stage-A"))),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, StageId("stage-A"))),
|
||||
)
|
||||
assertEquals(WorkflowStatus.RUNNING, state.workflowStatus)
|
||||
|
||||
@@ -205,7 +206,7 @@ class RouterProjectorTest {
|
||||
|
||||
state = projector.apply(
|
||||
state,
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, StageId("stage-A"), 1)),
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, StageId("stage-A"), 1, workflowId)),
|
||||
)
|
||||
assertEquals(WorkflowStatus.COMPLETED, state.workflowStatus)
|
||||
assertNull(state.currentStageId)
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import com.correx.core.events.events.OrchestrationPausedEvent
|
||||
import com.correx.core.events.events.OrchestrationResumedEvent
|
||||
import com.correx.core.events.events.SteeringNoteAddedEvent
|
||||
import com.correx.core.events.events.StageCompletedEvent
|
||||
import com.correx.core.events.events.StageFailedEvent
|
||||
import com.correx.core.events.events.SteeringNoteAddedEvent
|
||||
import com.correx.core.events.events.ToolInvokedEvent
|
||||
import com.correx.core.events.events.WorkflowCompletedEvent
|
||||
import com.correx.core.events.events.WorkflowFailedEvent
|
||||
import com.correx.core.events.events.WorkflowStartedEvent
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.core.router.DefaultRouterReducer
|
||||
import com.correx.core.router.model.StageOutcomeKind
|
||||
import com.correx.core.router.model.WorkflowStatus
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.testing.fixtures.EventFixtures.stored
|
||||
import kotlinx.datetime.Instant
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
@@ -25,6 +25,7 @@ class RouterReducerTest {
|
||||
private val reducer = DefaultRouterReducer()
|
||||
private val sessionId = SessionId("s1")
|
||||
private val stageId = StageId("stage-1")
|
||||
private val workflowId = "workflow-test"
|
||||
|
||||
@Test
|
||||
fun `initial state has IDLE status and empty collections`() {
|
||||
@@ -41,7 +42,7 @@ class RouterReducerTest {
|
||||
val state = reducer.initial
|
||||
val updated = reducer.reduce(
|
||||
state,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
assertEquals(sessionId, updated.sessionId)
|
||||
assertEquals(WorkflowStatus.RUNNING, updated.workflowStatus)
|
||||
@@ -53,11 +54,11 @@ class RouterReducerTest {
|
||||
val initial = reducer.initial
|
||||
val started = reducer.reduce(
|
||||
initial,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
val completed = reducer.reduce(
|
||||
started,
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 3)),
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 3, workflowId)),
|
||||
)
|
||||
assertEquals(WorkflowStatus.COMPLETED, completed.workflowStatus)
|
||||
assertNull(completed.currentStageId)
|
||||
@@ -69,7 +70,7 @@ class RouterReducerTest {
|
||||
val initial = reducer.initial
|
||||
val started = reducer.reduce(
|
||||
initial,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
val failed = reducer.reduce(
|
||||
started,
|
||||
@@ -84,7 +85,7 @@ class RouterReducerTest {
|
||||
val initial = reducer.initial
|
||||
val started = reducer.reduce(
|
||||
initial,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
val paused = reducer.reduce(
|
||||
started,
|
||||
@@ -99,7 +100,7 @@ class RouterReducerTest {
|
||||
val initial = reducer.initial
|
||||
val started = reducer.reduce(
|
||||
initial,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
val paused = reducer.reduce(
|
||||
started,
|
||||
@@ -130,7 +131,7 @@ class RouterReducerTest {
|
||||
val initial = reducer.initial
|
||||
val started = reducer.reduce(
|
||||
initial,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
val updated = reducer.reduce(
|
||||
started,
|
||||
@@ -146,7 +147,7 @@ class RouterReducerTest {
|
||||
val initial = reducer.initial
|
||||
val started = reducer.reduce(
|
||||
initial,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
val storedEvent = stored(payload = StageFailedEvent(sessionId, stageId, StageId("t1"), "timeout"))
|
||||
val updated = reducer.reduce(started, storedEvent)
|
||||
@@ -189,7 +190,7 @@ class RouterReducerTest {
|
||||
val initial = reducer.initial
|
||||
val started = reducer.reduce(
|
||||
initial,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
val withNote = reducer.reduce(
|
||||
started,
|
||||
@@ -223,7 +224,7 @@ class RouterReducerTest {
|
||||
val s0 = reducer.initial
|
||||
assertEquals(WorkflowStatus.IDLE, s0.workflowStatus)
|
||||
|
||||
val s1 = reducer.reduce(s0, stored(payload = WorkflowStartedEvent(sessionId, StageId("stage-A"))))
|
||||
val s1 = reducer.reduce(s0, stored(payload = WorkflowStartedEvent(sessionId, workflowId, StageId("stage-A"))))
|
||||
assertEquals(WorkflowStatus.RUNNING, s1.workflowStatus)
|
||||
assertEquals(StageId("stage-A"), s1.currentStageId)
|
||||
|
||||
@@ -231,11 +232,15 @@ class RouterReducerTest {
|
||||
assertEquals(1, s2.l2Memory.size)
|
||||
assertEquals(StageOutcomeKind.SUCCESS, s2.l2Memory[0].outcome)
|
||||
|
||||
val s3 = reducer.reduce(s2, stored(payload = WorkflowCompletedEvent(sessionId, StageId("stage-A"), 1)))
|
||||
val s3 =
|
||||
reducer.reduce(s2, stored(payload = WorkflowCompletedEvent(sessionId, StageId("stage-A"), 1, workflowId)))
|
||||
assertEquals(WorkflowStatus.COMPLETED, s3.workflowStatus)
|
||||
assertNull(s3.currentStageId)
|
||||
|
||||
val s4 = reducer.reduce(s3, stored(payload = OrchestrationPausedEvent(sessionId, StageId("stage-A"), "manual pause")))
|
||||
val s4 = reducer.reduce(
|
||||
s3,
|
||||
stored(payload = OrchestrationPausedEvent(sessionId, StageId("stage-A"), "manual pause")),
|
||||
)
|
||||
assertEquals(WorkflowStatus.PAUSED, s4.workflowStatus)
|
||||
|
||||
val s5 = reducer.reduce(s4, stored(payload = OrchestrationResumedEvent(sessionId, StageId("stage-A"))))
|
||||
|
||||
@@ -55,4 +55,4 @@ class SessionReplayDeterminismTest {
|
||||
|
||||
assertEquals(state1, state2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,4 +50,4 @@ object EventFixtures {
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import com.correx.core.events.types.InferenceRequestId
|
||||
import com.correx.core.events.types.ProviderId
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.core.utils.TypeId
|
||||
import com.correx.core.inference.FinishReason
|
||||
import com.correx.core.inference.GenerationConfig
|
||||
import com.correx.core.inference.InferenceProvider
|
||||
@@ -20,6 +19,7 @@ import com.correx.core.inference.InferenceResponse
|
||||
import com.correx.core.inference.InferenceRouter
|
||||
import com.correx.core.inference.ModelCapability
|
||||
import com.correx.core.inference.TokenUsage
|
||||
import com.correx.core.utils.TypeId
|
||||
import com.correx.testing.fixtures.inference.MockInferenceProvider
|
||||
import kotlinx.datetime.Clock
|
||||
import java.util.*
|
||||
|
||||
@@ -20,6 +20,7 @@ object WorkflowFixtures {
|
||||
)
|
||||
|
||||
return WorkflowGraph(
|
||||
id = "workflow-test",
|
||||
stages = mapOf(a to StageConfig(), b to StageConfig()),
|
||||
transitions = setOf(t1),
|
||||
start = a
|
||||
|
||||
+1
-1
@@ -69,4 +69,4 @@ class MockInferenceProvider(
|
||||
override fun capabilities(): Set<CapabilityScore> = declaredCapabilities
|
||||
}
|
||||
|
||||
class InferenceProviderException(message: String) : Exception(message)
|
||||
class InferenceProviderException(message: String) : Exception(message)
|
||||
|
||||
+1
-1
@@ -14,4 +14,4 @@ class MockTokenizer : Tokenizer {
|
||||
|
||||
override suspend fun countTokens(text: String): Int =
|
||||
(text.length + 3) / 4
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -32,12 +32,13 @@ object TransitionFixtures {
|
||||
val c = StageId("C")
|
||||
|
||||
return WorkflowGraph(
|
||||
id = "workflow-test",
|
||||
stages = mapOf(a to StageConfig(), b to StageConfig(), c to StageConfig()),
|
||||
transitions = setOf(
|
||||
TransitionEdge(id = TransitionId("t1"), from = a, to = b, condition = { true }),
|
||||
TransitionEdge(id = TransitionId("t2"), from = b, to = c, condition = { true }),
|
||||
),
|
||||
start = a
|
||||
start = a,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,18 @@ import com.correx.core.approvals.domain.DefaultApprovalEngine
|
||||
import com.correx.core.approvals.model.ApprovalContext
|
||||
import com.correx.core.approvals.model.ApprovalDecision
|
||||
import com.correx.core.approvals.model.ApprovalScopeIdentity
|
||||
import com.correx.core.artifacts.DefaultArtifactReducer
|
||||
import com.correx.core.artifactstore.ArtifactStore
|
||||
import com.correx.core.events.events.ApprovalRequestedEvent
|
||||
import com.correx.core.events.events.InferenceCompletedEvent
|
||||
import com.correx.core.events.events.InferenceStartedEvent
|
||||
import com.correx.core.events.events.OrchestrationPausedEvent
|
||||
import com.correx.core.events.events.OrchestrationResumedEvent
|
||||
import com.correx.core.events.events.WorkflowCompletedEvent
|
||||
import com.correx.core.events.events.WorkflowFailedEvent
|
||||
import com.correx.core.events.events.WorkflowStartedEvent
|
||||
import com.correx.core.events.execution.RetryPolicy
|
||||
import com.correx.core.events.types.ArtifactId
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.core.inference.InferenceRepository
|
||||
@@ -32,23 +37,19 @@ import com.correx.core.sessions.DefaultSessionRepository
|
||||
import com.correx.core.sessions.projections.replay.DefaultEventReplayer
|
||||
import com.correx.core.sessions.projections.replay.EventReplayer
|
||||
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.utils.TypeId
|
||||
import com.correx.core.validation.approval.ApprovalTrigger
|
||||
import com.correx.core.validation.pipeline.ValidationPipeline
|
||||
import com.correx.core.artifacts.DefaultArtifactReducer
|
||||
import com.correx.infrastructure.persistence.InMemoryEventStore
|
||||
import com.correx.infrastructure.persistence.artifact.LiveArtifactRepository
|
||||
import com.correx.testing.contracts.fixtures.artifactstore.NoopArtifactStore
|
||||
import com.correx.testing.fixtures.InferenceFixtures
|
||||
import com.correx.testing.fixtures.context.ContextFixtures
|
||||
import com.correx.testing.fixtures.cyclePolicyMissingValidator
|
||||
import com.correx.testing.fixtures.inference.MockInferenceProvider
|
||||
import com.correx.testing.fixtures.transitions.TransitionFixtures
|
||||
import com.correx.core.artifactstore.ArtifactStore
|
||||
import com.correx.core.events.events.InferenceCompletedEvent
|
||||
import com.correx.core.events.events.InferenceStartedEvent
|
||||
import com.correx.core.events.types.ArtifactId
|
||||
import com.correx.core.utils.TypeId
|
||||
import com.correx.testing.contracts.fixtures.artifactstore.NoopArtifactStore
|
||||
import com.correx.testing.fixtures.transitions.TransitionFixtures.threeStageGraph
|
||||
import com.correx.testing.kernel.MockSessionEventReplayer
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -209,9 +210,10 @@ class SessionOrchestratorIntegrationTest {
|
||||
// Single-stage graph: enterStage(A) triggers exactly one approval; after resume,
|
||||
// the always-true transition moves to the terminal "done" and the workflow completes.
|
||||
val graph = WorkflowGraph(
|
||||
id = "workflow-test",
|
||||
stages = mapOf(StageId("A") to StageConfig()),
|
||||
transitions = setOf(
|
||||
com.correx.core.transitions.graph.TransitionEdge(
|
||||
TransitionEdge(
|
||||
id = com.correx.core.events.types.TransitionId("t1"),
|
||||
from = StageId("A"),
|
||||
to = StageId("done"),
|
||||
@@ -268,6 +270,7 @@ class SessionOrchestratorIntegrationTest {
|
||||
@Test
|
||||
fun `workflow with empty graph fails immediately`(): Unit = runBlocking {
|
||||
val emptyGraph = WorkflowGraph(
|
||||
id = "workflow-test",
|
||||
stages = mapOf(StageId("start") to StageConfig()),
|
||||
transitions = emptySet(),
|
||||
start = StageId("start"),
|
||||
@@ -310,8 +313,8 @@ class SessionOrchestratorIntegrationTest {
|
||||
assertTrue(recordingStore.puts.size >= 2, "Expected at least 2 puts, got ${recordingStore.puts.size}")
|
||||
|
||||
val events = eventStore.read(sessionId)
|
||||
val started = events.mapNotNull { it.payload as? InferenceStartedEvent }.first()
|
||||
val completed = events.mapNotNull { it.payload as? InferenceCompletedEvent }.first()
|
||||
val started = events.firstNotNullOf { it.payload as? InferenceStartedEvent }
|
||||
val completed = events.firstNotNullOf { it.payload as? InferenceCompletedEvent }
|
||||
|
||||
assertEquals(recordingStore.idForIndex(0), started.promptArtifactId)
|
||||
assertEquals(recordingStore.idForIndex(1), completed.responseArtifactId)
|
||||
@@ -325,17 +328,18 @@ class SessionOrchestratorIntegrationTest {
|
||||
val z = StageId("Z")
|
||||
// ghost is missing from stages map but has an outgoing transition so it is non-terminal
|
||||
val brokenGraph = WorkflowGraph(
|
||||
id = "workflow-test",
|
||||
stages = mapOf(a to StageConfig(), b to StageConfig()),
|
||||
transitions = setOf(
|
||||
com.correx.core.transitions.graph.TransitionEdge(
|
||||
TransitionEdge(
|
||||
id = com.correx.core.events.types.TransitionId("t1"), from = a, to = b,
|
||||
condition = { true },
|
||||
),
|
||||
com.correx.core.transitions.graph.TransitionEdge(
|
||||
TransitionEdge(
|
||||
id = com.correx.core.events.types.TransitionId("t2"), from = b, to = ghost,
|
||||
condition = { true },
|
||||
),
|
||||
com.correx.core.transitions.graph.TransitionEdge(
|
||||
TransitionEdge(
|
||||
id = com.correx.core.events.types.TransitionId("t3"), from = ghost, to = z,
|
||||
condition = { true },
|
||||
),
|
||||
@@ -391,5 +395,7 @@ private class RecordingArtifactStore : ArtifactStore {
|
||||
|
||||
override suspend fun get(id: ArtifactId): ByteArray? = byId[id]
|
||||
|
||||
override suspend fun flushBefore(commit: suspend () -> Unit) { commit() }
|
||||
override suspend fun flushBefore(commit: suspend () -> Unit) {
|
||||
commit()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ class ValidationPipelineIntegrationTest {
|
||||
val a = StageId("A")
|
||||
val ghost = StageId("GHOST")
|
||||
val graphWithDanglingTransition = WorkflowGraph(
|
||||
id = "workflow-test",
|
||||
stages = mapOf(a to StageConfig()),
|
||||
transitions = setOf(TransitionEdge(TransitionId("t1"), from = a, to = ghost) { true }),
|
||||
start = a,
|
||||
@@ -69,4 +70,4 @@ class ValidationPipelineIntegrationTest {
|
||||
assertInstanceOf(ValidationOutcome.Rejected::class.java, outcome)
|
||||
assertFalse((outcome as ValidationOutcome.Rejected).retryable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,4 +39,4 @@ class MockSessionEventReplayer : EventReplayer<SessionState> {
|
||||
invalidTransitions = 0,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,4 +165,4 @@ class DefaultRetryCoordinatorTest {
|
||||
// virtual time should have advanced by backoffMs
|
||||
assertEquals(1000L, currentTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,4 +158,4 @@ class ReplayInferenceProviderTest {
|
||||
fun `id is ReplayProvider`() {
|
||||
Assertions.assertEquals(ProviderId("replay-provider"), replayProvider.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,4 +241,4 @@ class DefaultSessionReducerTest {
|
||||
SessionState(
|
||||
status = SessionStatus.PAUSED
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,4 +114,4 @@ class InferenceProjectorTest {
|
||||
assertEquals(InferenceStatus.COMPLETED, currentState.records.first().status)
|
||||
assertEquals(200, currentState.records.first().tokensUsed?.totalTokens)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,4 +188,4 @@ class InferenceReducerTest {
|
||||
assertEquals(1, newState.records.size)
|
||||
assertEquals(InferenceStatus.STARTED, newState.records.first().status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ class OrchestrationProjectorTest {
|
||||
private val projector = OrchestrationProjector(reducer)
|
||||
private val sessionId = SessionId("s1")
|
||||
private val stageId = StageId("stage-1")
|
||||
private val workflowId = "workflow-test"
|
||||
|
||||
@Test
|
||||
fun `should initialize orchestration with IDLE status`() {
|
||||
@@ -32,7 +33,7 @@ class OrchestrationProjectorTest {
|
||||
fun `should set RUNNING on WorkflowStartedEvent`() {
|
||||
val initialState = projector.initial()
|
||||
val started =
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, stageId)))
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)))
|
||||
assertEquals(OrchestrationStatus.RUNNING, started.status)
|
||||
}
|
||||
|
||||
@@ -40,7 +41,7 @@ class OrchestrationProjectorTest {
|
||||
fun `should set RUNNING after resume on pause`() {
|
||||
val initialState = projector.initial()
|
||||
val started =
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, stageId)))
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)))
|
||||
assertEquals(OrchestrationStatus.RUNNING, started.status)
|
||||
val paused =
|
||||
projector.apply(started, stored(payload = OrchestrationPausedEvent(sessionId, stageId, "Tool approval")))
|
||||
@@ -56,7 +57,7 @@ class OrchestrationProjectorTest {
|
||||
fun `should set FAILED on WorkflowFailedEvent`() {
|
||||
val initialState = projector.initial()
|
||||
val started =
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, stageId)))
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)))
|
||||
val failed =
|
||||
projector.apply(
|
||||
started,
|
||||
@@ -69,7 +70,7 @@ class OrchestrationProjectorTest {
|
||||
fun `same events produce same result`() {
|
||||
val initialState = projector.initial()
|
||||
val events = listOf(
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
stored(payload = WorkflowFailedEvent(sessionId, stageId, "Something went wrong", false)),
|
||||
stored(
|
||||
payload = RetryAttemptedEvent(
|
||||
@@ -80,7 +81,7 @@ class OrchestrationProjectorTest {
|
||||
failureReason = "Something went wrong",
|
||||
),
|
||||
),
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 1)),
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 1, workflowId)),
|
||||
)
|
||||
|
||||
val result1 = events.fold(initialState) { state, event ->
|
||||
@@ -96,11 +97,11 @@ class OrchestrationProjectorTest {
|
||||
@Test
|
||||
fun `full pause-resume lifecycle`() {
|
||||
val s0 = projector.initial()
|
||||
val s1 = projector.apply(s0, stored(payload = WorkflowStartedEvent(sessionId, stageId)))
|
||||
val s1 = projector.apply(s0, stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)))
|
||||
val s2 =
|
||||
projector.apply(s1, stored(payload = OrchestrationPausedEvent(sessionId, stageId, "approval required")))
|
||||
val s3 = projector.apply(s2, stored(payload = OrchestrationResumedEvent(sessionId, stageId)))
|
||||
val s4 = projector.apply(s3, stored(payload = WorkflowCompletedEvent(sessionId, stageId, 1)))
|
||||
val s4 = projector.apply(s3, stored(payload = WorkflowCompletedEvent(sessionId, stageId, 1, workflowId)))
|
||||
|
||||
assertEquals(OrchestrationStatus.RUNNING, s1.status)
|
||||
assertEquals(OrchestrationStatus.PAUSED, s2.status)
|
||||
@@ -109,4 +110,4 @@ class OrchestrationProjectorTest {
|
||||
assertFalse(s3.pendingApproval)
|
||||
assertEquals(OrchestrationStatus.COMPLETED, s4.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,13 @@ class OrchestrationReducerTest {
|
||||
private val sessionId = SessionId("s1")
|
||||
private val stageId = StageId("stage-1")
|
||||
private val state = OrchestrationState(stageId)
|
||||
private val workflowId = "workflow-test"
|
||||
|
||||
@Test
|
||||
fun `WorkflowStartedEvent sets status to RUNNING`() {
|
||||
val state = reducer.reduce(
|
||||
state,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
assertEquals(OrchestrationStatus.RUNNING, state.status)
|
||||
assertEquals(stageId, state.currentStageId)
|
||||
@@ -37,7 +38,7 @@ class OrchestrationReducerTest {
|
||||
fun `WorkflowFailedEvent sets status to FAILED and failure reason`() {
|
||||
val started = reducer.reduce(
|
||||
state,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
|
||||
val failed = reducer.reduce(
|
||||
@@ -52,12 +53,12 @@ class OrchestrationReducerTest {
|
||||
fun `WorkflowCompletedEvent sets status to COMPLETED`() {
|
||||
val started = reducer.reduce(
|
||||
state,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
|
||||
val completed = reducer.reduce(
|
||||
started,
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 1)),
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 1, workflowId)),
|
||||
)
|
||||
assertTrue(completed.failureReason.isNullOrBlank())
|
||||
assertEquals(OrchestrationStatus.COMPLETED, completed.status)
|
||||
@@ -68,7 +69,7 @@ class OrchestrationReducerTest {
|
||||
fun `OrchestrationPausedEvent sets status to PAUSED with reason and pending approval`() {
|
||||
val started = reducer.reduce(
|
||||
state,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
|
||||
val paused = reducer.reduce(
|
||||
@@ -84,7 +85,7 @@ class OrchestrationReducerTest {
|
||||
fun `OrchestrationResumedEvent sets status to RUNNING with null reason and no pending approval`() {
|
||||
val started = reducer.reduce(
|
||||
state,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
|
||||
val paused = reducer.reduce(
|
||||
@@ -105,7 +106,7 @@ class OrchestrationReducerTest {
|
||||
fun `RetryAttemptedEvent sets status to RUNNING with null reason and no pending approval`() {
|
||||
val started = reducer.reduce(
|
||||
state,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
|
||||
val failed = reducer.reduce(
|
||||
@@ -137,10 +138,10 @@ class OrchestrationReducerTest {
|
||||
fun `unrelated event does nothing`() {
|
||||
val started = reducer.reduce(
|
||||
state,
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
)
|
||||
|
||||
val unrelated = reducer.reduce(started, stored())
|
||||
assertEquals(started, unrelated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import com.correx.core.events.events.OrchestrationPausedEvent
|
||||
import com.correx.core.events.events.OrchestrationResumedEvent
|
||||
import com.correx.core.events.events.SteeringNoteAddedEvent
|
||||
import com.correx.core.events.events.StageCompletedEvent
|
||||
import com.correx.core.events.events.StageFailedEvent
|
||||
import com.correx.core.events.events.SteeringNoteAddedEvent
|
||||
import com.correx.core.events.events.WorkflowCompletedEvent
|
||||
import com.correx.core.events.events.WorkflowFailedEvent
|
||||
import com.correx.core.events.events.WorkflowStartedEvent
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.core.router.DefaultRouterReducer
|
||||
import com.correx.core.router.RouterProjector
|
||||
import com.correx.core.router.model.StageOutcomeKind
|
||||
import com.correx.core.router.model.WorkflowStatus
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.testing.fixtures.EventFixtures.stored
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertNull
|
||||
@@ -23,6 +23,7 @@ class RouterProjectorTest {
|
||||
private val projector = RouterProjector(reducer)
|
||||
private val sessionId = SessionId("s1")
|
||||
private val stageId = StageId("stage-1")
|
||||
private val workflowId = "workflow-test"
|
||||
|
||||
@Test
|
||||
fun `initial state has IDLE status and empty collections`() {
|
||||
@@ -37,7 +38,7 @@ class RouterProjectorTest {
|
||||
fun `should set RUNNING on WorkflowStartedEvent`() {
|
||||
val initialState = projector.initial()
|
||||
val started =
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, stageId)))
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)))
|
||||
assertEquals(WorkflowStatus.RUNNING, started.workflowStatus)
|
||||
assertEquals(stageId, started.currentStageId)
|
||||
}
|
||||
@@ -46,9 +47,9 @@ class RouterProjectorTest {
|
||||
fun `should set COMPLETED on WorkflowCompletedEvent`() {
|
||||
val initialState = projector.initial()
|
||||
val started =
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, stageId)))
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)))
|
||||
val completed =
|
||||
projector.apply(started, stored(payload = WorkflowCompletedEvent(sessionId, stageId, 1)))
|
||||
projector.apply(started, stored(payload = WorkflowCompletedEvent(sessionId, stageId, 1, workflowId)))
|
||||
assertEquals(WorkflowStatus.COMPLETED, completed.workflowStatus)
|
||||
assertNull(completed.currentStageId)
|
||||
}
|
||||
@@ -57,7 +58,7 @@ class RouterProjectorTest {
|
||||
fun `should set FAILED on WorkflowFailedEvent`() {
|
||||
val initialState = projector.initial()
|
||||
val started =
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, stageId)))
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)))
|
||||
val failed =
|
||||
projector.apply(
|
||||
started,
|
||||
@@ -71,7 +72,7 @@ class RouterProjectorTest {
|
||||
fun `should set PAUSED on OrchestrationPausedEvent`() {
|
||||
val initialState = projector.initial()
|
||||
val started =
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, stageId)))
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)))
|
||||
assertEquals(WorkflowStatus.RUNNING, started.workflowStatus)
|
||||
val paused =
|
||||
projector.apply(started, stored(payload = OrchestrationPausedEvent(sessionId, stageId, "Tool approval")))
|
||||
@@ -82,7 +83,7 @@ class RouterProjectorTest {
|
||||
fun `should set RUNNING after resume on pause`() {
|
||||
val initialState = projector.initial()
|
||||
val started =
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, stageId)))
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)))
|
||||
val paused =
|
||||
projector.apply(started, stored(payload = OrchestrationPausedEvent(sessionId, stageId, "Tool approval")))
|
||||
assertEquals(WorkflowStatus.PAUSED, paused.workflowStatus)
|
||||
@@ -105,7 +106,7 @@ class RouterProjectorTest {
|
||||
fun `should append l2Memory entry and clear currentStageId on StageFailedEvent`() {
|
||||
val initialState = projector.initial()
|
||||
val started =
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, stageId)))
|
||||
projector.apply(initialState, stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)))
|
||||
assertEquals(stageId, started.currentStageId)
|
||||
val failed =
|
||||
projector.apply(started, stored(payload = StageFailedEvent(sessionId, stageId, StageId("t1"), "timeout")))
|
||||
@@ -129,11 +130,11 @@ class RouterProjectorTest {
|
||||
fun `same events produce same result (determinism)`() {
|
||||
val initialState = projector.initial()
|
||||
val events = listOf(
|
||||
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
|
||||
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
|
||||
stored(payload = StageCompletedEvent(sessionId, StageId("stage-2"), StageId("t1"))),
|
||||
stored(payload = SteeringNoteAddedEvent(sessionId, "note")),
|
||||
stored(payload = StageFailedEvent(sessionId, stageId, StageId("t2"), "timeout")),
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 2)),
|
||||
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 2, workflowId)),
|
||||
)
|
||||
|
||||
val result1 = events.fold(initialState) { state, event ->
|
||||
@@ -149,11 +150,12 @@ class RouterProjectorTest {
|
||||
@Test
|
||||
fun `full lifecycle stage complete then stage fail then resume then complete`() {
|
||||
val s0 = projector.initial()
|
||||
val s1 = projector.apply(s0, stored(payload = WorkflowStartedEvent(sessionId, stageId)))
|
||||
val s2 = projector.apply(s1, stored(payload = StageCompletedEvent(sessionId, StageId("stage-2"), StageId("t1"))))
|
||||
val s1 = projector.apply(s0, stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)))
|
||||
val s2 =
|
||||
projector.apply(s1, stored(payload = StageCompletedEvent(sessionId, StageId("stage-2"), StageId("t1"))))
|
||||
val s3 = projector.apply(s2, stored(payload = StageFailedEvent(sessionId, stageId, StageId("t2"), "timeout")))
|
||||
val s4 = projector.apply(s3, stored(payload = WorkflowStartedEvent(sessionId, StageId("stage-3"))))
|
||||
val s5 = projector.apply(s4, stored(payload = WorkflowCompletedEvent(sessionId, stageId, 1)))
|
||||
val s4 = projector.apply(s3, stored(payload = WorkflowStartedEvent(sessionId, workflowId, StageId("stage-3"))))
|
||||
val s5 = projector.apply(s4, stored(payload = WorkflowCompletedEvent(sessionId, stageId, 1, workflowId)))
|
||||
|
||||
assertEquals(WorkflowStatus.RUNNING, s1.workflowStatus)
|
||||
assertEquals(StageId("stage-2"), s2.l2Memory[0].stageId)
|
||||
@@ -169,7 +171,8 @@ class RouterProjectorTest {
|
||||
@Test
|
||||
fun `unknown event type returns unchanged state`() {
|
||||
val initialState = projector.initial()
|
||||
val updated = projector.apply(initialState, stored(payload = com.correx.core.events.events.ToolInvokedEvent("test")))
|
||||
val updated =
|
||||
projector.apply(initialState, stored(payload = com.correx.core.events.events.ToolInvokedEvent("test")))
|
||||
assertEquals(initialState, updated)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,4 +141,4 @@ class SessionProjectorTest {
|
||||
|
||||
assertEquals(state1, state2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,4 +56,4 @@ class ApprovalReplayTest {
|
||||
assertEquals(d1.id, d2.id)
|
||||
assertEquals(ApprovalDecisionId("decision:fixed"), d1.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,4 +21,4 @@ class SessionEmptyReplayTest {
|
||||
|
||||
assertEquals(SessionStatus.CREATED, state.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,4 +54,4 @@ class SessionReplayTest {
|
||||
|
||||
assertEquals(SessionStatus.COMPLETED, state.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,4 +207,4 @@ class TransitionReplayIntegrationTest {
|
||||
|
||||
assertEquals(state1, state2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,4 +30,4 @@ class ValidationReplayTest {
|
||||
|
||||
assertTrue(results.distinct().size == 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class DefaultTransitionResolverTest {
|
||||
private val evaluator = object : TransitionConditionEvaluator {
|
||||
override fun evaluate(
|
||||
condition: TransitionCondition,
|
||||
context: EvaluationContext
|
||||
context: EvaluationContext,
|
||||
): Boolean {
|
||||
return condition.evaluate(context)
|
||||
}
|
||||
@@ -36,20 +36,20 @@ class DefaultTransitionResolverTest {
|
||||
id = "t1",
|
||||
from = "stage-a",
|
||||
to = "stage-b",
|
||||
condition = alwaysTrue()
|
||||
)
|
||||
condition = alwaysTrue(),
|
||||
),
|
||||
),
|
||||
stages = setOf("stage-a", "stage-b")
|
||||
stages = setOf("stage-a", "stage-b"),
|
||||
)
|
||||
|
||||
val result = resolver.resolve(
|
||||
graph = graph,
|
||||
context = context(currentStage = "stage-b")
|
||||
context = context(currentStage = "stage-b"),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
TransitionDecision.NoMatch,
|
||||
result
|
||||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -62,19 +62,19 @@ class DefaultTransitionResolverTest {
|
||||
id = "t1",
|
||||
from = "stage-a",
|
||||
to = "stage-b",
|
||||
condition = alwaysFalse()
|
||||
)
|
||||
)
|
||||
condition = alwaysFalse(),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val result = resolver.resolve(
|
||||
graph = graph,
|
||||
context = context(currentStage = "stage-a")
|
||||
context = context(currentStage = "stage-a"),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
TransitionDecision.Stay,
|
||||
result
|
||||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -87,26 +87,26 @@ class DefaultTransitionResolverTest {
|
||||
id = "t1",
|
||||
from = "stage-a",
|
||||
to = "stage-b",
|
||||
condition = alwaysTrue()
|
||||
)
|
||||
)
|
||||
condition = alwaysTrue(),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val result = resolver.resolve(
|
||||
graph = graph,
|
||||
context = context(currentStage = "stage-a")
|
||||
context = context(currentStage = "stage-a"),
|
||||
)
|
||||
|
||||
val move = assertInstanceOf<TransitionDecision.Move>(result)
|
||||
|
||||
assertEquals(
|
||||
TransitionId("t1"),
|
||||
move.transitionId
|
||||
move.transitionId,
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
StageId("stage-b"),
|
||||
move.to
|
||||
move.to,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -119,32 +119,32 @@ class DefaultTransitionResolverTest {
|
||||
id = "t2",
|
||||
from = "stage-a",
|
||||
to = "stage-c",
|
||||
condition = alwaysTrue()
|
||||
condition = alwaysTrue(),
|
||||
),
|
||||
edge(
|
||||
id = "t1",
|
||||
from = "stage-a",
|
||||
to = "stage-b",
|
||||
condition = alwaysTrue()
|
||||
)
|
||||
)
|
||||
condition = alwaysTrue(),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val result = resolver.resolve(
|
||||
graph = graph,
|
||||
context = context(currentStage = "stage-a")
|
||||
context = context(currentStage = "stage-a"),
|
||||
)
|
||||
|
||||
val move = assertInstanceOf<TransitionDecision.Move>(result)
|
||||
|
||||
assertEquals(
|
||||
TransitionId("t1"),
|
||||
move.transitionId
|
||||
move.transitionId,
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
StageId("stage-b"),
|
||||
move.to
|
||||
move.to,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -157,27 +157,27 @@ class DefaultTransitionResolverTest {
|
||||
id = "t1",
|
||||
from = "stage-x",
|
||||
to = "stage-y",
|
||||
condition = alwaysTrue()
|
||||
condition = alwaysTrue(),
|
||||
),
|
||||
edge(
|
||||
id = "t2",
|
||||
from = "stage-a",
|
||||
to = "stage-b",
|
||||
condition = alwaysTrue()
|
||||
)
|
||||
)
|
||||
condition = alwaysTrue(),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val result = resolver.resolve(
|
||||
graph = graph,
|
||||
context = context(currentStage = "stage-a")
|
||||
context = context(currentStage = "stage-a"),
|
||||
)
|
||||
|
||||
val move = assertInstanceOf<TransitionDecision.Move>(result)
|
||||
|
||||
assertEquals(
|
||||
TransitionId("t2"),
|
||||
move.transitionId
|
||||
move.transitionId,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -185,24 +185,25 @@ class DefaultTransitionResolverTest {
|
||||
id: String,
|
||||
from: String,
|
||||
to: String,
|
||||
condition: TransitionCondition
|
||||
condition: TransitionCondition,
|
||||
): TransitionEdge {
|
||||
return TransitionEdge(
|
||||
id = TransitionId(id),
|
||||
from = StageId(from),
|
||||
to = StageId(to),
|
||||
condition = condition
|
||||
condition = condition,
|
||||
)
|
||||
}
|
||||
|
||||
private fun graph(
|
||||
start: String,
|
||||
transitions: Set<TransitionEdge>,
|
||||
stages: Set<String> = transitions.flatMap { listOf(it.from.value, it.to.value) }.toSet()
|
||||
stages: Set<String> = transitions.flatMap { listOf(it.from.value, it.to.value) }.toSet(),
|
||||
) = WorkflowGraph(
|
||||
id = "workflow-test",
|
||||
start = StageId(start),
|
||||
stages = stages.associate { StageId(it) to StageConfig() },
|
||||
transitions = transitions
|
||||
transitions = transitions,
|
||||
)
|
||||
|
||||
private fun context(
|
||||
@@ -222,4 +223,4 @@ class DefaultTransitionResolverTest {
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private fun alwaysFalse() =
|
||||
TransitionCondition { false }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,4 +69,4 @@ class TransitionEventSerializationTest {
|
||||
|
||||
assertEquals(event, deserialized)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user