513fa1aa16
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.
94 lines
3.2 KiB
C#
94 lines
3.2 KiB
C#
using ZB.MOM.WW.ScadaBridge.AuditLog.Site;
|
|
using ZB.MOM.WW.Audit;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.AuditLog.Tests.Site;
|
|
|
|
/// <summary>
|
|
/// Tests for <see cref="RingBufferFallback"/> — the
|
|
/// drop-oldest fallback used by <see cref="FallbackAuditWriter"/> when the
|
|
/// primary SQLite writer is throwing.
|
|
/// </summary>
|
|
public class RingBufferFallbackTests
|
|
{
|
|
private static AuditEvent NewEvent(string? target = null)
|
|
{
|
|
return ScadaBridgeAuditEventFactory.Create(
|
|
eventId: Guid.NewGuid(),
|
|
occurredAtUtc: DateTime.UtcNow,
|
|
channel: AuditChannel.ApiOutbound,
|
|
kind: AuditKind.ApiCall,
|
|
status: AuditStatus.Delivered,
|
|
target: target);
|
|
}
|
|
|
|
/// <summary>Verifies that enqueuing 1025 events into a ring with a capacity of 1024 drops the oldest event and raises the overflow notification exactly once.</summary>
|
|
/// <returns>A task that represents the asynchronous operation.</returns>
|
|
[Fact]
|
|
public async Task Enqueue_1025_Into_1024Cap_Ring_DropsOldest_AndRaisesOverflowOnce()
|
|
{
|
|
var ring = new RingBufferFallback(capacity: 1024);
|
|
var overflowCount = 0;
|
|
ring.RingBufferOverflowed += () => Interlocked.Increment(ref overflowCount);
|
|
|
|
var events = Enumerable.Range(0, 1025).Select(i => NewEvent(target: i.ToString())).ToList();
|
|
foreach (var e in events)
|
|
{
|
|
Assert.True(ring.TryEnqueue(e));
|
|
}
|
|
|
|
Assert.Equal(1, overflowCount);
|
|
|
|
// The surviving 1024 are events[1..1024] (oldest dropped).
|
|
var drained = new List<AuditEvent>();
|
|
ring.Complete();
|
|
await foreach (var e in ring.DrainAsync(CancellationToken.None))
|
|
{
|
|
drained.Add(e);
|
|
}
|
|
|
|
Assert.Equal(1024, drained.Count);
|
|
Assert.Equal("1", drained[0].Target);
|
|
Assert.Equal("1024", drained[^1].Target);
|
|
}
|
|
|
|
/// <summary>Verifies that draining yields the queued events in FIFO order and then completes once the ring is empty.</summary>
|
|
/// <returns>A task that represents the asynchronous operation.</returns>
|
|
[Fact]
|
|
public async Task DrainAsync_Yields_FIFO_Then_Completes_When_Empty()
|
|
{
|
|
var ring = new RingBufferFallback(capacity: 16);
|
|
var enqueued = Enumerable.Range(0, 5).Select(i => NewEvent(target: i.ToString())).ToList();
|
|
foreach (var e in enqueued)
|
|
{
|
|
Assert.True(ring.TryEnqueue(e));
|
|
}
|
|
|
|
ring.Complete();
|
|
|
|
var drained = new List<AuditEvent>();
|
|
await foreach (var e in ring.DrainAsync(CancellationToken.None))
|
|
{
|
|
drained.Add(e);
|
|
}
|
|
|
|
Assert.Equal(5, drained.Count);
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
Assert.Equal(i.ToString(), drained[i].Target);
|
|
}
|
|
}
|
|
|
|
/// <summary>Verifies that enqueuing a single event into a ring with spare capacity succeeds and returns true.</summary>
|
|
[Fact]
|
|
public void TryEnqueue_AllSucceeds_ReturnsTrue()
|
|
{
|
|
var ring = new RingBufferFallback(capacity: 16);
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
Assert.True(ring.TryEnqueue(NewEvent()));
|
|
}
|
|
}
|
|
}
|