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:
Joseph Doherty
2026-07-07 14:09:49 -04:00
parent 8914472706
commit fca978de07
203 changed files with 1834 additions and 1383 deletions
@@ -15,6 +15,7 @@ namespace ZB.MOM.WW.MxGateway.IntegrationTests;
public sealed class DashboardLdapLiveTests
{
/// <summary>Verifies that an admin user in the GwAdmin group authenticates successfully.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveLdapFact]
public async Task AuthenticateAsync_AdminInGwAdminGroup_Succeeds()
{
@@ -32,17 +33,13 @@ public sealed class DashboardLdapLiveTests
claim.Type == DashboardAuthenticationDefaults.LdapGroupClaimType
&& claim.Value.Contains("GwAdmin", StringComparison.OrdinalIgnoreCase));
// IntegrationTests-023: DashboardAuthenticator builds the principal with a
// ClaimTypes.Role claim resolved from the LDAP groups via the
// DashboardGroupRoleMapper. The seeded GroupToRole map (GwAdmin -> Admin)
// means the admin principal must carry Role=Admin alongside the raw LDAP-group
// claim. A regression in the group→role mapping would fail this assertion.
Assert.Contains(result.Principal.Claims, claim =>
claim.Type == ClaimTypes.Role
&& claim.Value == DashboardRoles.Admin);
}
/// <summary>Verifies that a readonly user without GwAdmin group fails to authenticate.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveLdapFact]
public async Task AuthenticateAsync_ReadOnlyUserMissingGwAdminGroup_Fails()
{
@@ -59,6 +56,7 @@ public sealed class DashboardLdapLiveTests
}
/// <summary>Verifies that authentication with wrong password fails without leaking the password.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveLdapFact]
public async Task AuthenticateAsync_AdminWithWrongPassword_FailsWithoutLeakingPassword()
{
@@ -78,6 +76,7 @@ public sealed class DashboardLdapLiveTests
}
/// <summary>Verifies that authentication with unknown username fails.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveLdapFact]
public async Task AuthenticateAsync_UnknownUsername_Fails()
{
@@ -95,6 +94,7 @@ public sealed class DashboardLdapLiveTests
}
/// <summary>Verifies that authentication fails gracefully when the server is unreachable.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveLdapFact]
public async Task AuthenticateAsync_ServerUnreachable_FailsWithoutThrowing()
{
@@ -141,7 +141,7 @@ public sealed class DashboardLdapLiveTests
/// Builds the shared library <see cref="LibraryLdapOptions"/> by binding the real
/// <c>MxGateway:Ldap</c> configuration section the same way production does in
/// <c>AddZbLdapAuth(configuration, "MxGateway:Ldap")</c>, rather than hand-copying the
/// gateway shadow <c>LdapOptions</c> defaults field by field (IntegrationTests-028).
/// gateway shadow <c>LdapOptions</c> defaults field by field.
/// Binding the section directly onto the shared type means the live tests exercise the
/// exact option-binding path production uses, pick up every shared field (including
/// <see cref="LibraryLdapOptions.ConnectionTimeoutMs"/>, which governs the
@@ -7,6 +7,7 @@ namespace ZB.MOM.WW.MxGateway.IntegrationTests.Galaxy;
public sealed class GalaxyRepositoryLiveTests
{
/// <summary>Verifies that the Galaxy Repository can establish a live connection to the ZB database.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveGalaxyRepositoryFact]
public async Task TestConnection_AgainstZb_Succeeds()
{
@@ -18,6 +19,7 @@ public sealed class GalaxyRepositoryLiveTests
}
/// <summary>Verifies that the last deploy time can be retrieved from the ZB database.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveGalaxyRepositoryFact]
public async Task GetLastDeployTime_AgainstZb_ReturnsTimestamp()
{
@@ -29,6 +31,7 @@ public sealed class GalaxyRepositoryLiveTests
}
/// <summary>Verifies that the hierarchy can be retrieved from the ZB database.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveGalaxyRepositoryFact]
public async Task GetHierarchy_AgainstZb_ReturnsObjects()
{
@@ -46,6 +49,7 @@ public sealed class GalaxyRepositoryLiveTests
}
/// <summary>Verifies that object attributes can be retrieved from the ZB database.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveGalaxyRepositoryFact]
public async Task GetAttributes_AgainstZb_ReturnsAtLeastOneAttribute()
{
@@ -7,8 +7,7 @@ public static class IntegrationTestEnvironment
/// <summary>
/// Sourced from <see cref="GatewayContractInfo.LiveMxAccessOptInVariableName"/>
/// so the env-var literal is shared with
/// <c>ZB.MOM.WW.MxGateway.Worker.Tests.TestSupport.LiveMxAccessFactAttribute</c>
/// (Worker.Tests-025).
/// <c>ZB.MOM.WW.MxGateway.Worker.Tests.TestSupport.LiveMxAccessFactAttribute</c>.
/// </summary>
public const string LiveMxAccessVariableName = GatewayContractInfo.LiveMxAccessOptInVariableName;
public const string LiveMxAccessWorkerExecutableVariableName = "MXGATEWAY_LIVE_MXACCESS_WORKER_EXE";
@@ -104,7 +103,7 @@ public static class IntegrationTestEnvironment
/// when no root is found so a misconfigured run fails fast with an actionable
/// message rather than silently falling back to the current working directory
/// (which previously produced a misleading "worker exe not found" pointing at
/// a fabricated path — see IntegrationTests-022). The
/// a fabricated path). The
/// <see cref="LiveMxAccessWorkerExecutableVariableName"/> environment variable
/// remains the escape hatch for unusual deployments.
/// </summary>
@@ -115,7 +114,7 @@ public static class IntegrationTestEnvironment
/// ancestors above it. Tests pass an isolated boundary so the walker cannot
/// leak into ambient ancestors (a redirected <c>TMP</c>, a co-located checkout
/// at <c>C:\src</c>, an enclosing CI workspace, etc.) that would silently
/// satisfy <see cref="IsRepositoryRoot"/> — see IntegrationTests-025.
/// satisfy <see cref="IsRepositoryRoot"/>.
/// Production callers pass <see langword="null"/> so the walk continues to the
/// drive root as before.
/// </param>
@@ -34,7 +34,7 @@ public sealed class IntegrationTestEnvironmentTests
File.WriteAllText(Path.Combine(temporaryRoot, ".git"), "gitdir: ../.git/worktrees/test");
// Pass temporaryRoot as the stop-boundary so the walker can never leak
// into ambient ancestors of Path.GetTempPath() (IntegrationTests-025).
// into ambient ancestors of Path.GetTempPath().
string repositoryRoot = IntegrationTestEnvironment.ResolveRepositoryRoot(
nestedDirectory,
stopBoundary: temporaryRoot);
@@ -54,13 +54,13 @@ public sealed class IntegrationTestEnvironmentTests
/// Verifies that <see cref="IntegrationTestEnvironment.ResolveRepositoryRoot"/>
/// throws <see cref="InvalidOperationException"/> with a diagnostic message when
/// the walk exhausts without finding a repository root. The previous silent
/// fallback to <c>Directory.GetCurrentDirectory()</c> masked misconfiguration
/// (IntegrationTests-022); operators get a clear, actionable failure instead.
/// fallback to <c>Directory.GetCurrentDirectory()</c> masked misconfiguration;
/// operators get a clear, actionable failure instead.
/// The <c>stopBoundary</c> isolates the walker from ambient ancestors of
/// <see cref="Path.GetTempPath"/> (a redirected <c>TMP</c>, a co-located checkout
/// at <c>C:\src</c>, etc.) that could otherwise satisfy
/// <c>IsRepositoryRoot</c> and make this assertion flake on contributor or CI
/// boxes — see IntegrationTests-025.
/// boxes.
/// </summary>
[Fact]
public void ResolveRepositoryRoot_NoMarkers_ThrowsInvalidOperationExceptionNamingStartAndMarkers()
@@ -97,9 +97,8 @@ public sealed class IntegrationTestEnvironmentTests
/// <summary>
/// Verifies the <c>stopBoundary</c> parameter on
/// <see cref="IntegrationTestEnvironment.ResolveRepositoryRoot"/> isolates the
/// walker from ambient ancestors that happen to satisfy <c>IsRepositoryRoot</c>
/// — the precise failure mode IntegrationTests-025 describes. The test
/// deliberately constructs an outer directory that *does* carry repository-root
/// walker from ambient ancestors that happen to satisfy <c>IsRepositoryRoot</c>.
/// The test deliberately constructs an outer directory that *does* carry repository-root
/// markers (<c>src/</c> + <c>.git</c>) and an inner isolated chain that does
/// not. Without the boundary the walker would happily stop at the outer
/// directory; with the boundary it must throw because the chain it can see
@@ -11,7 +11,7 @@ namespace ZB.MOM.WW.MxGateway.IntegrationTests.TestSupport;
/// The unit-test project owns a parallel copy under
/// <c>ZB.MOM.WW.MxGateway.Tests/TestSupport/</c>; IntegrationTests keeps its
/// own copy here so the two test projects stay independently buildable
/// without a shared test-helpers project (IntegrationTests-024).
/// without a shared test-helpers project.
/// </summary>
public sealed class NullDashboardEventBroadcaster : IDashboardEventBroadcaster
{
@@ -30,6 +30,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// <summary>
/// Verifies that a gateway session can register, add item, advise, and stream events from live MXAccess.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveMxAccessFact]
public async Task GatewaySession_WithLiveWorker_RegistersAdvisesStreamsDataAndCloses()
{
@@ -119,6 +120,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// and that the worker emits a matching <see cref="MxEventFamily.OnWriteComplete"/> event
/// — the proof of round-trip the cross-language client e2e runner relies on.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveMxAccessFact]
public async Task GatewaySession_WithLiveWorker_WritesValueToAdvisedItem()
{
@@ -235,6 +237,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// Verifies that an AddItem against an invalid server handle surfaces the MXAccess failure
/// without faulting the gateway transport, exercising the invalid-handle parity path.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveMxAccessFact]
public async Task GatewaySession_WithLiveWorker_InvalidHandleCommand_SurfacesFailureWithoutTransportFault()
{
@@ -293,6 +296,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// OnDataChange events for the un-advised item. Exercises the lifecycle-ordering
/// parity CLAUDE.md singles out as a "do not synthesize" rule.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveMxAccessFact]
public async Task GatewaySession_WithLiveWorker_UnadviseRemoveItemUnregister_TeardownOrderingParity()
{
@@ -391,7 +395,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
// only constrains events generated AFTER the teardown returned. So the
// "before" baseline is taken *after* a first settle window drains those
// in-flight events, not before UnAdvise was issued (which races against
// the round-trip + STA dispatch + pipe send window — see IntegrationTests-017).
// the round-trip + STA dispatch + pipe send window).
//
// RecordingServerStreamWriter.Messages returns a snapshot copy under its
// own lock, so iterating after each settle window is safe without external
@@ -437,6 +441,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// parity surface the gateway must not "fix" — the test asserts the reply kind and
/// protocol status, not a fabricated outcome.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveMxAccessFact]
public async Task GatewaySession_WithLiveWorker_WriteSecured_AuthenticatedRoundTripParity()
{
@@ -445,7 +450,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
File.Exists(workerExecutablePath),
$"Live MXAccess worker executable was not found at {workerExecutablePath}. Build the worker or set {IntegrationTestEnvironment.LiveMxAccessWorkerExecutableVariableName}.");
// IntegrationTests-019: CLAUDE.md's credential-redaction rule covers every log
// CLAUDE.md's credential-redaction rule covers every log
// surface the test sees, not just the reply's DiagnosticMessage. Wire a buffering
// wrapper around output and route the worker stdout/stderr echo and the gateway
// ILogger sink through it so the post-run assertion covers the accumulated test
@@ -573,6 +578,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// assert the reply kind plus a non-INVALID_REQUEST protocol status, and log the
/// HResult for the record.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveMxAccessFact]
public async Task GatewaySession_WithLiveWorker_NewComCommands_RoundTripWithRealReplies()
{
@@ -726,6 +732,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// to be non-empty and internally consistent (no crash, no dropped payload).
/// </para>
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveMxAccessFact]
public async Task GatewaySession_WithLiveWorker_BufferedItem_AddsSetsIntervalAndAttemptsCapture()
{
@@ -908,6 +915,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// must observe the abnormal exit, transition the session, and surface a non-empty
/// fault description rather than hanging or crashing.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[LiveMxAccessFact]
public async Task GatewaySession_WithLiveWorker_AbnormalWorkerExit_MarksSessionFaulted()
{
@@ -981,7 +989,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
// message (they all begin with "Worker"); tighten to the pipe/disconnect/
// end-of-stream classifications that match THIS path, so a regression that
// routed an unrelated fault here would surface as a test failure rather
// than silently passing (see IntegrationTests-020). "heartbeat" is dropped
// than silently passing. "heartbeat" is dropped
// because HeartbeatGraceSeconds (15s) exceeds the StreamShutdownTimeout
// (10s) poll window, so a heartbeat-expired transition can never be
// observed inside this test.
@@ -991,7 +999,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
$"Fault description '{observedFault}' did not match a known abnormal-exit classification "
+ "(expected 'pipe disconnected' or 'end of stream' from WorkerClient's EndOfStream path).");
// IntegrationTests-021: also assert the StreamEvents call observed the fault
// Also assert the StreamEvents call observed the fault
// — the chain that puts the session into Faulted goes through ReadEventsAsync
// propagating a WorkerClientException into EventStreamService, which calls
// session.MarkFaulted. The gateway then maps the WorkerClientException to an
@@ -1037,7 +1045,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// test fails on a silent stream-task exception (the Write parity test relies on this so
/// stream-side defects in event delivery are visible). When <see langword="false"/>, all
/// cleanup exceptions are logged and swallowed so a real test-body assertion failure is not
/// masked by a shutdown timeout (the original IntegrationTests-004 fix).
/// masked by a shutdown timeout.
/// </param>
private async Task ShutDownAsync(
GatewayServiceFixture fixture,
@@ -1607,6 +1615,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// </summary>
/// <param name="sessionId">The session identifier.</param>
/// <param name="session">The session if found; otherwise null.</param>
/// <returns><see langword="true"/> if a session with the given id was found; otherwise <see langword="false"/>.</returns>
public bool TryGetSession(string sessionId, [MaybeNullWhen(false)] out GatewaySession session)
{
return _registry.TryGet(sessionId, out session);
@@ -1615,6 +1624,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// <summary>
/// Disposes the fixture resources and closes all sessions.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
public async ValueTask DisposeAsync()
{
foreach (GatewaySession session in _registry.Snapshot())
@@ -1685,6 +1695,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// Records the message and signals any pending waiter.
/// </summary>
/// <param name="message">The message to write.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public Task WriteAsync(T message)
{
lock (syncRoot)
@@ -1867,7 +1878,11 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
return workerProcess;
}
/// <inheritdoc />
/// <summary>
/// Waits for every recorded worker process to exit, up to the specified timeout per process.
/// </summary>
/// <param name="timeout">The maximum time to wait for each process.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public async Task WaitForProcessesAsync(TimeSpan timeout)
{
foreach (TestWorkerProcess process in processes)
@@ -1947,7 +1962,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
process.Kill(entireProcessTree);
}
/// <inheritdoc />
/// <summary>Disposes the wrapped process.</summary>
public void Dispose()
{
process.Dispose();
@@ -1959,13 +1974,15 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// </summary>
private sealed class TestOutputLoggerProvider(ITestOutputHelper output) : ILoggerProvider
{
/// <inheritdoc />
/// <summary>Creates a logger that writes to the test output helper for the given category.</summary>
/// <param name="categoryName">Category name for the logger.</param>
/// <returns>The created logger.</returns>
public ILogger CreateLogger(string categoryName)
{
return new TestOutputLogger(output, categoryName);
}
/// <inheritdoc />
/// <summary>No resources to release; provided to satisfy <see cref="ILoggerProvider"/>.</summary>
public void Dispose()
{
}
@@ -1978,20 +1995,31 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
ITestOutputHelper output,
string categoryName) : ILogger
{
/// <inheritdoc />
/// <summary>Not supported; this test logger does not track scopes.</summary>
/// <typeparam name="TState">The type of the state to begin the scope for.</typeparam>
/// <param name="state">The identifier for the scope.</param>
/// <returns>Always <see langword="null"/>.</returns>
public IDisposable? BeginScope<TState>(TState state)
where TState : notnull
{
return null;
}
/// <inheritdoc />
/// <summary>Determines whether the given log level is enabled.</summary>
/// <param name="logLevel">The log level to check.</param>
/// <returns><see langword="true"/> if <paramref name="logLevel"/> is at least <see cref="LogLevel.Information"/>; otherwise <see langword="false"/>.</returns>
public bool IsEnabled(LogLevel logLevel)
{
return logLevel >= LogLevel.Information;
}
/// <inheritdoc />
/// <summary>Writes the formatted log message and any exception to the test output helper.</summary>
/// <typeparam name="TState">The type of the object to be logged.</typeparam>
/// <param name="logLevel">The severity of the log entry.</param>
/// <param name="eventId">The event id associated with the log entry.</param>
/// <param name="state">The entry to be logged, which can be an object or a message string.</param>
/// <param name="exception">The exception related to this entry, if any.</param>
/// <param name="formatter">Function that creates the log message from <paramref name="state"/> and <paramref name="exception"/>.</param>
public void Log<TState>(
LogLevel logLevel,
EventId eventId,
@@ -2015,7 +2043,7 @@ public sealed class WorkerLiveMxAccessSmokeTests(ITestOutputHelper output)
/// <summary>
/// Buffering wrapper around an <see cref="ITestOutputHelper"/> that mirrors every line
/// written through it into a <see cref="StringBuilder"/> the test owns. The WriteSecured
/// parity test (IntegrationTests-019) uses this to make CLAUDE.md's "passwords and
/// parity test uses this to make CLAUDE.md's "passwords and
/// <c>WriteSecured</c> payloads must never reach logs" rule a property of the entire
/// test output stream — gateway <see cref="ILogger"/> entries (echoed via
/// <see cref="TestOutputLoggerProvider"/>), worker stdout/stderr (echoed via