125 lines
5.7 KiB
C#
125 lines
5.7 KiB
C#
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using w4c_workflows.Controllers;
|
|
using w4c_workflows.Data;
|
|
using w4c_workflows.Models;
|
|
using Xunit;
|
|
|
|
namespace w4c_workflows.Tests;
|
|
|
|
[Collection("WorkflowsPostgres")]
|
|
public class RunsControllerTests
|
|
{
|
|
private readonly WorkflowsPostgresFixture _fixture;
|
|
|
|
public RunsControllerTests(WorkflowsPostgresFixture fixture)
|
|
{
|
|
_fixture = fixture;
|
|
}
|
|
|
|
private static RunsController Controller(WorkflowsDbContext db, string tenantId)
|
|
{
|
|
var controller = new RunsController(db)
|
|
{
|
|
ControllerContext = new ControllerContext { HttpContext = new DefaultHttpContext() },
|
|
};
|
|
controller.HttpContext.Items["TenantId"] = tenantId;
|
|
return controller;
|
|
}
|
|
|
|
private static string Tenant() => "t" + Guid.NewGuid().ToString("N")[..12];
|
|
|
|
[Fact]
|
|
public async Task List_returns_runs_newest_first_scoped_to_tenant()
|
|
{
|
|
var tenantId = Tenant();
|
|
await using var db = _fixture.CreateContext();
|
|
var workflow = WorkflowDataHelpers.CompileAndSave(db, tenantId, WorkflowDataHelpers.LinearYaml);
|
|
|
|
var older = WorkflowDataHelpers.AddRun(db, workflow, RunStatus.Succeeded,
|
|
startedAt: DateTime.UtcNow.AddMinutes(-10), finishedAt: DateTime.UtcNow.AddMinutes(-9));
|
|
var newer = WorkflowDataHelpers.AddRun(db, workflow, RunStatus.Failed,
|
|
startedAt: DateTime.UtcNow.AddMinutes(-1), finishedAt: DateTime.UtcNow, error: "boom");
|
|
|
|
// A second tenant's runs must never leak into the response.
|
|
var other = Tenant();
|
|
var otherWorkflow = WorkflowDataHelpers.CompileAndSave(db, other, WorkflowDataHelpers.LinearYaml);
|
|
WorkflowDataHelpers.AddRun(db, otherWorkflow, RunStatus.Running, startedAt: DateTime.UtcNow);
|
|
|
|
var result = Assert.IsType<OkObjectResult>(await Controller(db, tenantId).List(null, 50, 0, default));
|
|
var body = Assert.IsType<RunsController.RunListResponse>(result.Value);
|
|
|
|
Assert.Equal(2, body.Total);
|
|
Assert.Equal(new[] { newer.Id, older.Id }, body.Runs.Select(r => r.Id).ToArray());
|
|
Assert.Equal("linear", body.Runs[0].WorkflowName);
|
|
Assert.Equal("boom", body.Runs[0].Error);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task List_filters_by_workflow()
|
|
{
|
|
var tenantId = Tenant();
|
|
await using var db = _fixture.CreateContext();
|
|
var wf1 = WorkflowDataHelpers.CompileAndSave(db, tenantId, WorkflowDataHelpers.LinearYaml, "workflows/a.yaml");
|
|
var wf2 = WorkflowDataHelpers.CompileAndSave(db, tenantId, WorkflowDataHelpers.DurableYaml, "workflows/b.yaml");
|
|
|
|
WorkflowDataHelpers.AddRun(db, wf1, RunStatus.Succeeded, DateTime.UtcNow);
|
|
WorkflowDataHelpers.AddRun(db, wf2, RunStatus.Failed, DateTime.UtcNow);
|
|
|
|
var result = Assert.IsType<OkObjectResult>(await Controller(db, tenantId).List(wf1.Id, 50, 0, default));
|
|
var body = Assert.IsType<RunsController.RunListResponse>(result.Value);
|
|
|
|
Assert.Equal(1, body.Total);
|
|
Assert.Equal(wf1.Id, body.Runs[0].WorkflowId);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Get_returns_detail_and_404s_for_foreign_run()
|
|
{
|
|
var tenantId = Tenant();
|
|
await using var db = _fixture.CreateContext();
|
|
var workflow = WorkflowDataHelpers.CompileAndSave(db, tenantId, WorkflowDataHelpers.LinearYaml);
|
|
var run = WorkflowDataHelpers.AddRun(db, workflow, RunStatus.Succeeded,
|
|
DateTime.UtcNow.AddMinutes(-1), DateTime.UtcNow, error: null);
|
|
|
|
var controller = Controller(db, tenantId);
|
|
var result = Assert.IsType<OkObjectResult>(await controller.Get(run.Id, default));
|
|
var detail = Assert.IsType<RunsController.RunDetail>(result.Value);
|
|
Assert.Equal(run.Id, detail.Id);
|
|
Assert.Equal(workflow.Id, detail.WorkflowId);
|
|
Assert.Equal("linear", detail.WorkflowName);
|
|
|
|
// A run owned by another tenant is not visible.
|
|
var other = Tenant();
|
|
var otherWorkflow = WorkflowDataHelpers.CompileAndSave(db, other, WorkflowDataHelpers.LinearYaml);
|
|
var foreignRun = WorkflowDataHelpers.AddRun(db, otherWorkflow, RunStatus.Succeeded, DateTime.UtcNow);
|
|
Assert.IsType<NotFoundObjectResult>(await controller.Get(foreignRun.Id, default));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Tasks_returns_task_runs_in_dispatch_order()
|
|
{
|
|
var tenantId = Tenant();
|
|
await using var db = _fixture.CreateContext();
|
|
var workflow = WorkflowDataHelpers.CompileAndSave(db, tenantId, WorkflowDataHelpers.LinearYaml);
|
|
var run = WorkflowDataHelpers.AddRun(db, workflow, RunStatus.Running, DateTime.UtcNow);
|
|
|
|
var root = WorkflowDataHelpers.TaskByKey(workflow, "root");
|
|
var a = WorkflowDataHelpers.TaskByKey(workflow, "a");
|
|
db.TaskRuns.AddRange(
|
|
new TaskRun { Id = Guid.NewGuid(), RunId = run.Id, TaskId = root.Id, Attempt = 1, Status = TaskRunStatus.Succeeded, StartedAt = DateTime.UtcNow.AddMinutes(-2), FinishedAt = DateTime.UtcNow.AddMinutes(-1) },
|
|
new TaskRun { Id = Guid.NewGuid(), RunId = run.Id, TaskId = a.Id, Attempt = 1, Status = TaskRunStatus.Failed, Error = "boom", IsCompensation = true, StartedAt = DateTime.UtcNow.AddMinutes(-1), FinishedAt = DateTime.UtcNow });
|
|
db.SaveChanges();
|
|
|
|
var result = Assert.IsType<OkObjectResult>(await Controller(db, tenantId).Tasks(run.Id, default));
|
|
var tasks = Assert.IsType<List<RunsController.TaskRunSummary>>(result.Value);
|
|
|
|
Assert.Equal(2, tasks.Count);
|
|
Assert.Equal("root", tasks[0].TaskKey);
|
|
Assert.Equal("a", tasks[1].TaskKey);
|
|
Assert.True(tasks[1].IsCompensation);
|
|
Assert.Equal("boom", tasks[1].Error);
|
|
}
|
|
}
|