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:
@@ -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()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user