feat(inboundapi): mint inbound ExecutionId early, carry it as RouteToCallRequest.ParentExecutionId
This commit is contained in:
@@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging.Abstractions;
|
||||
using NSubstitute;
|
||||
using ScadaLink.Commons.Entities.InboundApi;
|
||||
using ScadaLink.Commons.Interfaces.Services;
|
||||
using ScadaLink.Commons.Messages.InboundApi;
|
||||
|
||||
namespace ScadaLink.InboundAPI.Tests;
|
||||
|
||||
@@ -427,6 +428,71 @@ public class InboundScriptExecutorTests
|
||||
Assert.Contains("whatever", result.ResultJson!);
|
||||
}
|
||||
|
||||
// --- Audit Log #23 (ParentExecutionId, T3): the inbound request's
|
||||
// ExecutionId is threaded through ExecuteAsync onto routed calls ---
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_WithParentExecutionId_RoutedCallCarriesItAsParentExecutionId()
|
||||
{
|
||||
// The endpoint hands ExecuteAsync the inbound request's ExecutionId; a
|
||||
// routed Route.To(...).Call(...) inside the script must stamp that id onto
|
||||
// the RouteToCallRequest as ParentExecutionId.
|
||||
var inboundExecutionId = Guid.NewGuid();
|
||||
|
||||
var locator = Substitute.For<IInstanceLocator>();
|
||||
locator.GetSiteIdForInstanceAsync("inst-1", Arg.Any<CancellationToken>()).Returns("SiteA");
|
||||
var router = Substitute.For<IInstanceRouter>();
|
||||
RouteToCallRequest? captured = null;
|
||||
router.RouteToCallAsync("SiteA", Arg.Do<RouteToCallRequest>(r => captured = r), Arg.Any<CancellationToken>())
|
||||
.Returns(ci => new RouteToCallResponse(
|
||||
((RouteToCallRequest)ci[1]).CorrelationId, true, null, null, DateTimeOffset.UtcNow));
|
||||
var route = new RouteHelper(locator, router);
|
||||
|
||||
var method = new ApiMethod("routes", "return 1;") { Id = 1, TimeoutSeconds = 10 };
|
||||
_executor.RegisterHandler("routes", async ctx =>
|
||||
{
|
||||
await ctx.Route.To("inst-1").Call("doWork");
|
||||
return 1;
|
||||
});
|
||||
|
||||
var result = await _executor.ExecuteAsync(
|
||||
method, new Dictionary<string, object?>(), route, TimeSpan.FromSeconds(10),
|
||||
parentExecutionId: inboundExecutionId);
|
||||
|
||||
Assert.True(result.Success, result.ErrorMessage);
|
||||
Assert.NotNull(captured);
|
||||
Assert.Equal(inboundExecutionId, captured!.ParentExecutionId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_WithoutParentExecutionId_RoutedCallHasNullParentExecutionId()
|
||||
{
|
||||
// ExecuteAsync called without a parent execution id (the default) routes
|
||||
// calls with ParentExecutionId null.
|
||||
var locator = Substitute.For<IInstanceLocator>();
|
||||
locator.GetSiteIdForInstanceAsync("inst-1", Arg.Any<CancellationToken>()).Returns("SiteA");
|
||||
var router = Substitute.For<IInstanceRouter>();
|
||||
RouteToCallRequest? captured = null;
|
||||
router.RouteToCallAsync("SiteA", Arg.Do<RouteToCallRequest>(r => captured = r), Arg.Any<CancellationToken>())
|
||||
.Returns(ci => new RouteToCallResponse(
|
||||
((RouteToCallRequest)ci[1]).CorrelationId, true, null, null, DateTimeOffset.UtcNow));
|
||||
var route = new RouteHelper(locator, router);
|
||||
|
||||
var method = new ApiMethod("routes2", "return 1;") { Id = 1, TimeoutSeconds = 10 };
|
||||
_executor.RegisterHandler("routes2", async ctx =>
|
||||
{
|
||||
await ctx.Route.To("inst-1").Call("doWork");
|
||||
return 1;
|
||||
});
|
||||
|
||||
var result = await _executor.ExecuteAsync(
|
||||
method, new Dictionary<string, object?>(), route, TimeSpan.FromSeconds(10));
|
||||
|
||||
Assert.True(result.Success, result.ErrorMessage);
|
||||
Assert.NotNull(captured);
|
||||
Assert.Null(captured!.ParentExecutionId);
|
||||
}
|
||||
|
||||
private sealed class CompileLogCounter
|
||||
{
|
||||
public int CompilationFailures;
|
||||
|
||||
Reference in New Issue
Block a user