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") }