Files
poimen-workflows/tests/routing_workflow_test.go
T
Test a0e64224a7
ci / test (push) Successful in 2m12s
feat: RoutingWorkflow + LLM Router + Memory Activity
- Add RoutingWorkflow: generic state machine executor for WorkflowSpec
- Add LLM Router: natural language → WorkflowSpec generation
- Add RetrieveMemoryActivity: query poimen-memory for context
- Add activities: AnalyzeCode, SecurityScan, GenerateReport, Notify, etc.
- Add agent-prompts/router: LLM prompt documentation
- Extend starter with --route flag for routing workflows
- Remove orchestrator job (trigger via API/message instead)
- Clean up: move docs to Desktop, add .gitignore for *.md
2026-09-02 19:21:53 -07:00

273 lines
7.2 KiB
Go

package tests
import (
"context"
"fmt"
"testing"
"github.com/rockliang/poimen/workflows/internal/routing"
"github.com/rockliang/poimen/workflows/statemachine"
"github.com/stretchr/testify/require"
"go.temporal.io/sdk/testsuite"
)
func TestRoutingWorkflow_SimpleWorkflow(t *testing.T) {
testSuite := &testsuite.WorkflowTestSuite{}
env := testSuite.NewTestWorkflowEnvironment()
// Register mock activity
env.RegisterActivity(mockCloneRepoActivity)
// Create simple workflow spec
spec := &routing.WorkflowSpec{
Name: "test-workflow",
Input: map[string]interface{}{
"repo": "https://github.com/test/repo",
"branch": "main",
},
States: []routing.State{
{
Name: "Clone",
Type: routing.StateTypeTask,
Resource: "mockCloneRepoActivity",
Parameters: map[string]interface{}{
"repo": "${input.repo}",
"branch": "${input.branch}",
},
Timeout: "5m",
Retry: &routing.RetryPolicy{
MaxAttempts: 2,
BackoffRate: 1.5,
InitialInterval: "1s",
},
End: true,
},
},
}
input := statemachine.RoutingWorkflowInput{Spec: spec}
env.ExecuteWorkflow(statemachine.RoutingWorkflow, input)
require.True(t, env.IsWorkflowCompleted())
require.NoError(t, env.GetWorkflowError())
var output statemachine.RoutingWorkflowOutput
require.NoError(t, env.GetWorkflowResult(&output))
require.Equal(t, "COMPLETED", output.Status)
require.NotNil(t, output.FinalOutput)
}
func TestRoutingWorkflow_MultiStepWorkflow(t *testing.T) {
testSuite := &testsuite.WorkflowTestSuite{}
env := testSuite.NewTestWorkflowEnvironment()
// Register mock activities
env.RegisterActivity(mockCloneRepoActivity)
env.RegisterActivity(mockAnalyzeActivity)
// Create multi-step workflow spec
spec := &routing.WorkflowSpec{
Name: "multi-step-workflow",
Input: map[string]interface{}{
"repo": "https://github.com/test/repo",
},
States: []routing.State{
{
Name: "Clone",
Type: routing.StateTypeTask,
Resource: "mockCloneRepoActivity",
Parameters: map[string]interface{}{
"repo": "${input.repo}",
},
Timeout: "5m",
Next: "Analyze",
},
{
Name: "Analyze",
Type: routing.StateTypeTask,
Resource: "mockAnalyzeActivity",
Parameters: map[string]interface{}{
"path": "${Clone.output.path}",
},
Timeout: "10m",
End: true,
},
},
}
input := statemachine.RoutingWorkflowInput{Spec: spec}
env.ExecuteWorkflow(statemachine.RoutingWorkflow, input)
require.True(t, env.IsWorkflowCompleted())
require.NoError(t, env.GetWorkflowError())
var output statemachine.RoutingWorkflowOutput
require.NoError(t, env.GetWorkflowResult(&output))
t.Logf("Output: %+v", output)
t.Logf("Error: %s", output.Error)
require.Equal(t, "COMPLETED", output.Status)
require.Contains(t, output.StepResults, "Clone")
require.Contains(t, output.StepResults, "Analyze")
}
func TestRoutingWorkflow_PassState(t *testing.T) {
testSuite := &testsuite.WorkflowTestSuite{}
env := testSuite.NewTestWorkflowEnvironment()
// Create workflow with Pass state
spec := &routing.WorkflowSpec{
Name: "pass-state-workflow",
Input: map[string]interface{}{},
States: []routing.State{
{
Name: "StaticResult",
Type: routing.StateTypePass,
Result: map[string]interface{}{"status": "ok", "message": "static result"},
End: true,
},
},
}
input := statemachine.RoutingWorkflowInput{Spec: spec}
env.ExecuteWorkflow(statemachine.RoutingWorkflow, input)
require.True(t, env.IsWorkflowCompleted())
require.NoError(t, env.GetWorkflowError())
var output statemachine.RoutingWorkflowOutput
require.NoError(t, env.GetWorkflowResult(&output))
require.Equal(t, "COMPLETED", output.Status)
}
func TestRoutingWorkflow_FailState(t *testing.T) {
testSuite := &testsuite.WorkflowTestSuite{}
env := testSuite.NewTestWorkflowEnvironment()
// Create workflow with Fail state
spec := &routing.WorkflowSpec{
Name: "fail-state-workflow",
Input: map[string]interface{}{},
States: []routing.State{
{
Name: "HandleError",
Type: routing.StateTypeFail,
Error: "WorkflowError",
Cause: "Something went wrong",
},
},
}
input := statemachine.RoutingWorkflowInput{Spec: spec}
env.ExecuteWorkflow(statemachine.RoutingWorkflow, input)
require.True(t, env.IsWorkflowCompleted())
require.NoError(t, env.GetWorkflowError())
var output statemachine.RoutingWorkflowOutput
require.NoError(t, env.GetWorkflowResult(&output))
require.Equal(t, "FAILED", output.Status)
require.Contains(t, output.Error, "WorkflowError")
}
func TestRoutingWorkflow_ErrorCatch(t *testing.T) {
testSuite := &testsuite.WorkflowTestSuite{}
env := testSuite.NewTestWorkflowEnvironment()
// Register mock activities
env.RegisterActivity(mockFailingActivity)
// Create workflow with error handling
spec := &routing.WorkflowSpec{
Name: "error-catch-workflow",
Input: map[string]interface{}{},
States: []routing.State{
{
Name: "FlakyStep",
Type: routing.StateTypeTask,
Resource: "mockFailingActivity",
Parameters: map[string]interface{}{},
Timeout: "1m",
Retry: &routing.RetryPolicy{
MaxAttempts: 1,
BackoffRate: 1.0,
InitialInterval: "1s",
},
Catch: []routing.CatchClause{
{
ErrorEquals: []string{"ActivityError"},
Next: "HandleError",
},
},
Next: "Success",
},
{
Name: "Success",
Type: routing.StateTypePass,
Result: "success",
End: true,
},
{
Name: "HandleError",
Type: routing.StateTypeFail,
Error: "CaughtError",
Cause: "Activity failed and was caught",
},
},
}
input := statemachine.RoutingWorkflowInput{Spec: spec}
env.ExecuteWorkflow(statemachine.RoutingWorkflow, input)
require.True(t, env.IsWorkflowCompleted())
require.NoError(t, env.GetWorkflowError())
var output statemachine.RoutingWorkflowOutput
require.NoError(t, env.GetWorkflowResult(&output))
require.Equal(t, "FAILED", output.Status)
require.Contains(t, output.Error, "CaughtError")
}
func TestRoutingWorkflow_EmptySpec(t *testing.T) {
testSuite := &testsuite.WorkflowTestSuite{}
env := testSuite.NewTestWorkflowEnvironment()
// Empty spec
input := statemachine.RoutingWorkflowInput{Spec: nil}
env.ExecuteWorkflow(statemachine.RoutingWorkflow, input)
require.True(t, env.IsWorkflowCompleted())
require.NoError(t, env.GetWorkflowError())
var output statemachine.RoutingWorkflowOutput
require.NoError(t, env.GetWorkflowResult(&output))
require.Equal(t, "FAILED", output.Status)
require.Contains(t, output.Error, "empty")
}
// Mock activities
func mockCloneRepoActivity(ctx context.Context, params map[string]interface{}) (map[string]interface{}, error) {
return map[string]interface{}{
"path": "/tmp/cloned-repo",
"commit": "abc123",
"branch": "main",
}, nil
}
func mockAnalyzeActivity(ctx context.Context, params map[string]interface{}) (map[string]interface{}, error) {
return map[string]interface{}{
"quality": 0.85,
"issues": []string{},
"summary": "Code analysis complete",
}, nil
}
func mockFailingActivity(ctx context.Context, params map[string]interface{}) (map[string]interface{}, error) {
return nil, fmt.Errorf("mock activity failure")
}