w4c-workflows-api/w4c-workflows-api.Tests/NodeWorkflowAuditTests.cs
2026-09-12 01:02:46 +03:00

89 lines
3.1 KiB
C#

using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using w4c_workflows.Data;
using w4c_workflows.Services.Credentials;
using w4c_workflows.Services.Nodes;
using w4c_workflows.Services.Nodes.Executors;
using w4c_workflows.Services.Nodes.Interpolation;
using Xunit;
namespace w4c_workflows.Tests;
/// <summary>
/// End-to-end check that a node workflow run emits one audit entry per executed
/// node through the real <see cref="NodeWorkflowRunner"/> wiring.
/// </summary>
public class NodeWorkflowAuditTests
{
private const string Tenant = "audit-tenant";
private const string Yaml = """
name: audit-demo
tasks:
- id: prepare
node: { type: core.set }
parameters:
mode: manual
fields:
- name: status
value: ready
next: decide
- id: decide
node: { type: core.if }
parameters:
left: "={{ $json.status }}"
operator: equals
right: ready
edges:
- { output: 0, to: ok }
- { output: 1, to: nope }
- id: ok
node: { type: core.noop }
- id: nope
node: { type: core.noop }
""";
[Fact]
public async Task Audit_records_one_entry_per_executed_node()
{
var connection = new SqliteConnection("DataSource=:memory:");
await connection.OpenAsync();
await using var _connection = connection;
await using var db = new WorkflowsDbContext(new DbContextOptionsBuilder<WorkflowsDbContext>()
.UseSqlite(connection)
.Options);
await WorkflowsSchema.ApplyAsync(db, liteMode: true);
var catalog = NodeTestData.CoreCatalog();
var workflow = WorkflowDataHelpers.CompileAndSave(db, Tenant, Yaml, "workflows/audit.yaml");
var run = WorkflowDataHelpers.AddPendingRun(db, workflow, "[{}]");
var sink = new RecordingActionAuditSink();
var executors = new List<INodeExecutor>
{
new NoOpNodeExecutor(),
new SetNodeExecutor(),
new IfNodeExecutor(),
};
var graphRunner = new NodeGraphRunner(
new NodeExecutorRegistry(executors), new NodeParameterInterpolator());
var vault = new CredentialVault(new ReversibleTestCipher(), new CredentialTypeCatalog());
var runner = new NodeWorkflowRunner(catalog, graphRunner, vault, null, sink);
var outcome = await runner.RunAsync(db, run, workflow, workingDirectory: null, default);
Assert.True(outcome.Succeeded, outcome.Error);
Assert.Equal(4, sink.Entries.Count);
Assert.All(sink.Entries, entry =>
{
Assert.Equal("node.executed", entry.Action);
Assert.Equal("succeeded", entry.Outcome);
Assert.Equal(Tenant, entry.TenantId);
Assert.Equal(run.Id.ToString(), entry.RunId);
});
Assert.Equal(
new[] { "decide", "nope", "ok", "prepare" },
sink.Entries.Select(e => e.NodeId!).OrderBy(x => x, StringComparer.Ordinal).ToArray());
}
}