using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging.Abstractions; using w4c_workflows.Data; using w4c_workflows.Models; using w4c_workflows.Services; using w4c_workflows.Services.Runs; using Xunit; namespace w4c_workflows.Tests; [Collection("WorkflowsPostgres")] public class RunLauncherTests { private const string CronYaml = """ name: nightly mode: function language: shell trigger: type: cron cron: "0 9 * * *" entry: { file: nightly.sh } """; private readonly WorkflowsPostgresFixture _fixture; public RunLauncherTests(WorkflowsPostgresFixture fixture) { _fixture = fixture; } private static Workflow CompileAndSave(WorkflowsDbContext db, string tenantId, string yaml) { var compiler = new WorkflowCompiler(new WorkflowValidator(new LanguageRegistry())); var result = compiler.Compile(yaml, "workflows/nightly.yaml", tenantId); Assert.True(result.Success, string.Join("\n", result.Errors)); db.Workflows.Add(result.Workflow!.Workflow); db.Tasks.AddRange(result.Workflow.Tasks); db.SaveChanges(); return result.Workflow.Workflow; } [Fact] public async Task Launch_creates_a_pending_run_with_trigger_input_and_correlation() { var tenantId = "t" + Guid.NewGuid().ToString("N")[..12]; await using var db = _fixture.CreateContext(); var workflow = CompileAndSave(db, tenantId, CronYaml); var launcher = new RunLauncher(db, NullLogger.Instance); var runId = await launcher.LaunchAsync( new LaunchRequest(tenantId, workflow.Id, workflow.TriggerJson, "{\"x\":1}", "corr-1"), default); var run = await db.WorkflowRuns.SingleAsync(r => r.Id == runId); Assert.Equal(workflow.Id, run.WorkflowId); Assert.Equal(tenantId, run.TenantId); Assert.Equal(RunStatus.Pending, run.Status); Assert.Equal(workflow.TriggerJson, run.TriggerJson); Assert.Equal("{\"x\":1}", run.InputJson); Assert.Equal("corr-1", run.CorrelationId); Assert.Null(run.StartedAt); Assert.Null(run.FinishedAt); } [Fact] public async Task Launch_rejects_unknown_workflow() { await using var db = _fixture.CreateContext(); var launcher = new RunLauncher(db, NullLogger.Instance); await Assert.ThrowsAsync(() => launcher.LaunchAsync(new LaunchRequest("t", Guid.NewGuid(), null, null, null), default)); } [Fact] public async Task Launch_rejects_workflow_for_another_tenant() { var tenantId = "t" + Guid.NewGuid().ToString("N")[..12]; await using var db = _fixture.CreateContext(); var workflow = CompileAndSave(db, tenantId, CronYaml); var launcher = new RunLauncher(db, NullLogger.Instance); await Assert.ThrowsAsync(() => launcher.LaunchAsync(new LaunchRequest("other-tenant", workflow.Id, null, null, null), default)); } }