docs: complete XML-doc coverage and strip internal tracking IDs from code comments
ci / java (push) Successful in 5m51s
ci / portable (push) Successful in 6m43s

Resolve all CommentChecker findings across the gateway server, worker, tests,
and .NET client (314 -> 0 real issues): add missing <returns>/<summary>/<param>
on public and test members, convert Stream/interface overrides to <inheritdoc/>,
and remove internal task/issue tracking IDs (SEC-*, IPC-*, WRK-*, GWC-*, TST-*,
Client.Dotnet-*) from shipped code documentation while preserving the design
rationale prose. Shipped comments should not carry internal bookkeeping, and
complete XML docs keep the analyzer/TreatWarningsAsErrors gate and generated API
docs clean. The 6 remaining flags are heuristic false positives (MD5, UTC-4,
capacity-1, near-1601) left intact so real documentation is not corrupted.

Claude-Session: https://claude.ai/code/session_01DMXXvNuPekkkrTEyPNxEkW
This commit is contained in:
Joseph Doherty
2026-07-10 06:15:47 -04:00
parent abb0930359
commit b86c6bb47f
74 changed files with 393 additions and 298 deletions
@@ -14,6 +14,7 @@ public sealed class BrowseChildrenSmokeTests
/// Verifies that BrowseChildren returns a non-zero cache sequence and
/// a consistent children/child-has-children count from a live gateway.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact(Skip = "Set MXGATEWAY_API_KEY and MXGATEWAY_ENDPOINT to enable.")]
public async Task BrowseChildren_LiveGateway_ReturnsRootsWithCacheSequence()
{
@@ -8,14 +8,10 @@ namespace ZB.MOM.WW.MxGateway.Client.Tests;
/// </summary>
internal sealed class FakeGalaxyRepositoryTransport(MxGatewayClientOptions options) : IGalaxyRepositoryClientTransport
{
/// <summary>
/// Gets the gateway client options.
/// </summary>
/// <inheritdoc />
public MxGatewayClientOptions Options { get; } = options;
/// <summary>
/// Gets the raw gRPC client; always null for the fake.
/// </summary>
/// <inheritdoc />
public GalaxyRepository.GalaxyRepositoryClient? RawClient => null;
/// <summary>
@@ -66,11 +62,7 @@ internal sealed class FakeGalaxyRepositoryTransport(MxGatewayClientOptions optio
/// </summary>
public Queue<Exception> DiscoverHierarchyExceptions { get; } = new();
/// <summary>
/// Records the request and either throws a queued exception or returns the configured reply.
/// </summary>
/// <param name="request">The TestConnectionRequest to process.</param>
/// <param name="callOptions">Call options specifying RPC behavior.</param>
/// <inheritdoc />
public Task<TestConnectionReply> TestConnectionAsync(
TestConnectionRequest request,
CallOptions callOptions)
@@ -84,11 +76,7 @@ internal sealed class FakeGalaxyRepositoryTransport(MxGatewayClientOptions optio
return Task.FromResult(TestConnectionReply);
}
/// <summary>
/// Records the request and either throws a queued exception or returns the configured reply.
/// </summary>
/// <param name="request">The GetLastDeployTimeRequest to process.</param>
/// <param name="callOptions">Call options specifying RPC behavior.</param>
/// <inheritdoc />
public Task<GetLastDeployTimeReply> GetLastDeployTimeAsync(
GetLastDeployTimeRequest request,
CallOptions callOptions)
@@ -102,11 +90,7 @@ internal sealed class FakeGalaxyRepositoryTransport(MxGatewayClientOptions optio
return Task.FromResult(GetLastDeployTimeReply);
}
/// <summary>
/// Records the request and either throws a queued exception or returns the configured reply.
/// </summary>
/// <param name="request">The DiscoverHierarchyRequest to process.</param>
/// <param name="callOptions">Call options specifying RPC behavior.</param>
/// <inheritdoc />
public Task<DiscoverHierarchyReply> DiscoverHierarchyAsync(
DiscoverHierarchyRequest request,
CallOptions callOptions)
@@ -141,11 +125,7 @@ internal sealed class FakeGalaxyRepositoryTransport(MxGatewayClientOptions optio
/// </summary>
public Func<Task>? BrowseChildrenGate { get; set; }
/// <summary>
/// Records the request and either throws a queued exception or returns the configured reply.
/// </summary>
/// <param name="request">The BrowseChildrenRequest to process.</param>
/// <param name="callOptions">Call options specifying RPC behavior.</param>
/// <inheritdoc />
public async Task<BrowseChildrenReply> BrowseChildrenAsync(
BrowseChildrenRequest request,
CallOptions callOptions)
@@ -187,11 +167,7 @@ internal sealed class FakeGalaxyRepositoryTransport(MxGatewayClientOptions optio
/// </summary>
public Func<CancellationToken, Task>? WatchDeployEventsBeforeYield { get; set; }
/// <summary>
/// Records the request and streams events, checking for queued exceptions and calling WatchDeployEventsBeforeYield before each event.
/// </summary>
/// <param name="request">The WatchDeployEventsRequest to process.</param>
/// <param name="callOptions">Call options specifying RPC behavior.</param>
/// <inheritdoc />
public async IAsyncEnumerable<DeployEvent> WatchDeployEventsAsync(
WatchDeployEventsRequest request,
CallOptions callOptions)
@@ -11,14 +11,10 @@ internal sealed class FakeGatewayTransport(MxGatewayClientOptions options) : IMx
private readonly Queue<MxCommandReply> _invokeReplies = new();
private readonly List<MxEvent> _events = [];
/// <summary>
/// Gets the gateway client options.
/// </summary>
/// <inheritdoc />
public MxGatewayClientOptions Options { get; } = options;
/// <summary>
/// Gets null, since this is a test fake without a real gRPC client.
/// </summary>
/// <inheritdoc />
public MxAccessGateway.MxAccessGatewayClient? RawClient => null;
/// <summary>
@@ -102,11 +98,7 @@ internal sealed class FakeGatewayTransport(MxGatewayClientOptions options) : IMx
/// </summary>
public Queue<Exception> InvokeExceptions { get; } = new();
/// <summary>
/// Verifies that the OpenSessionAsync call is recorded and returns the configured reply.
/// </summary>
/// <param name="request">The OpenSessionRequest to process.</param>
/// <param name="callOptions">Call options specifying RPC behavior.</param>
/// <inheritdoc />
public Task<OpenSessionReply> OpenSessionAsync(
OpenSessionRequest request,
CallOptions callOptions)
@@ -120,11 +112,7 @@ internal sealed class FakeGatewayTransport(MxGatewayClientOptions options) : IMx
return Task.FromResult(OpenSessionReply);
}
/// <summary>
/// Verifies that the CloseSessionAsync call is recorded and returns the configured reply.
/// </summary>
/// <param name="request">The CloseSessionRequest to process.</param>
/// <param name="callOptions">Call options specifying RPC behavior.</param>
/// <inheritdoc />
public Task<CloseSessionReply> CloseSessionAsync(
CloseSessionRequest request,
CallOptions callOptions)
@@ -138,11 +126,7 @@ internal sealed class FakeGatewayTransport(MxGatewayClientOptions options) : IMx
return Task.FromResult(CloseSessionReply);
}
/// <summary>
/// Verifies that the InvokeAsync call is recorded and returns the next enqueued reply.
/// </summary>
/// <param name="request">The MxCommandRequest to process.</param>
/// <param name="callOptions">Call options specifying RPC behavior.</param>
/// <inheritdoc />
public Task<MxCommandReply> InvokeAsync(
MxCommandRequest request,
CallOptions callOptions)
@@ -156,11 +140,7 @@ internal sealed class FakeGatewayTransport(MxGatewayClientOptions options) : IMx
return Task.FromResult(_invokeReplies.Dequeue());
}
/// <summary>
/// Verifies that the StreamEventsAsync call is recorded and yields all enqueued events.
/// </summary>
/// <param name="request">The StreamEventsRequest to process.</param>
/// <param name="callOptions">Call options specifying RPC behavior.</param>
/// <inheritdoc />
public async IAsyncEnumerable<MxEvent> StreamEventsAsync(
StreamEventsRequest request,
CallOptions callOptions)
@@ -193,11 +173,7 @@ internal sealed class FakeGatewayTransport(MxGatewayClientOptions options) : IMx
_events.Add(gatewayEvent);
}
/// <summary>
/// Records the acknowledge call and returns the next enqueued reply (or default).
/// </summary>
/// <param name="request">The acknowledge alarm request.</param>
/// <param name="callOptions">Call options specifying RPC behavior.</param>
/// <inheritdoc />
public Task<AcknowledgeAlarmReply> AcknowledgeAlarmAsync(
AcknowledgeAlarmRequest request,
CallOptions callOptions)
@@ -218,11 +194,7 @@ internal sealed class FakeGatewayTransport(MxGatewayClientOptions options) : IMx
});
}
/// <summary>
/// Records the query call and yields each enqueued snapshot.
/// </summary>
/// <param name="request">The query active alarms request.</param>
/// <param name="callOptions">Call options specifying RPC behavior.</param>
/// <inheritdoc />
public async IAsyncEnumerable<ActiveAlarmSnapshot> QueryActiveAlarmsAsync(
QueryActiveAlarmsRequest request,
CallOptions callOptions)
@@ -251,11 +223,7 @@ internal sealed class FakeGatewayTransport(MxGatewayClientOptions options) : IMx
_activeAlarmSnapshots.Add(snapshot);
}
/// <summary>
/// Records the stream-alarms call and yields each enqueued feed message.
/// </summary>
/// <param name="request">The stream alarms request.</param>
/// <param name="callOptions">Call options specifying RPC behavior.</param>
/// <inheritdoc />
public async IAsyncEnumerable<AlarmFeedMessage> StreamAlarmsAsync(
StreamAlarmsRequest request,
CallOptions callOptions)
@@ -9,6 +9,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that TestConnectionAsync attaches the API key in request metadata and returns the Ok flag.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task TestConnectionAsync_AttachesApiKeyMetadataAndReturnsOkFlag()
{
@@ -27,6 +28,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that TestConnectionAsync returns false when the server reports NotOk.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task TestConnectionAsync_ReturnsFalseWhenServerReportsNotOk()
{
@@ -42,6 +44,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that GetLastDeployTimeAsync returns null when the server reports not present.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task GetLastDeployTimeAsync_ReturnsNullWhenNotPresent()
{
@@ -58,6 +61,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that GetLastDeployTimeAsync returns the timestamp when the server reports it present.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task GetLastDeployTimeAsync_ReturnsTimestampWhenPresent()
{
@@ -79,6 +83,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that DiscoverHierarchyAsync returns the objects from the server reply.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task DiscoverHierarchyAsync_ReturnsObjectsFromReply()
{
@@ -141,6 +146,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that DiscoverHierarchyAsync propagates cancellation tokens to the transport.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task DiscoverHierarchyAsync_PropagatesCancellationToTransport()
{
@@ -161,6 +167,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that TestConnectionAsync retries on transient gRPC failures.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task DiscoverHierarchyAsync_WithRepeatedPageToken_ThrowsProtocolError()
{
@@ -184,6 +191,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that DiscoverHierarchyAsync maps typed filter options correctly to the request.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task DiscoverHierarchyAsync_WithOptions_MapsTypedFilters()
{
@@ -218,6 +226,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that TestConnectionAsync retries on transient gRPC failures.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task TestConnectionAsync_RetriesOnTransientGrpcFailure()
{
@@ -235,6 +244,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that DiscoverHierarchyAsync retries on transient gRPC failures.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task DiscoverHierarchyAsync_RetriesOnTransientGrpcFailure()
{
@@ -251,6 +261,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that WatchDeployEventsAsync delivers the bootstrap event.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WatchDeployEventsAsync_DeliversBootstrapEvent()
{
@@ -287,6 +298,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that WatchDeployEventsAsync delivers multiple events in order.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WatchDeployEventsAsync_DeliversMultipleEventsInOrder()
{
@@ -325,6 +337,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that WatchDeployEventsAsync stops iteration cleanly when cancelled.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WatchDeployEventsAsync_CancellationStopsIterationCleanly()
{
@@ -369,6 +382,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that WatchDeployEventsAsync throws ObjectDisposedException after the client is disposed.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WatchDeployEventsAsync_ThrowsAfterDisposal()
{
@@ -384,6 +398,7 @@ public sealed class GalaxyRepositoryClientTests
/// <summary>
/// Verifies that TestConnectionAsync throws ObjectDisposedException after the client is disposed.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task TestConnectionAsync_ThrowsAfterDisposal()
{
@@ -12,6 +12,7 @@ public sealed class LazyBrowseNodeTests
/// Verifies that calling BrowseAsync with no parent returns the root nodes
/// from the first BrowseChildren reply and surfaces the per-child has-children hint.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Browse_NoParent_ReturnsRoots()
{
@@ -36,6 +37,7 @@ public sealed class LazyBrowseNodeTests
/// <summary>
/// Verifies that ExpandAsync populates Children and marks the node expanded after one RPC.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Expand_PopulatesChildrenAndMarksExpanded()
{
@@ -62,6 +64,7 @@ public sealed class LazyBrowseNodeTests
/// <summary>
/// Verifies that a second ExpandAsync call is a no-op and issues no additional RPC.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Expand_CalledTwice_NoSecondRpc()
{
@@ -86,6 +89,7 @@ public sealed class LazyBrowseNodeTests
/// <summary>
/// Verifies that an RPC failure (NotFound) during expand is wrapped in MxGatewayException.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Expand_UnknownParent_ThrowsMxGatewayException()
{
@@ -113,6 +117,7 @@ public sealed class LazyBrowseNodeTests
/// <summary>
/// Verifies that ExpandAsync drains multi-page sibling replies and forwards the page token.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Expand_MultiPageSiblings_GathersAllPages()
{
@@ -147,6 +152,7 @@ public sealed class LazyBrowseNodeTests
/// <summary>
/// Verifies that ten concurrent ExpandAsync calls issue exactly one RPC, not ten.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Expand_CalledConcurrently_OnlyFiresOneRpc()
{
@@ -179,8 +185,9 @@ public sealed class LazyBrowseNodeTests
/// Verifies that reading Children/IsExpanded concurrently with an in-flight ExpandAsync
/// never throws (no torn enumeration of a mid-append list) and, once IsExpanded flips to
/// true, the published Children snapshot is fully populated. Pins the safe-publication
/// contract on the lock-free readers (Client.Dotnet-025).
/// contract on the lock-free readers.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Expand_ConcurrentReadOfChildren_NeverTearsAndPublishesAtomically()
{
@@ -268,6 +275,7 @@ public sealed class LazyBrowseNodeTests
/// <summary>
/// Verifies that BrowseChildrenOptions filter fields are forwarded to the BrowseChildren request.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Browse_WithFilter_ForwardsToRequest()
{
@@ -12,6 +12,7 @@ namespace ZB.MOM.WW.MxGateway.Client.Tests;
public sealed class MxGatewayClientAlarmsTests
{
/// <summary>AcknowledgeAlarmAsync records request and returns reply.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task AcknowledgeAlarmAsync_RecordsRequestShapeAndReturnsReply()
{
@@ -48,6 +49,7 @@ public sealed class MxGatewayClientAlarmsTests
}
/// <summary>AcknowledgeAlarmAsync honors cancellation.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task AcknowledgeAlarmAsync_HonorsCancellation()
{
@@ -72,6 +74,7 @@ public sealed class MxGatewayClientAlarmsTests
}
/// <summary>AcknowledgeAlarmAsync maps unauthenticated RPC exception to typed exception.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task AcknowledgeAlarmAsync_MapsUnauthenticated_RpcException_ToTypedException()
{
@@ -97,6 +100,7 @@ public sealed class MxGatewayClientAlarmsTests
}
/// <summary>QueryActiveAlarmsAsync streams enqueued snapshots.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task QueryActiveAlarmsAsync_StreamsEnqueuedSnapshots()
{
@@ -122,6 +126,7 @@ public sealed class MxGatewayClientAlarmsTests
}
/// <summary>QueryActiveAlarmsAsync passes filter prefix.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task QueryActiveAlarmsAsync_PassesFilterPrefix()
{
@@ -142,6 +147,7 @@ public sealed class MxGatewayClientAlarmsTests
}
/// <summary>QueryActiveAlarmsAsync honors cancellation during enumeration.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task QueryActiveAlarmsAsync_HonorsCancellationDuringEnumeration()
{
@@ -24,6 +24,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>Verifies that the version command with --json flag prints JSON protocol versions.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_VersionJson_PrintsJsonProtocolVersions()
{
@@ -38,6 +39,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>Verifies that the write command builds a write request and prints JSON reply.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_Write_BuildsWriteCommandAndPrintsJsonReply()
{
@@ -83,7 +85,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>
/// Client.Dotnet-030: <c>advise-supervisory</c> was present in the command
/// <c>advise-supervisory</c> was present in the command
/// dispatch table but absent from <see cref="MxGatewayClientCli"/>'s
/// <c>IsKnownGatewayCommand</c> guard, so the guard intercepted it first and
/// returned exit code 2 "Unknown command" before dispatch could run. This
@@ -91,6 +93,7 @@ public sealed class MxGatewayClientCliTests
/// "Unknown command") and reaches the dispatch handler (exit 0, reply written
/// to stdout).
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_AdviseSupervisory_IsRecognizedAndReachesDispatch()
{
@@ -130,6 +133,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>Verifies that error output redacts sensitive API key values.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_ErrorOutput_RedactsApiKey()
{
@@ -154,12 +158,13 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>
/// Client.Dotnet-028: when the API key is sourced from the env var
/// When the API key is sourced from the env var
/// (<c>--api-key-env</c> path, no <c>--api-key</c> flag), the error-redaction
/// catch block must still resolve and redact the effective key. Regression
/// guard for the catch block reverting to <c>GetOptional("api-key")</c> only,
/// which is null on the env-var path and leaves the key unredacted.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_ErrorOutput_RedactsApiKey_WhenSourcedFromEnvironmentVariable()
{
@@ -196,6 +201,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>Verifies that stream-events with max-events limit stops output in non-JSON format.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_StreamEvents_WithMaxEventsStopsNonJsonOutput()
{
@@ -238,6 +244,7 @@ public sealed class MxGatewayClientCliTests
/// <summary>Verifies that stream-alarms with --max-events stops output and distinguishes payload cases.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_StreamAlarms_WithMaxEventsStopsAndDistinguishesPayloadCases()
{
@@ -277,6 +284,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>Verifies that acknowledge-alarm builds a request and prints the JSON reply.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_AcknowledgeAlarm_BuildsRequestAndPrintsJsonReply()
{
@@ -319,6 +327,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>Verifies that smoke command closes opened session when a command fails.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_Smoke_WhenCommandFails_ClosesOpenedSession()
{
@@ -350,6 +359,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>Verifies that galaxy-test-connection command prints JSON reply.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_GalaxyTestConnection_PrintsJsonReply()
{
@@ -380,6 +390,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>Verifies that galaxy-discover command prints hierarchy summary.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_GalaxyDiscover_PrintsHierarchySummary()
{
@@ -453,6 +464,7 @@ public sealed class MxGatewayClientCliTests
/// Verifies galaxy-browse walks root objects and eagerly expands one further
/// level when --depth 1 is passed, printing an indented tree.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_GalaxyBrowse_TextTreeExpandsToDepth()
{
@@ -509,6 +521,7 @@ public sealed class MxGatewayClientCliTests
/// Verifies galaxy-browse --json emits a nested JSON document and forwards
/// the filter flags onto the BrowseChildren request.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_GalaxyBrowse_JsonForwardsFilters()
{
@@ -553,6 +566,7 @@ public sealed class MxGatewayClientCliTests
/// Verifies galaxy-browse --parent fetches exactly one level of children for
/// the supplied gobject id via a parent-scoped BrowseChildren request.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_GalaxyBrowse_ParentFetchesSingleLevel()
{
@@ -590,6 +604,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>Verifies that galaxy-watch command prints text output for deploy events.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_GalaxyWatch_PrintsTextOutputForEvents()
{
@@ -644,6 +659,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>Verifies that galaxy-watch with --json emits one JSON object per event.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_GalaxyWatch_JsonEmitsOneObjectPerEvent()
{
@@ -679,6 +695,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>Verifies that batch mode dispatches a single version command and emits the EOR sentinel.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_Batch_DispatchesVersionAndWritesEndOfRecord()
{
@@ -705,6 +722,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>Verifies that batch mode routes per-command errors to stdout as JSON between EOR markers.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_Batch_WritesErrorsToStdoutAsJson()
{
@@ -739,7 +757,7 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>
/// Client.Dotnet-018: the README CLI examples for the alarm subcommands at
/// The README CLI examples for the alarm subcommands at
/// `clients/dotnet/README.md` must drive cleanly through the production
/// CLI argument parser. The previous text used non-existent flags
/// (`--session-id`, `--max-messages`, `--alarm-reference`) that would
@@ -749,6 +767,7 @@ public sealed class MxGatewayClientCliTests
/// against exit code 0.
/// </summary>
/// <param name="command">The alarm subcommand to validate (e.g. "stream-alarms", "acknowledge-alarm").</param>
/// <returns>A task that represents the asynchronous operation.</returns>
[Theory]
[InlineData("stream-alarms")]
[InlineData("acknowledge-alarm")]
@@ -797,12 +816,13 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>
/// Client.Dotnet-019: `BenchReadBulkAsync` previously fell back to
/// `BenchReadBulkAsync` previously fell back to
/// <c>reply.ReturnValue.Int32Value</c> when the register reply had no
/// typed <c>Register</c> payload, silently driving the rest of the bench
/// against a zero server handle. The fix must fail loudly with a
/// descriptive <see cref="MxGatewayException"/>.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_BenchReadBulk_WhenRegisterReplyMissingTypedPayload_FailsLoudly()
{
@@ -810,9 +830,6 @@ public sealed class MxGatewayClientCliTests
using var error = new StringWriter();
FakeCliClient fakeClient = new();
// Successful protocol + MX status but no typed `Register` payload.
// Before the Client.Dotnet-019 fix this silently became serverHandle=0
// and the bench proceeded through SubscribeBulk / warmup / steady-state
// against an invalid handle, producing a misleading zero-result summary.
fakeClient.InvokeReplies.Enqueue(new MxCommandReply
{
SessionId = "session-fixture",
@@ -847,12 +864,13 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>
/// Client.Dotnet-020: the steady-state loop in `BenchReadBulkAsync` had a
/// The steady-state loop in `BenchReadBulkAsync` had a
/// bare `catch { failedCalls++; continue; }` that swallowed
/// <see cref="OperationCanceledException"/>, so token-driven cancellation
/// kept spinning until <c>--duration-seconds</c> elapsed. After the fix
/// the bench must exit promptly when the supplied token cancels.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RunAsync_BenchReadBulk_WhenSteadyStateLoopReceivesCancellation_ExitsPromptly()
{
@@ -941,12 +959,13 @@ public sealed class MxGatewayClientCliTests
}
/// <summary>
/// Client.Dotnet-021: both `ReadBulkAsync` and `BenchReadBulkAsync` cast
/// Both `ReadBulkAsync` and `BenchReadBulkAsync` cast
/// the user-supplied <c>--timeout-ms</c> to <see cref="uint"/> without
/// bounds checking, so a negative value (e.g. <c>-1</c>) silently wraps
/// to ~49.7 days. The fix must reject negatives with a clear error.
/// </summary>
/// <param name="command">The bulk-read subcommand to validate (e.g. "read-bulk", "bench-read-bulk").</param>
/// <returns>A task that represents the asynchronous operation.</returns>
[Theory]
[InlineData("read-bulk")]
[InlineData("bench-read-bulk")]
@@ -1109,7 +1128,8 @@ public sealed class MxGatewayClientCliTests
/// <summary>Optional per-call handler that overrides queue-based behaviour.</summary>
public Func<MxCommandRequest, CancellationToken, Task<MxCommandReply>>? InvokeHandler { get; init; }
/// <inheritdoc />
/// <summary>Disposes the fake client. No-op; there are no unmanaged resources to release.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
public ValueTask DisposeAsync()
{
return ValueTask.CompletedTask;
@@ -7,6 +7,7 @@ namespace ZB.MOM.WW.MxGateway.Client.Tests;
public sealed class MxGatewayClientSessionTests
{
/// <summary>Verifies that open session attaches API key metadata and cancellation token.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task OpenSessionRawAsync_AttachesApiKeyMetadataAndCancellation()
{
@@ -22,6 +23,7 @@ public sealed class MxGatewayClientSessionTests
}
/// <summary>Verifies that open session returns a session with the raw open reply.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task OpenSessionAsync_ReturnsSessionWithRawOpenReply()
{
@@ -37,6 +39,7 @@ public sealed class MxGatewayClientSessionTests
}
/// <summary>Verifies that register builds a register command and returns server handle.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task RegisterAsync_BuildsRegisterCommandAndReturnsServerHandle()
{
@@ -62,6 +65,7 @@ public sealed class MxGatewayClientSessionTests
}
/// <summary>Verifies that add item 2 builds a command with the specified context.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task AddItem2Async_BuildsAddItem2CommandWithContext()
{
@@ -87,6 +91,7 @@ public sealed class MxGatewayClientSessionTests
}
/// <summary>Verifies that write raw builds a write command with the raw value.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteRawAsync_BuildsWriteCommandWithRawValue()
{
@@ -118,6 +123,7 @@ public sealed class MxGatewayClientSessionTests
}
/// <summary>Verifies that write 2 raw builds a write 2 command with value and timestamp.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Write2RawAsync_BuildsWrite2CommandWithValueAndTimestamp()
{
@@ -146,6 +152,7 @@ public sealed class MxGatewayClientSessionTests
}
/// <summary>Verifies that subscribe bulk builds one command and returns per-item results.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task SubscribeBulkAsync_BuildsOneBulkCommandAndReturnsPerItemResults()
{
@@ -185,6 +192,7 @@ public sealed class MxGatewayClientSessionTests
}
/// <summary>Verifies that stream events yields events in the order received from the gateway.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task StreamEventsAsync_YieldsEventsInGatewayOrder()
{
@@ -216,6 +224,7 @@ public sealed class MxGatewayClientSessionTests
}
/// <summary>Verifies that close is explicit and idempotent.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task CloseAsync_IsExplicitAndIdempotent()
{
@@ -232,6 +241,7 @@ public sealed class MxGatewayClientSessionTests
}
/// <summary>Verifies that invoke retries safe diagnostic commands on transient RPC failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task InvokeAsync_RetriesSafeDiagnosticCommandOnTransientGrpcFailure()
{
@@ -256,6 +266,7 @@ public sealed class MxGatewayClientSessionTests
}
/// <summary>Verifies that open session does not retry on transient RPC failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task OpenSessionAsync_DoesNotRetryTransientGrpcFailure()
{
@@ -269,6 +280,7 @@ public sealed class MxGatewayClientSessionTests
}
/// <summary>Verifies that invoke does not retry write commands on transient RPC failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task InvokeAsync_DoesNotRetryWriteCommand()
{
@@ -284,6 +296,7 @@ public sealed class MxGatewayClientSessionTests
}
/// <summary>Verifies that invoke helpers pass cancellation token to the transport.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task InvokeHelpers_PassCancellationTokenToTransport()
{
@@ -330,6 +343,7 @@ public sealed class MxGatewayClientSessionTests
}
/// <summary>Verifies that WriteArrayElementsAsync builds a write command whose value is a SparseArrayValue.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteArrayElementsAsync_BuildsWriteCommandWithSparseArrayValue()
{
@@ -3,6 +3,7 @@ namespace ZB.MOM.WW.MxGateway.Client.Tests;
public sealed class MxGatewayGeneratedContractTests
{
/// <summary>Verifies that the generated gRPC client can be instantiated from the client factory.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task GeneratedGrpcClient_CanBeConstructedFromClientFactory()
{