using w4c_workflows.Data; using w4c_workflows.Models; using w4c_workflows.Services; using Xunit; namespace w4c_workflows.Tests; /// Shared compile-and-persist helpers for lifecycle/dispatcher tests. internal static class WorkflowDataHelpers { public const string LinearYaml = """ name: linear mode: function language: shell entry: { file: root.sh } tasks: - id: a parent: root next: b language: shell entry: { file: a.sh } - id: b parent: root language: shell entry: { file: b.sh } """; public const string DurableYaml = """ name: durable mode: durable language: shell entry: { file: root.sh } tasks: - id: a parent: root language: shell entry: { file: a.sh } """; /// Three-task success chain where every chained task declares its own /// compensation (onError) target, for saga reverse-compensation tests. public const string SagaYaml = """ name: saga mode: function language: shell entry: { file: root.sh } tasks: - id: a parent: root next: b onError: compensate_a language: shell entry: { file: a.sh } - id: b parent: root next: c onError: compensate_b language: shell entry: { file: b.sh } - id: c parent: root onError: compensate_c language: shell entry: { file: c.sh } - id: compensate_a parent: root language: shell entry: { file: compensate_a.sh } - id: compensate_b parent: root language: shell entry: { file: compensate_b.sh } - id: compensate_c parent: root language: shell entry: { file: compensate_c.sh } """; public static Workflow CompileAndSave(WorkflowsDbContext db, string tenantId, string yaml, string path = "workflows/linear.yaml") { var compiler = new WorkflowCompiler(new WorkflowValidator(new LanguageRegistry())); var result = compiler.Compile(yaml, path, tenantId); Assert.True(result.Success, string.Join("\n", result.Errors)); var workflow = result.Workflow!.Workflow; workflow.Tasks = result.Workflow.Tasks.ToList(); db.Workflows.Add(workflow); db.SaveChanges(); return workflow; } public static WorkflowTask TaskByKey(Workflow workflow, string key) => workflow.Tasks.Single(t => t.Key == key); public static WorkflowRun AddPendingRun(WorkflowsDbContext db, Workflow workflow, string? input = null, Guid? startTaskId = null) { var run = new WorkflowRun { Id = Guid.NewGuid(), WorkflowId = workflow.Id, TenantId = workflow.TenantId, Status = RunStatus.Pending, TriggerJson = "{\"type\":\"event\"}", InputJson = input, CorrelationId = "test-correlation", StartTaskId = startTaskId, }; db.WorkflowRuns.Add(run); db.SaveChanges(); return run; } /// Adds a run in a terminal/in-flight status with an explicit start time. public static WorkflowRun AddRun(WorkflowsDbContext db, Workflow workflow, string status, DateTime? startedAt = null, DateTime? finishedAt = null, string? error = null) { var run = new WorkflowRun { Id = Guid.NewGuid(), WorkflowId = workflow.Id, TenantId = workflow.TenantId, Status = status, TriggerJson = "{\"type\":\"event\"}", CorrelationId = $"corr-{Guid.NewGuid():N}", StartedAt = startedAt, FinishedAt = finishedAt, Error = error, }; db.WorkflowRuns.Add(run); db.SaveChanges(); return run; } }