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

129 lines
4.2 KiB
C#

using w4c_workflows.Models.Nodes;
using w4c_workflows.Services.Nodes;
using Xunit;
namespace w4c_workflows.Tests;
/// <summary>
/// The legacy lowering bridge: a script definition (language + entry, next/onError)
/// becomes a node graph of synthetic <c>core.code</c> nodes while script execution
/// still happens in the language runtime behind the node.
/// </summary>
public class LegacyWorkflowLowererTests
{
private static NodeGraphCompileResult CompileLowered(string yaml)
{
var lowered = LegacyWorkflowLowerer.ToNodeDefinition(NodeTestData.Parse(yaml));
return new NodeGraphCompiler(NodeTestData.CoreCatalog()).Compile(lowered);
}
[Fact]
public void Lowers_the_header_entry_and_tasks_into_core_code_nodes()
{
var yaml = """
name: legacy
mode: function
language: shell
entry: { file: root.sh }
tasks:
- id: a
parent: root
next: b
language: python
entry: { file: a.py }
- id: b
parent: root
entry: { file: b.sh }
""";
var result = CompileLowered(yaml);
Assert.True(result.Success, string.Join("\n", result.Errors));
var graph = result.Graph!;
Assert.Equal(LegacyWorkflowLowerer.EntryStepId, graph.EntryNodeId);
Assert.All(graph.Nodes, n => Assert.Equal("core.code", n.Blueprint.Type));
var entry = graph.Find(LegacyWorkflowLowerer.EntryStepId)!;
Assert.Equal("shell", entry.Parameters["language"]!.GetValue<string>());
Assert.Equal("root.sh", entry.Parameters["entryFile"]!.GetValue<string>());
var a = graph.Find("a")!;
Assert.Equal("python", a.Parameters["language"]!.GetValue<string>());
Assert.Equal("a.py", a.Parameters["entryFile"]!.GetValue<string>());
}
[Fact]
public void Preserves_next_as_main_and_onError_as_the_error_port()
{
var yaml = """
name: legacy-error
mode: function
language: shell
entry: { file: root.sh }
tasks:
- id: a
parent: root
next: b
onError: undo
entry: { file: a.sh }
- id: b
parent: root
entry: { file: b.sh }
- id: undo
parent: root
entry: { file: undo.sh }
""";
var result = CompileLowered(yaml);
Assert.True(result.Success, string.Join("\n", result.Errors));
var graph = result.Graph!;
Assert.Contains(
graph.Edges,
e => e.FromNodeId == LegacyWorkflowLowerer.EntryStepId && e.FromOutput == 0 && e.ToNodeId == "a");
Assert.Contains(graph.Edges, e => e.FromNodeId == "a" && e.FromOutput == 0 && e.ToNodeId == "b");
// core.code's error output is port 1.
Assert.Contains(graph.Edges, e => e.FromNodeId == "a" && e.FromOutput == 1 && e.ToNodeId == "undo");
}
[Fact]
public void Lowers_a_root_only_workflow_to_a_single_entry_node()
{
var yaml = """
name: ping
mode: function
language: shell
entry: { file: ping.sh }
""";
var result = CompileLowered(yaml);
Assert.True(result.Success, string.Join("\n", result.Errors));
Assert.Single(result.Graph!.Nodes);
Assert.Equal(LegacyWorkflowLowerer.EntryStepId, result.Graph!.EntryNodeId);
Assert.Empty(result.Graph!.Edges);
}
[Fact]
public void Avoids_colliding_with_a_task_named_like_the_synthetic_entry()
{
var yaml = """
name: collision
mode: function
language: shell
entry: { file: root.sh }
tasks:
- id: __entry
parent: root
entry: { file: a.sh }
""";
var result = CompileLowered(yaml);
Assert.True(result.Success, string.Join("\n", result.Errors));
Assert.Equal(2, result.Graph!.Nodes.Count);
Assert.NotNull(result.Graph!.Find("__entry"));
Assert.NotNull(result.Graph!.Find("__entry1"));
}
}