docs(src): add missing XML docs and strip tracking-ID comments
Sweep of 203 source files resolving CommentChecker findings: add <summary>/<param>/<returns>/<inheritdoc> where missing, and remove resolved task/issue tracking markers (Tests-NNN, Worker-NNN, Server-NNN, Task N) from code comments. Comment/doc-only — no logic changes. Server+Tests build clean under TreatWarningsAsErrors.
This commit is contained in:
@@ -14,6 +14,7 @@ public sealed class WorkerFrameProtocolTests
|
||||
private const string Nonce = "nonce-secret";
|
||||
|
||||
/// <summary>Verifies that valid envelopes round-trip through write and read.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task WriteAndReadAsync_WithValidEnvelope_RoundTripsFrame()
|
||||
{
|
||||
@@ -32,6 +33,7 @@ public sealed class WorkerFrameProtocolTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that wrong protocol version throws mismatch error.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ReadAsync_WithWrongProtocolVersion_ThrowsProtocolVersionMismatch()
|
||||
{
|
||||
@@ -49,6 +51,7 @@ public sealed class WorkerFrameProtocolTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that wrong session ID throws mismatch error.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ReadAsync_WithWrongSessionId_ThrowsSessionMismatch()
|
||||
{
|
||||
@@ -72,6 +75,7 @@ public sealed class WorkerFrameProtocolTests
|
||||
/// length prefix is the leading four bytes of the stream, so a four-zero-byte
|
||||
/// stream is exactly a frame declaring a zero-length payload.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ReadAsync_WithZeroLengthPayload_ThrowsMalformedLength()
|
||||
{
|
||||
@@ -93,6 +97,7 @@ public sealed class WorkerFrameProtocolTests
|
||||
/// A small maximum is configured so the rejection is asserted without
|
||||
/// allocating a multi-megabyte buffer.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ReadAsync_WithPayloadAboveConfiguredMaximum_ThrowsMessageTooLarge()
|
||||
{
|
||||
@@ -115,6 +120,7 @@ public sealed class WorkerFrameProtocolTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that malformed payload throws invalid envelope error.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ReadAsync_WithMalformedPayload_ThrowsInvalidEnvelope()
|
||||
{
|
||||
@@ -130,7 +136,7 @@ public sealed class WorkerFrameProtocolTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Worker.Tests-021 (a): pins the <c>EndOfStream</c> branch of
|
||||
/// Pins the <c>EndOfStream</c> branch of
|
||||
/// <c>WorkerFrameReader.ReadExactlyOrThrowAsync</c>. The gateway
|
||||
/// closing its end of the pipe during a partial-frame read is the
|
||||
/// most common production transport failure; the reader must
|
||||
@@ -140,6 +146,7 @@ public sealed class WorkerFrameProtocolTests
|
||||
/// payload but only supplies 50 bytes, so the inner read loop sees
|
||||
/// <c>bytesRead == 0</c> mid-frame.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ReadAsync_WhenStreamEndsMidFrame_ThrowsEndOfStream()
|
||||
{
|
||||
@@ -157,16 +164,16 @@ public sealed class WorkerFrameProtocolTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Worker.Tests-021 (b): pins the writer-side
|
||||
/// <c>MessageTooLarge</c> branch. A session that constructs an
|
||||
/// envelope whose serialised size exceeds <c>MaxMessageBytes</c>
|
||||
/// must be rejected by the writer before any bytes are sent down
|
||||
/// the pipe, so a misbehaving producer cannot push the receiver
|
||||
/// past its bounds. A small <c>MaxMessageBytes</c> is configured
|
||||
/// so a modest <c>GatewayHello</c> payload — with its nonce
|
||||
/// padded out to several hundred bytes — exceeds the limit
|
||||
/// Pins the writer-side <c>MessageTooLarge</c> branch. A session that
|
||||
/// constructs an envelope whose serialised size exceeds
|
||||
/// <c>MaxMessageBytes</c> must be rejected by the writer before any
|
||||
/// bytes are sent down the pipe, so a misbehaving producer cannot
|
||||
/// push the receiver past its bounds. A small <c>MaxMessageBytes</c>
|
||||
/// is configured so a modest <c>GatewayHello</c> payload — with its
|
||||
/// nonce padded out to several hundred bytes — exceeds the limit
|
||||
/// without allocating anything large.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task WriteAsync_WithEnvelopeAboveConfiguredMaximum_ThrowsMessageTooLarge()
|
||||
{
|
||||
@@ -191,11 +198,10 @@ public sealed class WorkerFrameProtocolTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Worker.Tests-021 (c): documents that the writer-side
|
||||
/// <c>InvalidEnvelope</c> branch (raised when
|
||||
/// <c>WorkerEnvelope.CalculateSize()</c> returns 0) is unreachable
|
||||
/// through public API. <c>WorkerEnvelopeValidator.Validate</c> (run
|
||||
/// before the size check in <c>WorkerFrameWriter.WriteAsync</c>)
|
||||
/// Documents that the writer-side <c>InvalidEnvelope</c> branch
|
||||
/// (raised when <c>WorkerEnvelope.CalculateSize()</c> returns 0) is
|
||||
/// unreachable through public API. <c>WorkerEnvelopeValidator.Validate</c>
|
||||
/// (run before the size check in <c>WorkerFrameWriter.WriteAsync</c>)
|
||||
/// rejects any envelope whose <c>BodyCase</c> is <c>None</c> with
|
||||
/// <c>InvalidEnvelope</c>; a body-less envelope is therefore
|
||||
/// intercepted before the empty-payload branch can fire. Any
|
||||
@@ -209,6 +215,7 @@ public sealed class WorkerFrameProtocolTests
|
||||
/// would weaken the writer against future serialisation
|
||||
/// regressions; this test makes its rationale visible.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task WriteAsync_WithEmptyEnvelope_ThrowsInvalidEnvelopeFromValidator()
|
||||
{
|
||||
@@ -233,6 +240,7 @@ public sealed class WorkerFrameProtocolTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that concurrent writes produce complete serialized frames.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task WriteAsync_WithConcurrentCalls_SerializesCompleteFrames()
|
||||
{
|
||||
@@ -256,12 +264,13 @@ public sealed class WorkerFrameProtocolTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Worker-009 regression: the reader rents its payload buffer from a
|
||||
/// shared pool, so a rented buffer can be larger than the current frame
|
||||
/// and may carry bytes from a previous, larger frame. Reading frames of
|
||||
/// differing sizes back-to-back through one reader must parse each frame
|
||||
/// using only its own payload length, never trailing pooled bytes.
|
||||
/// The reader rents its payload buffer from a shared pool, so a rented
|
||||
/// buffer can be larger than the current frame and may carry bytes from
|
||||
/// a previous, larger frame. Reading frames of differing sizes
|
||||
/// back-to-back through one reader must parse each frame using only its
|
||||
/// own payload length, never trailing pooled bytes.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ReadAsync_WithVaryingFrameSizes_ParsesEachFrameExactly()
|
||||
{
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace ZB.MOM.WW.MxGateway.Worker.Tests.Ipc;
|
||||
public sealed class WorkerPipeClientTests
|
||||
{
|
||||
/// <summary>Verifies that worker client connects and completes handshake.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_ConnectsToPipeAndCompletesHandshake()
|
||||
{
|
||||
@@ -83,6 +84,7 @@ public sealed class WorkerPipeClientTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that worker client retries until pipe server becomes available.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_RetriesUntilPipeServerAppears()
|
||||
{
|
||||
@@ -127,6 +129,7 @@ public sealed class WorkerPipeClientTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that worker client throws timeout if pipe never appears.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_WhenPipeNeverAppears_ThrowsTimeoutException()
|
||||
{
|
||||
@@ -148,7 +151,7 @@ public sealed class WorkerPipeClientTests
|
||||
/// <summary>
|
||||
/// Reads frames until one matching the expected body case is found,
|
||||
/// skipping interleaved heartbeats (the first heartbeat is emitted
|
||||
/// immediately on entering the heartbeat loop — see Worker-002).
|
||||
/// immediately on entering the heartbeat loop).
|
||||
/// </summary>
|
||||
private static async Task<WorkerEnvelope> ReadUntilAsync(
|
||||
WorkerFrameReader reader,
|
||||
|
||||
@@ -20,6 +20,7 @@ public sealed class WorkerPipeSessionTests
|
||||
private const string Nonce = "nonce-secret";
|
||||
|
||||
/// <summary>Verifies that valid gateway hello triggers worker hello and ready responses.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task CompleteStartupHandshakeAsync_WithValidGatewayHello_SendsHelloThenReady()
|
||||
{
|
||||
@@ -51,6 +52,7 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that wrong nonce causes protocol violation fault before initialization.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task CompleteStartupHandshakeAsync_WithWrongNonce_FaultsBeforeInitialization()
|
||||
{
|
||||
@@ -79,6 +81,7 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that unsupported protocol version causes mismatch fault before initialization.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task CompleteStartupHandshakeAsync_WithWrongProtocol_FaultsBeforeInitialization()
|
||||
{
|
||||
@@ -106,6 +109,7 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that malformed frame causes protocol violation fault.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task CompleteStartupHandshakeAsync_WithMalformedFrame_WritesWorkerFault()
|
||||
{
|
||||
@@ -132,6 +136,7 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that MXAccess COM creation failure produces fault instead of ready.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task CompleteStartupHandshakeAsync_WhenMxAccessCreationFails_WritesFaultInsteadOfReady()
|
||||
{
|
||||
@@ -158,6 +163,7 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that heartbeat payload reflects current runtime snapshot.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_SendsHeartbeatPayloadFromRuntimeSnapshot()
|
||||
{
|
||||
@@ -211,6 +217,7 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that heartbeat reports current command correlation during execution.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_WhenCommandIsExecuting_HeartbeatReportsCurrentCorrelation()
|
||||
{
|
||||
@@ -258,6 +265,7 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that worker events are written to the pipe.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_WhenRuntimeHasEvents_WritesWorkerEventEnvelope()
|
||||
{
|
||||
@@ -293,6 +301,7 @@ public sealed class WorkerPipeSessionTests
|
||||
/// (not dispatched to the STA) with an OK reply that echoes the ping
|
||||
/// message into the reply's diagnostic field.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_PingControlCommand_RepliesOkAndEchoesMessage()
|
||||
{
|
||||
@@ -324,6 +333,7 @@ public sealed class WorkerPipeSessionTests
|
||||
/// Verifies that GetSessionState reports the worker's lifecycle as the
|
||||
/// proto SessionState — READY while the message loop is serving.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_GetSessionStateControlCommand_RepliesReady()
|
||||
{
|
||||
@@ -359,6 +369,7 @@ public sealed class WorkerPipeSessionTests
|
||||
/// Verifies that GetWorkerInfo populates the worker process id, version,
|
||||
/// and MXAccess ProgID/CLSID from the worker's own metadata.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_GetWorkerInfoControlCommand_PopulatesWorkerInfoFields()
|
||||
{
|
||||
@@ -398,6 +409,7 @@ public sealed class WorkerPipeSessionTests
|
||||
/// Verifies that DrainEvents drains the runtime session's queued events
|
||||
/// into the reply rather than streaming them as WorkerEvent envelopes.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_DrainEventsControlCommand_ReturnsQueuedEvents()
|
||||
{
|
||||
@@ -442,6 +454,7 @@ public sealed class WorkerPipeSessionTests
|
||||
/// shutdown runs and disposes the runtime session, and that the message
|
||||
/// loop then stops.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_ShutdownWorkerControlCommand_RepliesOkThenShutsDown()
|
||||
{
|
||||
@@ -491,12 +504,12 @@ public sealed class WorkerPipeSessionTests
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that stale STA activity with no command in flight triggers
|
||||
/// the watchdog StaHung fault. Worker-017 changed the watchdog to skip
|
||||
/// the fault while a command is in flight (the worker is busy
|
||||
/// executing it, not hung), so this test deliberately leaves the
|
||||
/// current-command correlation id empty to assert the genuine-hung
|
||||
/// path still fires.
|
||||
/// the watchdog StaHung fault. The watchdog skips the fault while a
|
||||
/// command is in flight (the worker is busy executing it, not hung),
|
||||
/// so this test deliberately leaves the current-command correlation
|
||||
/// id empty to assert the genuine-hung path still fires.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_WhenStaActivityIsStale_WritesWatchdogFault()
|
||||
{
|
||||
@@ -532,17 +545,18 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Worker-017 regression: while a command is in flight (snapshot's
|
||||
/// current command correlation id is non-empty), stale STA activity
|
||||
/// must NOT trigger the watchdog StaHung fault. The STA is busy
|
||||
/// executing the command, not hung; <c>StaRuntime.ProcessQueuedCommands</c>
|
||||
/// only calls <c>MarkActivity()</c> before and after each work item,
|
||||
/// so a synchronously long-running command (e.g. <c>ReadBulk</c>
|
||||
/// waiting <c>timeout_ms</c> for OnDataChange) legitimately freezes
|
||||
/// While a command is in flight (snapshot's current command
|
||||
/// correlation id is non-empty), stale STA activity must NOT trigger
|
||||
/// the watchdog StaHung fault. The STA is busy executing the command,
|
||||
/// not hung; <c>StaRuntime.ProcessQueuedCommands</c> only calls
|
||||
/// <c>MarkActivity()</c> before and after each work item, so a
|
||||
/// synchronously long-running command (e.g. <c>ReadBulk</c> waiting
|
||||
/// <c>timeout_ms</c> for OnDataChange) legitimately freezes
|
||||
/// <c>LastActivityUtc</c>. The heartbeat already advertises the
|
||||
/// in-flight correlation id so the gateway can apply its own per-command
|
||||
/// timeout.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_WhenStaActivityIsStaleWithCommandInFlight_DoesNotWriteWatchdogFault()
|
||||
{
|
||||
@@ -596,13 +610,13 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Worker-004 regression: once the watchdog reports an StaHung fault,
|
||||
/// subsequent heartbeats must report <see cref="WorkerState.Faulted"/>
|
||||
/// rather than a non-faulted state that contradicts the fault. The
|
||||
/// snapshot uses an empty current-command correlation id so the
|
||||
/// heartbeat State is derived from the session state, not forced to
|
||||
/// ExecutingCommand.
|
||||
/// Once the watchdog reports an StaHung fault, subsequent heartbeats
|
||||
/// must report <see cref="WorkerState.Faulted"/> rather than a
|
||||
/// non-faulted state that contradicts the fault. The snapshot uses an
|
||||
/// empty current-command correlation id so the heartbeat State is
|
||||
/// derived from the session state, not forced to ExecutingCommand.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_AfterWatchdogFault_HeartbeatReportsFaultedState()
|
||||
{
|
||||
@@ -643,15 +657,16 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Worker-023 regression: the in-flight-command suppression on the
|
||||
/// <c>StaHung</c> watchdog (Worker-017) is bounded by
|
||||
/// <c>WorkerPipeSessionOptions.HeartbeatStuckCeiling</c>. A truly
|
||||
/// stuck synchronous STA command (e.g. a dead MXAccess provider) would
|
||||
/// otherwise keep <c>CurrentCommandCorrelationId</c> non-empty forever
|
||||
/// and permanently defeat the watchdog. Once <c>LastStaActivityUtc</c>
|
||||
/// has been stale for longer than <c>HeartbeatStuckCeiling</c> the
|
||||
/// watchdog DOES fire <c>StaHung</c> even with a command in flight.
|
||||
/// The in-flight-command suppression on the <c>StaHung</c> watchdog is
|
||||
/// bounded by <c>WorkerPipeSessionOptions.HeartbeatStuckCeiling</c>. A
|
||||
/// truly stuck synchronous STA command (e.g. a dead MXAccess provider)
|
||||
/// would otherwise keep <c>CurrentCommandCorrelationId</c> non-empty
|
||||
/// forever and permanently defeat the watchdog. Once
|
||||
/// <c>LastStaActivityUtc</c> has been stale for longer than
|
||||
/// <c>HeartbeatStuckCeiling</c> the watchdog DOES fire <c>StaHung</c>
|
||||
/// even with a command in flight.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_WhenStaActivityIsStaleBeyondCeilingWithCommandInFlight_WritesWatchdogFault()
|
||||
{
|
||||
@@ -690,10 +705,11 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Worker-025 regression: <c>RunAsync</c> must throw a diagnostic
|
||||
/// exception if the runtime-session factory returns null, rather than
|
||||
/// deferring the failure to an NRE on the next dereference.
|
||||
/// <c>RunAsync</c> must throw a diagnostic exception if the
|
||||
/// runtime-session factory returns null, rather than deferring the
|
||||
/// failure to an NRE on the next dereference.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_WhenRuntimeSessionFactoryReturnsNull_ThrowsDiagnosticException()
|
||||
{
|
||||
@@ -715,11 +731,11 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Worker-006 regression: when graceful shutdown times out, RunAsync
|
||||
/// must still dispose the runtime session in its finally block.
|
||||
/// Skipping disposal on the timed-out path leaked the STA thread and
|
||||
/// the MXAccess COM object.
|
||||
/// When graceful shutdown times out, RunAsync must still dispose the
|
||||
/// runtime session in its finally block. Skipping disposal on the
|
||||
/// timed-out path leaked the STA thread and the MXAccess COM object.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_WhenShutdownTimesOut_StillDisposesRuntimeSession()
|
||||
{
|
||||
@@ -783,6 +799,7 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that shutdown drops late replies and sends shutdown ack.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_WhenShutdownArrivesDuringCommand_DropsLateReplyAndWritesShutdownAck()
|
||||
{
|
||||
@@ -823,6 +840,7 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that command exceptions after shutdown are dropped before ack.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_WhenCommandThrowsAfterShutdown_DropsLateFaultAndWritesShutdownAck()
|
||||
{
|
||||
@@ -852,9 +870,9 @@ public sealed class WorkerPipeSessionTests
|
||||
await pipePair.GatewayWriter
|
||||
.WriteAsync(CreateShutdownEnvelope(), cancellation.Token);
|
||||
|
||||
// The first heartbeat is emitted immediately on entering the loop
|
||||
// (Worker-002), so skip any interleaved heartbeats; the late fault
|
||||
// must still be dropped — no WorkerFault may precede the ack.
|
||||
// The first heartbeat is emitted immediately on entering the loop,
|
||||
// so skip any interleaved heartbeats; the late fault must still be
|
||||
// dropped — no WorkerFault may precede the ack.
|
||||
WorkerEnvelope envelopeAfterShutdown;
|
||||
do
|
||||
{
|
||||
@@ -873,7 +891,7 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Worker.Tests-017 regression: the <c>WorkerCancel</c> branch of
|
||||
/// The <c>WorkerCancel</c> branch of
|
||||
/// <see cref="WorkerPipeSession.DispatchGatewayEnvelopeAsync"/> must
|
||||
/// forward the envelope's correlation id to the runtime session via
|
||||
/// <see cref="IWorkerRuntimeSession.CancelCommand"/> and keep the
|
||||
@@ -881,6 +899,7 @@ public sealed class WorkerPipeSessionTests
|
||||
/// returns <c>true</c> (keep reading), so a subsequent
|
||||
/// <c>WorkerShutdown</c> still produces the normal shutdown ack.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_WhenGatewaySendsWorkerCancel_ForwardsCorrelationIdToRuntimeSession()
|
||||
{
|
||||
@@ -910,7 +929,7 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Worker.Tests-017 regression: the <c>default:</c> arm of
|
||||
/// The <c>default:</c> arm of
|
||||
/// <see cref="WorkerPipeSession.DispatchGatewayEnvelopeAsync"/> must
|
||||
/// throw <see cref="WorkerFrameProtocolException"/> with
|
||||
/// <see cref="WorkerFrameProtocolErrorCode.UnexpectedEnvelopeBody"/>
|
||||
@@ -923,6 +942,7 @@ public sealed class WorkerPipeSessionTests
|
||||
/// pre-handshake protocol violations); the contract this test pins
|
||||
/// is the exception type/error-code and message-loop exit.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_WhenGatewaySendsUnexpectedEnvelopeBodyAfterHandshake_ThrowsAndExitsMessageLoop()
|
||||
{
|
||||
@@ -956,11 +976,12 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Worker-002 regression: the first heartbeat must be emitted
|
||||
/// immediately on entering the heartbeat loop, not after a full
|
||||
/// HeartbeatInterval. A long interval is configured so a delay-first
|
||||
/// loop would fail to deliver a heartbeat inside the assertion window.
|
||||
/// The first heartbeat must be emitted immediately on entering the
|
||||
/// heartbeat loop, not after a full HeartbeatInterval. A long interval
|
||||
/// is configured so a delay-first loop would fail to deliver a
|
||||
/// heartbeat inside the assertion window.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_SendsFirstHeartbeatImmediatelyOnEnteringLoop()
|
||||
{
|
||||
@@ -984,7 +1005,7 @@ public sealed class WorkerPipeSessionTests
|
||||
// if the first heartbeat is not received within 5s, ReadUntilAsync throws
|
||||
// OperationCanceledException and the test fails. A redundant wall-clock
|
||||
// elapsed < 5s assertion would add the same class of flakiness
|
||||
// Workers.Tests-003/004/013/020 corrected elsewhere, so it is omitted here.
|
||||
// corrected elsewhere, so it is omitted here.
|
||||
using CancellationTokenSource heartbeatWait = CancellationTokenSource
|
||||
.CreateLinkedTokenSource(cancellation.Token);
|
||||
heartbeatWait.CancelAfter(TimeSpan.FromSeconds(5));
|
||||
@@ -999,11 +1020,12 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Worker-003 regression: when a command completes after the worker
|
||||
/// has transitioned out of a command-serving state, the dropped
|
||||
/// reply must be logged with a diagnostic rather than discarded
|
||||
/// silently, so a stuck gateway correlation wait can be traced.
|
||||
/// When a command completes after the worker has transitioned out of
|
||||
/// a command-serving state, the dropped reply must be logged with a
|
||||
/// diagnostic rather than discarded silently, so a stuck gateway
|
||||
/// correlation wait can be traced.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task RunAsync_WhenReplyIsDroppedAfterShutdown_LogsDiagnostic()
|
||||
{
|
||||
@@ -1110,7 +1132,7 @@ public sealed class WorkerPipeSessionTests
|
||||
// (default = position in the typical Hello/Command/Cancel/Shutdown
|
||||
// ordering) so a multi-frame test that interleaves the helpers can
|
||||
// assign monotonically increasing values and produce a wire trace
|
||||
// that reads in ascending order — see Worker.Tests-030.
|
||||
// that reads in ascending order.
|
||||
private static WorkerEnvelope CreateGatewayHelloEnvelope(
|
||||
string nonce = Nonce,
|
||||
uint supportedProtocolVersion = GatewayContractInfo.WorkerProtocolVersion,
|
||||
@@ -1346,17 +1368,13 @@ public sealed class WorkerPipeSessionTests
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Records an informational log event.</summary>
|
||||
/// <param name="eventName">The event name.</param>
|
||||
/// <param name="fields">The event fields.</param>
|
||||
/// <inheritdoc />
|
||||
public void Information(string eventName, IReadOnlyDictionary<string, object?> fields)
|
||||
{
|
||||
Record(eventName, fields);
|
||||
}
|
||||
|
||||
/// <summary>Records an error log event.</summary>
|
||||
/// <param name="eventName">The event name.</param>
|
||||
/// <param name="fields">The event fields.</param>
|
||||
/// <inheritdoc />
|
||||
public void Error(string eventName, IReadOnlyDictionary<string, object?> fields)
|
||||
{
|
||||
Record(eventName, fields);
|
||||
@@ -1447,7 +1465,7 @@ public sealed class WorkerPipeSessionTests
|
||||
return new PipePair(gatewayStream, workerStream);
|
||||
}
|
||||
|
||||
/// <summary>Disposes pipe resources.</summary>
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
WorkerStream.Dispose();
|
||||
|
||||
Reference in New Issue
Block a user