From 4e335891b4584054bd979131e3affeb7d7b1ef9f Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 10 Sep 2026 15:27:25 -0400 Subject: [PATCH] test(site-runtime): traced reset-aware handshake emits four ordered step rows (#36) Claude-Session: https://claude.ai/code/session_01XPsuy2ZZ5Gbyfpt8PrK5BV --- .../ScriptRuntimeContextTraceEmissionTests.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Scripts/ScriptRuntimeContextTraceEmissionTests.cs b/tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Scripts/ScriptRuntimeContextTraceEmissionTests.cs index bcae4e0f..7c00bf80 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Scripts/ScriptRuntimeContextTraceEmissionTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Scripts/ScriptRuntimeContextTraceEmissionTests.cs @@ -818,4 +818,45 @@ public class ScriptRuntimeContextTraceEmissionTests : TestKit Assert.Null(logs[0].StepEventId); Assert.Equal("script", logs[0].LogSource); } + + /// + /// Gitea #36: the reset-aware handshake is four traced steps in leg order — reset write, + /// reset-echo wait, batch write, response wait — each with its own row id, with no new + /// audit kinds (the Flow Debugger projection needs no change). + /// + [Fact] + public async Task WriteBatchResetAndWait_WhenTraced_EmitsFourStepRowsInLegOrder() + { + var probe = CreateTestProbe(); + var collector = new FlowTraceCollector(); + var ctx = CreateContext(probe.Ref, new CapturingAuditWriter(), traced: true, collector); + + var call = ctx.WriteBatchResetAndWait( + new Dictionary { ["Recipe"] = "R-17" }, + "Trigger", "1", "Ack", "1", TimeSpan.FromSeconds(3), + "Ack", "0", TimeSpan.FromSeconds(2)); + + var reset = probe.ExpectMsg(TimeSpan.FromSeconds(5)); + Assert.True(reset.Trace); + probe.Reply(new SetStaticAttributeResponse(reset.CorrelationId, InstanceName, "Ack", true, null, DateTimeOffset.UtcNow)); + var resetWait = probe.ExpectMsg(TimeSpan.FromSeconds(5)); + probe.Reply(new WaitForAttributeResponse(resetWait.CorrelationId, Matched: true, "0", "Good", TimedOut: false)); + var batch = probe.ExpectMsg(TimeSpan.FromSeconds(5)); + probe.Reply(new WriteAttributeBatchResponse(batch.CorrelationId, true, null)); + var respWait = probe.ExpectMsg(TimeSpan.FromSeconds(5)); + probe.Reply(new WaitForAttributeResponse(respWait.CorrelationId, Matched: true, "1", "Good", TimedOut: false)); + Assert.True((await call).Matched); + + var rows = collector.Snapshot(); + Assert.Equal( + new (AuditKind Kind, string? Target)[] + { + (AuditKind.AttributeWrite, "Ack"), + (AuditKind.AttributeWait, "Ack"), + (AuditKind.AttributeWrite, "Trigger"), + (AuditKind.AttributeWait, "Ack"), + }, + rows.Select(e => (Row(e).Kind, e.Target)).ToList()); + Assert.Equal(4, rows.Select(e => e.EventId).Distinct().Count()); + } }