docs(tests): fix CommentChecker findings across tests/ — 13,392 → 0 (repo-wide scan clean)

Comment/XML-doc changes only:
- add summaries to ~10k test methods, fixtures, fakes and helpers
  (+ <param> on theories, <returns> on async Task methods,
  <inheritdoc/> on interface implementations the checker can resolve)
- strip ~2.6k project-tracking references (WP*, P*-*, row-NN, Task N,
  #NN, Component-0NN) from comments, keeping the explanatory text;
  reword false positives in comments only
- real docs on fakes implementing BCL/library interfaces
  (IDisposable, ILogger, IOptionsMonitor, IAsyncLifetime)
- reword the last 5 src/ false positives (CWE-1236, failures-1,
  year-0001, M365)

Only non-comment edits: four one-line nested classes split across lines
so members can carry docs. Build 0 errors / 0 warnings.
This commit is contained in:
Joseph Doherty
2026-10-07 15:05:49 -04:00
parent 0ffd4bdbea
commit 513fa1aa16
998 changed files with 17896 additions and 2395 deletions
@@ -11,7 +11,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
namespace ZB.MOM.WW.ScadaBridge.AuditLog.Tests.Site;
/// <summary>
/// C4 (Task 2.5) hot-path + drain tests for <see cref="SqliteAuditWriter"/>'s
/// Hot-path + drain tests for <see cref="SqliteAuditWriter"/>'s
/// two-table site schema. Exercise the Channel-based enqueue, the background
/// writer's per-event canonical(<c>audit_event</c>) + sidecar
/// (<c>audit_forward_state</c>) INSERTs, duplicate-EventId swallowing, the
@@ -87,7 +87,7 @@ public class SqliteAuditWriterWriteTests
return byState;
}
// C4 (Task 2.5): build the canonical ZB.MOM.WW.Audit.AuditEvent via the shared
// Build the canonical ZB.MOM.WW.Audit.AuditEvent via the shared
// factory. The SQLite writer stores the 10 canonical fields directly in
// audit_event and writes a Pending sidecar row into audit_forward_state, with
// IsCachedKind precomputed from the event's Kind. Reads recompose the canonical
@@ -120,6 +120,8 @@ public class SqliteAuditWriterWriteTests
eventId: id ?? Guid.NewGuid(),
occurredAtUtc: occurredAtUtc ?? DateTime.UtcNow);
/// <summary>Verifies that a fresh event persists its canonical fields and a Pending sidecar row.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAsync_FreshEvent_PersistsCanonical_And_SidecarPending()
{
@@ -140,6 +142,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(AuditForwardState.Pending.ToString(), ReadForwardState(dataSource, evt.EventId));
}
/// <summary>Verifies that the canonical fields written for an event round-trip unchanged through a read.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAsync_Roundtrips_Canonical_Fields_Through_Read()
{
@@ -164,6 +168,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(evt.DetailsJson, row.DetailsJson);
}
/// <summary>Verifies that 1000 concurrent writes all persist without throwing.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAsync_Concurrent_1000Calls_All_Persist_NoExceptions()
{
@@ -186,16 +192,17 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(1000, Convert.ToInt64(sidecarCmd.ExecuteScalar()));
}
// ----- FlushIntervalMs soft-flush coalescing (arch-review remediation WP1.2) ----- //
// ----- FlushIntervalMs soft-flush coalescing (arch-review remediation) ----- //
/// <summary>
/// A trickle of events — well under <see cref="SqliteAuditWriterOptions.BatchSize"/>,
/// spaced closer together than <see cref="SqliteAuditWriterOptions.FlushIntervalMs"/> —
/// must coalesce into ONE transaction rather than fsyncing once per event. This is the
/// bug WP1.2 fixes: <c>FlushIntervalMs</c> was validated but never read by the writer
/// bug this fixes: <c>FlushIntervalMs</c> was validated but never read by the writer
/// loop, so every trickle-rate write incurred its own commit (and, under SQLite's
/// default synchronous=FULL, its own fsync).
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAsync_TrickleLoad_CoalescesIntoOneTransaction()
{
@@ -229,6 +236,7 @@ public class SqliteAuditWriterWriteTests
/// waiting for a partner — the deadline bounds worst-case added latency, it does
/// not turn into an unbounded debounce.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAsync_EventsSpacedBeyondFlushInterval_FlushSeparately()
{
@@ -249,6 +257,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(2, writer.FlushCountForTests);
}
/// <summary>Verifies that a duplicate event id is swallowed without an exception and the first write wins.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAsync_DuplicateEventId_FirstWriteWins_NoException()
{
@@ -281,13 +291,15 @@ public class SqliteAuditWriterWriteTests
Assert.Equal("first", targetCmd.ExecuteScalar() as string);
}
/// <summary>Verifies that a write always sets the sidecar forward state to Pending.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAsync_ForcesSidecarForwardStatePending()
{
var (writer, dataSource) = CreateWriter(nameof(WriteAsync_ForcesSidecarForwardStatePending));
await using var _ = writer;
// C4 (Task 2.5): ForwardState is not a field on the canonical record; a
// ForwardState is not a field on the canonical record; a
// fresh event's sidecar row defaults to Pending on INSERT.
var evt = NewEvent();
await writer.WriteAsync(evt);
@@ -297,6 +309,8 @@ public class SqliteAuditWriterWriteTests
// ----- IsCachedKind drain split (precomputed at insert) ----- //
/// <summary>Verifies that a cached audit kind sets the cached-kind flag to 1 and a non-cached kind sets it to 0.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAsync_CachedKind_SetsIsCachedKind_1_NonCached_0()
{
@@ -320,6 +334,9 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(0L, Convert.ToInt64(cmd.ExecuteScalar()));
}
/// <summary>Verifies that cached audit kinds drain through the cached-telemetry read and not the ordinary pending read.</summary>
/// <param name="kind">The cached audit kind under test.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
[Theory]
[InlineData(AuditKind.CachedSubmit)]
[InlineData(AuditKind.ApiCallCached)]
@@ -342,6 +359,8 @@ public class SqliteAuditWriterWriteTests
Assert.DoesNotContain(pendingRows, r => r.EventId == cached.EventId);
}
/// <summary>Verifies that a non-cached audit kind drains through the ordinary pending read and not the cached-telemetry read.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task NonCachedKind_DrainsVia_ReadPending_Not_ReadPendingCachedTelemetry()
{
@@ -358,6 +377,8 @@ public class SqliteAuditWriterWriteTests
Assert.DoesNotContain(cachedRows, r => r.EventId == nonCached.EventId);
}
/// <summary>Verifies that the pending read returns the oldest rows first, limited to the requested count.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReadPendingAsync_Returns_OldestFirst_LimitedToN()
{
@@ -387,6 +408,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(baseTime.AddSeconds(3), rows[2].OccurredAtUtc);
}
/// <summary>Verifies that marking events as forwarded flips their sidecar rows to Forwarded.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MarkForwardedAsync_FlipsSidecarRowsToForwarded()
{
@@ -406,6 +429,8 @@ public class SqliteAuditWriterWriteTests
Assert.False(byState.ContainsKey(AuditForwardState.Pending.ToString()));
}
/// <summary>Verifies that marking events as forwarded increments the attempt count and stamps the last-attempt time.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MarkForwardedAsync_BumpsAttemptCount_And_StampsLastAttemptUtc()
{
@@ -428,6 +453,8 @@ public class SqliteAuditWriterWriteTests
Assert.False(reader.IsDBNull(1)); // LastAttemptUtc stamped
}
/// <summary>Verifies that marking a non-existent event id as forwarded does not throw.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MarkForwardedAsync_NonExistentId_NoThrow()
{
@@ -440,6 +467,8 @@ public class SqliteAuditWriterWriteTests
// No assertion needed: the call must complete without throwing.
}
/// <summary>Verifies that the forwarded read returns only rows in the Forwarded state.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReadForwardedAsync_Returns_Only_Forwarded_Rows()
{
@@ -457,8 +486,10 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(forwarded.EventId, row.EventId);
}
// ----- M6 reconciliation pull surface ----- //
// ----- Reconciliation pull surface ----- //
/// <summary>Verifies that the since-read returns pending and forwarded rows oldest first, limited to the requested count.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReadPendingSinceAsync_Returns_PendingAndForwarded_OldestFirst_LimitedToN()
{
@@ -488,6 +519,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(baseTime.AddSeconds(3), rows[2].OccurredAtUtc);
}
/// <summary>Verifies that the since-read excludes rows older than the supplied cutoff.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReadPendingSinceAsync_ExcludesRowsOlderThanSinceUtc()
{
@@ -511,6 +544,8 @@ public class SqliteAuditWriterWriteTests
Assert.DoesNotContain(rows, r => r.EventId == old.EventId);
}
/// <summary>Verifies that the since-read excludes rows that are already reconciled.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReadPendingSinceAsync_ExcludesReconciledRows()
{
@@ -531,8 +566,10 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(pending.EventId, rows[0].EventId);
}
// ----- WP2.3: composite keyset cursor + cursor-proved retirement ----- //
// ----- Composite keyset cursor + cursor-proved retirement ----- //
/// <summary>Verifies that supplying an after-id skips rows at or before the composite timestamp-and-id cursor.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReadPendingSinceAsync_WithAfterId_SkipsRowsAtOrBeforeTheCompositeCursor()
{
@@ -567,6 +604,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(sameInstant.Select(e => e.EventId).ToHashSet(), allIds);
}
/// <summary>Verifies that reconciling up to a cursor with an id retires only rows at or before that cursor.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MarkReconciledUpToAsync_WithCursorId_RetiresOnlyRowsAtOrBeforeIt()
{
@@ -599,6 +638,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(3, remaining.Count); // the two un-consumed at the instant + newer
}
/// <summary>Verifies that reconciling up to a timestamp without a cursor id leaves rows at the boundary instant servable.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MarkReconciledUpToAsync_WithoutCursorId_LeavesTheBoundaryInstantServable()
{
@@ -626,6 +667,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(boundary.EventId, row.EventId);
}
/// <summary>Verifies that rows served without an advancing cursor remain servable so they are delivered at least once.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ServingRows_WithoutAnAdvancingCursor_KeepsThemServable_AtLeastOnce()
{
@@ -652,6 +695,8 @@ public class SqliteAuditWriterWriteTests
second.Select(r => r.EventId).ToHashSet());
}
/// <summary>Verifies that a late-stamped insert below the cursor is never retired by reconciling up to the cursor.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MarkReconciledUpToAsync_LateStampedInsertBelowTheCursor_IsNeverRetired()
{
@@ -695,6 +740,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(lateStamped.EventId, Assert.Single(reread).EventId);
}
/// <summary>Verifies that forwarded rows are retired by reconciling up to a cursor even if they were never pulled.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MarkReconciledUpToAsync_ForwardedRowsRetire_EvenWithoutHavingBeenPulled()
{
@@ -722,6 +769,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(AuditForwardState.Pending.ToString(), ReadForwardState(dataSource, neverShipped.EventId));
}
/// <summary>Verifies that reconciling before any pull retires no pending rows.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MarkReconciledUpToAsync_BeforeAnyPull_RetiresNothingPending()
{
@@ -745,6 +794,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(1, await writer.MarkReconciledUpToAsync(t0.AddHours(1), afterId: null));
}
/// <summary>Verifies that the since-read throws for an invalid batch size.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReadPendingSinceAsync_InvalidBatchSize_Throws()
{
@@ -757,6 +808,8 @@ public class SqliteAuditWriterWriteTests
() => writer.ReadPendingSinceAsync(DateTime.MinValue, batchSize: -3));
}
/// <summary>Verifies that marking events as reconciled flips both pending and forwarded rows to Reconciled.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MarkReconciledAsync_FlipsPendingAndForwarded_To_Reconciled()
{
@@ -781,6 +834,8 @@ public class SqliteAuditWriterWriteTests
Assert.False(byState.ContainsKey(AuditForwardState.Forwarded.ToString()));
}
/// <summary>Verifies that marking reconciled is idempotent and leaves already-reconciled rows untouched.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MarkReconciledAsync_Idempotent_LeavesAlreadyReconciledRowsUntouched()
{
@@ -796,6 +851,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(AuditForwardState.Reconciled.ToString(), ReadForwardState(dataSource, a.EventId));
}
/// <summary>Verifies that marking a non-existent event id as reconciled does not throw.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MarkReconciledAsync_NonExistentId_NoThrow()
{
@@ -807,7 +864,7 @@ public class SqliteAuditWriterWriteTests
}
/// <summary>
/// Fix 2 / M1 state guard: <see cref="SqliteAuditWriter.MarkForwardedAsync"/>
/// State guard: <see cref="SqliteAuditWriter.MarkForwardedAsync"/>
/// must NOT demote a <see cref="AuditForwardState.Reconciled"/> row back to
/// <see cref="AuditForwardState.Forwarded"/>. When a batch contains both a
/// Pending ID and an already-Reconciled ID:
@@ -818,6 +875,7 @@ public class SqliteAuditWriterWriteTests
/// This mirrors the idempotency guard already present on
/// <see cref="SqliteAuditWriter.MarkReconciledAsync"/>.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MarkForwardedAsync_DoesNotDemoteReconciledRow_WhilePendingStillTransitions()
{
@@ -879,6 +937,7 @@ public class SqliteAuditWriterWriteTests
/// <see cref="SqliteAuditWriter.MarkForwardedAsync"/> call flip atomically — and
/// <see cref="SqliteAuditWriter.MarkReconciledAsync"/> chunks the same way.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MarkForwardedThenReconciled_LargeBatch_ChunksParameters_AllFlip()
{
@@ -912,6 +971,8 @@ public class SqliteAuditWriterWriteTests
// ----- ExecutionId (rides DetailsJson, recomposed via AsRow) ----- //
/// <summary>Verifies that a non-null execution id round-trips through a write and read.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAsync_NonNullExecutionId_RoundTrips()
{
@@ -928,6 +989,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(executionId, row.AsRow().ExecutionId);
}
/// <summary>Verifies that a null execution id round-trips as null.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAsync_NullExecutionId_RoundTripsAsNull()
{
@@ -945,6 +1008,8 @@ public class SqliteAuditWriterWriteTests
// ----- SourceNode stamping (Tasks 11/12) ----- //
/// <summary>Verifies that the source node is stamped from the node identity provider when the event has none.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAsync_StampsSourceNodeFromProvider_WhenEventHasNone()
{
@@ -962,6 +1027,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal("node-a", row.SourceNode);
}
/// <summary>Verifies that a source node supplied by the caller is preserved.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAsync_PreservesCallerProvidedSourceNode()
{
@@ -980,6 +1047,8 @@ public class SqliteAuditWriterWriteTests
Assert.Equal("node-z", row.SourceNode);
}
/// <summary>Verifies that the source node stays null when the provider returns null.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAsync_LeavesSourceNodeNull_WhenProviderReturnsNull()
{
@@ -999,13 +1068,14 @@ public class SqliteAuditWriterWriteTests
// ----- C4 hardening: safe enum-parse in MapRow ----- //
/// <summary>
/// C4 hardening (Task 2.5): a row whose stored <c>Outcome</c> column holds an
/// C4 hardening: a row whose stored <c>Outcome</c> column holds an
/// unknown/renamed enum string must NOT fault the read path; it degrades
/// gracefully to <see cref="AuditOutcome.Success"/> (the safe
/// <see cref="AuditRowProjection.ParseEnum{TEnum}"/> fallback). The read is
/// exercised via the public <see cref="SqliteAuditWriter.ReadPendingAsync"/>
/// surface which calls the private <c>MapRow</c>.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReadPendingAsync_UnknownOutcomeString_DoesNotThrow_YieldsFallback()
{
@@ -1033,8 +1103,10 @@ public class SqliteAuditWriterWriteTests
Assert.Equal(AuditOutcome.Success, row.Outcome);
}
// ── Task 24: pin the inclusive (>=) reconciliation cursor boundary ──
// ── Pin the inclusive (>=) reconciliation cursor boundary ──
/// <summary>Verifies that a row at the boundary timestamp is included in the since-read and that event-id deduplication absorbs the resulting duplicates.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReadPendingSince_BoundaryTimestamp_IsInclusive_EventIdDedupAbsorbsDuplicates()
{