feat(inboundapi): mint inbound ExecutionId early, carry it as RouteToCallRequest.ParentExecutionId
This commit is contained in:
@@ -395,6 +395,78 @@ public class AuditWriteMiddlewareTests
|
||||
Assert.NotEqual(writer.Events[0].ExecutionId, writer.Events[1].ExecutionId);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// ParentExecutionId — Audit Log #23 (ParentExecutionId feature, T3): the
|
||||
// inbound request's ExecutionId is minted ONCE, early, and stashed on
|
||||
// HttpContext.Items so the endpoint handler can carry it onto the routed
|
||||
// RouteToCallRequest as ParentExecutionId. The inbound row that the
|
||||
// middleware itself emits stays top-level — its own ParentExecutionId is
|
||||
// NEVER set.
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InboundExecutionId_IsStashedOnHttpItems_BeforeEndpointRuns()
|
||||
{
|
||||
var writer = new RecordingAuditWriter();
|
||||
var ctx = BuildContext();
|
||||
object? observedDuringHandler = null;
|
||||
var mw = CreateMiddleware(hc =>
|
||||
{
|
||||
// The endpoint handler must be able to read the early-minted id —
|
||||
// it is stashed before _next so a downstream reader sees it.
|
||||
hc.Items.TryGetValue(AuditWriteMiddleware.InboundExecutionIdItemKey, out observedDuringHandler);
|
||||
hc.Response.StatusCode = 200;
|
||||
return Task.CompletedTask;
|
||||
}, writer);
|
||||
|
||||
await mw.InvokeAsync(ctx);
|
||||
|
||||
var stashed = Assert.IsType<Guid>(observedDuringHandler);
|
||||
Assert.NotEqual(Guid.Empty, stashed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InboundRow_ExecutionId_Equals_TheEarlyMintedStashedId()
|
||||
{
|
||||
var writer = new RecordingAuditWriter();
|
||||
var ctx = BuildContext();
|
||||
Guid stashedDuringHandler = Guid.Empty;
|
||||
var mw = CreateMiddleware(hc =>
|
||||
{
|
||||
stashedDuringHandler =
|
||||
(Guid)hc.Items[AuditWriteMiddleware.InboundExecutionIdItemKey]!;
|
||||
hc.Response.StatusCode = 200;
|
||||
return Task.CompletedTask;
|
||||
}, writer);
|
||||
|
||||
await mw.InvokeAsync(ctx);
|
||||
|
||||
// The inbound audit row's ExecutionId must be the SAME id minted early
|
||||
// and shared with the endpoint handler — not a second, late mint.
|
||||
var evt = Assert.Single(writer.Events);
|
||||
Assert.Equal(stashedDuringHandler, evt.ExecutionId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InboundRow_OwnParentExecutionId_StaysNull()
|
||||
{
|
||||
var writer = new RecordingAuditWriter();
|
||||
var ctx = BuildContext();
|
||||
var mw = CreateMiddleware(_ =>
|
||||
{
|
||||
ctx.Response.StatusCode = 200;
|
||||
return Task.CompletedTask;
|
||||
}, writer);
|
||||
|
||||
await mw.InvokeAsync(ctx);
|
||||
|
||||
// The inbound request is itself top-level — only the spawn id flows
|
||||
// OUT on RouteToCallRequest. The inbound row's own ParentExecutionId
|
||||
// is never set.
|
||||
var evt = Assert.Single(writer.Events);
|
||||
Assert.Null(evt.ParentExecutionId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DurationMs_IsRecorded()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user