using ScadaLink.AuditLog.Site; using ScadaLink.Commons.Entities.Audit; using ScadaLink.Commons.Types.Enums; namespace ScadaLink.AuditLog.Tests.Site; /// /// Bundle B (M2-T3) tests for — the /// drop-oldest fallback used by when the /// primary SQLite writer is throwing. /// public class RingBufferFallbackTests { private static AuditEvent NewEvent(string? target = null) { return new AuditEvent { EventId = Guid.NewGuid(), OccurredAtUtc = DateTime.UtcNow, Channel = AuditChannel.ApiOutbound, Kind = AuditKind.ApiCall, Status = AuditStatus.Delivered, Target = target, PayloadTruncated = false, ForwardState = AuditForwardState.Pending, }; } [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(); 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); } [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(); 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); } } [Fact] public void TryEnqueue_AllSucceeds_ReturnsTrue() { var ring = new RingBufferFallback(capacity: 16); for (int i = 0; i < 8; i++) { Assert.True(ring.TryEnqueue(NewEvent())); } } }