140 lines
4.3 KiB
C#
140 lines
4.3 KiB
C#
using Omika.Core.Configuration;
|
|
using Omika.Core.Observability;
|
|
|
|
namespace Omika.Tests.Observability;
|
|
|
|
public class TelemetryWorkerTests
|
|
{
|
|
[Fact]
|
|
public async Task Worker_DrainsToExporter()
|
|
{
|
|
var (queue, counters) = CreateQueue();
|
|
var exporter = new CollectingExporter();
|
|
var worker = new TelemetryWorker(queue, exporter);
|
|
|
|
queue.TryEnqueue(ObservabilityTestHarness.NewEvent(TelemetryEventCodes.MobileAppStarted));
|
|
queue.TryEnqueue(ObservabilityTestHarness.NewEvent(TelemetryEventCodes.MobileAppStarted));
|
|
|
|
using var cts = new CancellationTokenSource();
|
|
Task run = worker.ExecuteAsync(cts.Token);
|
|
|
|
await ObservabilityTestHarness.WaitUntilAsync(() => exporter.Count == 2);
|
|
|
|
cts.Cancel();
|
|
await run;
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Worker_DoesNotStarveLowPriority()
|
|
{
|
|
var (queue, _) = CreateQueue();
|
|
var exporter = new CollectingExporter();
|
|
var worker = new TelemetryWorker(queue, exporter);
|
|
|
|
// Fort arriéré de P0 + quelques P4 : les P4 doivent quand même être exportés.
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
queue.TryEnqueue(ObservabilityTestHarness.NewEvent(
|
|
TelemetryEventCodes.MobileSyncOperationReceived, priority: TelemetryPriority.P0));
|
|
}
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
queue.TryEnqueue(ObservabilityTestHarness.NewEvent(
|
|
TelemetryEventCodes.MobileAppStarted, priority: TelemetryPriority.P4));
|
|
}
|
|
|
|
using var cts = new CancellationTokenSource();
|
|
Task run = worker.ExecuteAsync(cts.Token);
|
|
|
|
await ObservabilityTestHarness.WaitUntilAsync(() => exporter.Count == 110);
|
|
|
|
cts.Cancel();
|
|
await run;
|
|
|
|
Assert.Equal(100, exporter.ByPriority(TelemetryPriority.P0));
|
|
Assert.Equal(10, exporter.ByPriority(TelemetryPriority.P4));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Worker_ExporterThrows_DoesNotPropagate()
|
|
{
|
|
var (queue, _) = CreateQueue();
|
|
var worker = new TelemetryWorker(queue, new ThrowingExporter());
|
|
|
|
queue.TryEnqueue(ObservabilityTestHarness.NewEvent(TelemetryEventCodes.MobileAppStarted));
|
|
|
|
using var cts = new CancellationTokenSource();
|
|
Task run = worker.ExecuteAsync(cts.Token);
|
|
|
|
// Laisse au worker le temps de tenter l'export, d'échouer et de reprendre.
|
|
await Task.Delay(300);
|
|
cts.Cancel();
|
|
|
|
await run;
|
|
// Le lot a été abandonné (perte de log acceptable) ; aucune exception.
|
|
Assert.Equal(0, queue.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Worker_Cancellation_Stops()
|
|
{
|
|
var (queue, _) = CreateQueue();
|
|
var worker = new TelemetryWorker(queue, new NullTelemetryExporter());
|
|
|
|
using var cts = new CancellationTokenSource();
|
|
Task run = worker.ExecuteAsync(cts.Token);
|
|
|
|
cts.Cancel();
|
|
await run;
|
|
}
|
|
|
|
private static (PriorityTelemetryQueue Queue, TelemetryCounters Counters) CreateQueue()
|
|
{
|
|
var options = new ObservabilityOptions();
|
|
var counters = new TelemetryCounters();
|
|
return (new PriorityTelemetryQueue(options, counters), counters);
|
|
}
|
|
|
|
private sealed class CollectingExporter : ITelemetryExporter
|
|
{
|
|
private readonly object _lock = new();
|
|
private readonly List<OmikaEvent> _exported = [];
|
|
|
|
public int Count
|
|
{
|
|
get
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return _exported.Count;
|
|
}
|
|
}
|
|
}
|
|
|
|
public int ByPriority(TelemetryPriority priority)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return _exported.Count(e => e.EffectivePriority == priority);
|
|
}
|
|
}
|
|
|
|
public Task ExportAsync(IReadOnlyList<OmikaEvent> events, CancellationToken cancellationToken = default)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_exported.AddRange(events);
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|
|
|
|
private sealed class ThrowingExporter : ITelemetryExporter
|
|
{
|
|
public Task ExportAsync(IReadOnlyList<OmikaEvent> events, CancellationToken cancellationToken = default) =>
|
|
throw new InvalidOperationException("exporteur défaillant (test)");
|
|
}
|
|
}
|