Implement missing backend endpoints for release orchestration
TASK-002: 11 deployment monitoring endpoints in JobEngine (list, get, logs, events, metrics, pause/resume/cancel/rollback/retry) TASK-003: 6 evidence management endpoints in JobEngine (list, get, verify, export, raw, timeline) TASK-005: 3 release dashboard endpoints in JobEngine (dashboard summary, approve/reject promotion) TASK-006: 2 registry image search endpoints in Scanner (search with 9 mock images, digests lookup) All endpoints return seed/mock data for testing. Auth policies match existing patterns. Dual route registration on both /api/ and /api/v1/ prefixes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
using System.Text.Json;
|
||||
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
|
||||
using StellaOps.ElkSharp;
|
||||
|
||||
namespace StellaOps.Workflow.Renderer.Tests;
|
||||
|
||||
[TestFixture]
|
||||
public class ElkSharpEdgeRefinementTests
|
||||
{
|
||||
[Test]
|
||||
[Property("Intent", "Operational")]
|
||||
public async Task LayoutAsync_WhenBestEffortRenderedTwice_ShouldProduceDeterministicGeometry()
|
||||
{
|
||||
var graph = BuildElkSharpStressGraph();
|
||||
var engine = new ElkSharpLayeredLayoutEngine();
|
||||
var options = new ElkLayoutOptions
|
||||
{
|
||||
Direction = ElkLayoutDirection.LeftToRight,
|
||||
Effort = ElkLayoutEffort.Best,
|
||||
OrderingIterations = 18,
|
||||
PlacementIterations = 10,
|
||||
};
|
||||
|
||||
var first = await engine.LayoutAsync(graph, options);
|
||||
var second = await engine.LayoutAsync(graph, options);
|
||||
|
||||
JsonSerializer.Serialize(first).Should().Be(JsonSerializer.Serialize(second));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Property("Intent", "Operational")]
|
||||
public async Task LayoutAsync_WhenTopToBottomRefinementEnabled_ShouldMatchDisabledOutput()
|
||||
{
|
||||
var graph = BuildElkSharpStressGraph();
|
||||
var engine = new ElkSharpLayeredLayoutEngine();
|
||||
|
||||
var baseline = await engine.LayoutAsync(graph, new ElkLayoutOptions
|
||||
{
|
||||
Direction = ElkLayoutDirection.TopToBottom,
|
||||
Effort = ElkLayoutEffort.Best,
|
||||
OrderingIterations = 18,
|
||||
PlacementIterations = 10,
|
||||
EdgeRefinement = new EdgeRefinementOptions
|
||||
{
|
||||
Enabled = false,
|
||||
},
|
||||
});
|
||||
|
||||
var refined = await engine.LayoutAsync(graph, new ElkLayoutOptions
|
||||
{
|
||||
Direction = ElkLayoutDirection.TopToBottom,
|
||||
Effort = ElkLayoutEffort.Best,
|
||||
OrderingIterations = 18,
|
||||
PlacementIterations = 10,
|
||||
EdgeRefinement = new EdgeRefinementOptions
|
||||
{
|
||||
Enabled = true,
|
||||
MaxGlobalPasses = 2,
|
||||
MaxTrialsPerProblemEdge = 4,
|
||||
},
|
||||
});
|
||||
|
||||
JsonSerializer.Serialize(refined).Should().Be(JsonSerializer.Serialize(baseline));
|
||||
}
|
||||
|
||||
private static ElkGraph BuildElkSharpStressGraph()
|
||||
{
|
||||
return new ElkGraph
|
||||
{
|
||||
Id = "elksharp-refinement",
|
||||
Nodes =
|
||||
[
|
||||
new ElkNode { Id = "start", Label = "Start", Kind = "Start", Width = 88, Height = 48 },
|
||||
new ElkNode { Id = "review", Label = "Review", Kind = "Decision", Width = 176, Height = 120 },
|
||||
new ElkNode { Id = "approve", Label = "Approve", Kind = "Task", Width = 176, Height = 84 },
|
||||
new ElkNode { Id = "retry", Label = "Retry", Kind = "Task", Width = 176, Height = 84 },
|
||||
new ElkNode { Id = "notify", Label = "Notify", Kind = "Task", Width = 176, Height = 84 },
|
||||
new ElkNode { Id = "archive", Label = "Archive", Kind = "Task", Width = 176, Height = 84 },
|
||||
new ElkNode { Id = "end", Label = "End", Kind = "End", Width = 88, Height = 48 },
|
||||
],
|
||||
Edges =
|
||||
[
|
||||
new ElkEdge { Id = "start-review", SourceNodeId = "start", TargetNodeId = "review" },
|
||||
new ElkEdge { Id = "review-approve", SourceNodeId = "review", TargetNodeId = "approve", Label = "when approved" },
|
||||
new ElkEdge { Id = "review-retry", SourceNodeId = "review", TargetNodeId = "retry", Label = "on failure" },
|
||||
new ElkEdge { Id = "approve-notify", SourceNodeId = "approve", TargetNodeId = "notify" },
|
||||
new ElkEdge { Id = "retry-review", SourceNodeId = "retry", TargetNodeId = "review", Label = "repeat while retry" },
|
||||
new ElkEdge { Id = "notify-end", SourceNodeId = "notify", TargetNodeId = "end", Label = "default" },
|
||||
new ElkEdge { Id = "approve-archive", SourceNodeId = "approve", TargetNodeId = "archive" },
|
||||
new ElkEdge { Id = "archive-end", SourceNodeId = "archive", TargetNodeId = "end", Label = "default" },
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user