143 lines
5.3 KiB
C#
143 lines
5.3 KiB
C#
using Omika.Core.Observability;
|
|
using Omika.Core.Observability.Outbox;
|
|
|
|
namespace Omika.Tests.Observability.Outbox;
|
|
|
|
/// <summary>Tests du DiagnosticOutbox : filtrage P0..P3, saturation, éviction, rétention, fail-open.</summary>
|
|
public class DiagnosticOutboxTests
|
|
{
|
|
private static (DiagnosticOutbox Outbox, InMemoryDiagnosticOutboxStore Store, DiagnosticCounters Counters) Create(
|
|
DiagnosticOutboxOptions? options = null)
|
|
{
|
|
var store = new InMemoryDiagnosticOutboxStore();
|
|
var counters = new DiagnosticCounters();
|
|
var outbox = new DiagnosticOutbox(store, options ?? new DiagnosticOutboxOptions(), counters);
|
|
return (outbox, store, counters);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Store_StoresP0ThroughP3_ByDefault()
|
|
{
|
|
(DiagnosticOutbox outbox, _, DiagnosticCounters counters) = Create();
|
|
|
|
int stored = await outbox.StoreAsync(
|
|
[
|
|
OutboxTestHarness.NewEvent(TelemetryPriority.P0),
|
|
OutboxTestHarness.NewEvent(TelemetryPriority.P1),
|
|
OutboxTestHarness.NewEvent(TelemetryPriority.P2),
|
|
OutboxTestHarness.NewEvent(TelemetryPriority.P3)
|
|
]);
|
|
|
|
Assert.Equal(4, stored);
|
|
Assert.Equal(4, counters.OutboxStored);
|
|
Assert.Equal(0, counters.OutboxDropped);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Store_DropsP4_ByDefault()
|
|
{
|
|
(DiagnosticOutbox outbox, _, DiagnosticCounters counters) = Create();
|
|
|
|
int stored = await outbox.StoreAsync([OutboxTestHarness.NewEvent(TelemetryPriority.P4)]);
|
|
|
|
Assert.Equal(0, stored);
|
|
Assert.Equal(1, counters.OutboxDropped);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Store_IncludeP4Option_StoresP4()
|
|
{
|
|
var options = new DiagnosticOutboxOptions { IncludeP4 = true };
|
|
(DiagnosticOutbox outbox, _, DiagnosticCounters counters) = Create(options);
|
|
|
|
int stored = await outbox.StoreAsync([OutboxTestHarness.NewEvent(TelemetryPriority.P4)]);
|
|
|
|
Assert.Equal(1, stored);
|
|
Assert.Equal(1, counters.OutboxStored);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Store_EvictsP3_BeforeP0_WhenSaturated()
|
|
{
|
|
var options = new DiagnosticOutboxOptions { MaxRows = 10 };
|
|
(DiagnosticOutbox outbox, InMemoryDiagnosticOutboxStore store, DiagnosticCounters counters) = Create(options);
|
|
|
|
// Remplit l'outbox avec 10 P3.
|
|
List<OmikaEvent> p3s = Enumerable.Range(0, 10)
|
|
.Select(_ => (OmikaEvent)OutboxTestHarness.NewEvent(TelemetryPriority.P3))
|
|
.ToList();
|
|
await outbox.StoreAsync(p3s);
|
|
Assert.Equal(10, await store.CountAsync());
|
|
|
|
// Un nouveau P0 doit évincer un P3 (pas un P0).
|
|
await outbox.StoreAsync([OutboxTestHarness.NewEvent(TelemetryPriority.P0)]);
|
|
|
|
Assert.Equal(10, await store.CountAsync());
|
|
Assert.Contains(store.Snapshot(), r => r.Priority == TelemetryPriority.P0);
|
|
Assert.Equal(1, counters.OutboxEvictedP3);
|
|
Assert.Equal(0, counters.OutboxEvictedP0);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Store_FullOfP0_DropsNewP0_WithCounter()
|
|
{
|
|
var options = new DiagnosticOutboxOptions { MaxRows = 5 };
|
|
(DiagnosticOutbox outbox, InMemoryDiagnosticOutboxStore store, DiagnosticCounters counters) = Create(options);
|
|
|
|
await outbox.StoreAsync(Enumerable.Range(0, 5)
|
|
.Select(_ => OutboxTestHarness.NewEvent(TelemetryPriority.P0))
|
|
.ToList());
|
|
Assert.Equal(5, await store.CountAsync());
|
|
|
|
int stored = await outbox.StoreAsync([OutboxTestHarness.NewEvent(TelemetryPriority.P0)]);
|
|
|
|
Assert.Equal(0, stored);
|
|
Assert.Equal(5, await store.CountAsync());
|
|
Assert.Equal(1, counters.OutboxDroppedFull);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Store_Disabled_StoresNothing()
|
|
{
|
|
var options = new DiagnosticOutboxOptions { Enabled = false };
|
|
(DiagnosticOutbox outbox, InMemoryDiagnosticOutboxStore store, _) = Create(options);
|
|
|
|
int stored = await outbox.StoreAsync([OutboxTestHarness.NewEvent(TelemetryPriority.P0)]);
|
|
|
|
Assert.Equal(0, stored);
|
|
Assert.Equal(0, await store.CountAsync());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CleanupExpired_RemovesExpiredOnly()
|
|
{
|
|
(DiagnosticOutbox outbox, InMemoryDiagnosticOutboxStore store, DiagnosticCounters counters) = Create();
|
|
|
|
// Utilise une rétention courte pour forcer l'expiration.
|
|
var options = new DiagnosticOutboxOptions { Retention = TimeSpan.FromMilliseconds(1) };
|
|
(outbox, store, counters) = Create(options);
|
|
await outbox.StoreAsync([OutboxTestHarness.NewEvent(TelemetryPriority.P3)]);
|
|
|
|
await Task.Delay(20);
|
|
int removed = await outbox.CleanupExpiredAsync();
|
|
|
|
Assert.Equal(1, removed);
|
|
Assert.Equal(1, counters.OutboxExpired);
|
|
Assert.Equal(0, await store.CountAsync());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Store_ThrowingStore_FailOpen_DegradesAndCounts()
|
|
{
|
|
var store = new InMemoryDiagnosticOutboxStore { ThrowOnStore = true };
|
|
var counters = new DiagnosticCounters();
|
|
var outbox = new DiagnosticOutbox(store, new DiagnosticOutboxOptions(), counters);
|
|
|
|
int stored = await outbox.StoreAsync([OutboxTestHarness.NewEvent(TelemetryPriority.P0)]);
|
|
|
|
Assert.Equal(0, stored);
|
|
Assert.Equal(1, counters.OutboxDegraded);
|
|
Assert.True(outbox.IsDegraded);
|
|
}
|
|
}
|