Files
2026-10-23 18:46:50 +02:00

147 lines
6.1 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Omika.Core.Observability.Forwarding;
namespace Omika.Tests.Observability.Forwarding;
/// <summary>Tests du spool disque du forwarder (checkpoint, bornes, suppression, quota, rétention).</summary>
public class DiagnosticsForwarderSpoolTests : IDisposable
{
private const string File001 = "omika-mobile-diagnostic-20261002-001.jsonl";
private const string File002 = "omika-mobile-diagnostic-20261002-002.jsonl";
private const string File003 = "omika-mobile-diagnostic-20261002-003.jsonl";
private readonly string _dir = ForwardingTestHarness.CreateTempDirectory();
private static DiagnosticsForwardingSpoolOptions DefaultSpool => new();
public void Dispose() => ForwardingTestHarness.DeleteDirectory(_dir);
private DiagnosticsForwarderSpool NewSpool(DiagnosticsForwardingSpoolOptions? options = null) =>
new(_dir, "forwarder-checkpoint.json", options ?? DefaultSpool);
[Fact]
public void ReadNext_EmptyDirectory_ReturnsReachedEnd()
{
var spool = NewSpool();
DiagnosticsForwarderBatch batch = spool.ReadNext(null, 10, 1024);
Assert.Empty(batch.Records);
Assert.True(batch.ReachedEnd);
}
[Fact]
public void ReadNext_ReadsRecordsInOrder_AndResumesAcrossFiles()
{
ForwardingTestHarness.WriteSpoolFile(_dir, File001,
[ForwardingTestHarness.NewRecord(component: "a"), ForwardingTestHarness.NewRecord(component: "b")]);
ForwardingTestHarness.WriteSpoolFile(_dir, File002,
[ForwardingTestHarness.NewRecord(component: "c")]);
var spool = NewSpool();
DiagnosticsForwarderBatch first = spool.ReadNext(null, 2, 1_000_000);
Assert.Equal(2, first.Records.Count);
Assert.Equal("a", first.Records[0].Event.Component);
Assert.Equal("b", first.Records[1].Event.Component);
Assert.NotNull(first.NextPosition);
Assert.Equal(File001, first.NextPosition!.FileName);
DiagnosticsForwarderBatch second = spool.ReadNext(first.NextPosition, 2, 1_000_000);
Assert.Single(second.Records);
Assert.Equal("c", second.Records[0].Event.Component);
Assert.Equal(File002, second.NextPosition!.FileName);
}
[Fact]
public void ReadNext_RespectsMaxBytes_StillReturnsAtLeastOneRecord()
{
ForwardingTestHarness.WriteSpoolFile(_dir, File001,
[ForwardingTestHarness.NewRecord(), ForwardingTestHarness.NewRecord()]);
var spool = NewSpool();
DiagnosticsForwarderBatch batch = spool.ReadNext(null, 100, 10);
Assert.Single(batch.Records); // premier seuil (octets) : 1 seul, jamais zéro.
}
[Fact]
public void Commit_ThenLoadCheckpoint_ResumesFromNextLine()
{
ForwardingTestHarness.WriteSpoolFile(_dir, File001,
[ForwardingTestHarness.NewRecord(component: "a"), ForwardingTestHarness.NewRecord(component: "b"), ForwardingTestHarness.NewRecord(component: "c")]);
var spool = NewSpool();
DiagnosticsForwarderBatch first = spool.ReadNext(null, 1, 1_000_000);
Assert.Single(first.Records);
Assert.Equal("a", first.Records[0].Event.Component);
spool.Commit(first.NextPosition!);
DiagnosticsForwarderPosition? checkpoint = spool.LoadCheckpoint();
Assert.NotNull(checkpoint);
Assert.Equal(File001, checkpoint!.FileName);
Assert.Equal(0, checkpoint.LineIndex);
DiagnosticsForwarderBatch second = spool.ReadNext(checkpoint, 10, 1_000_000);
Assert.Equal(2, second.Records.Count);
Assert.Equal("b", second.Records[0].Event.Component);
Assert.Equal("c", second.Records[1].Event.Component);
}
[Fact]
public void PruneConsumed_DeletesOlderFiles_NeverActiveFile()
{
ForwardingTestHarness.WriteSpoolFile(_dir, File001, [ForwardingTestHarness.NewRecord()]);
ForwardingTestHarness.WriteSpoolFile(_dir, File002, [ForwardingTestHarness.NewRecord()]);
ForwardingTestHarness.WriteSpoolFile(_dir, File003, [ForwardingTestHarness.NewRecord()]);
var spool = NewSpool();
int deleted = spool.PruneConsumed(new DiagnosticsForwarderPosition { FileName = File002, LineIndex = 0 });
Assert.Equal(1, deleted); // seul 001 (antérieur) est supprimé.
Assert.False(File.Exists(Path.Combine(_dir, File001)));
Assert.True(File.Exists(Path.Combine(_dir, File002)));
Assert.True(File.Exists(Path.Combine(_dir, File003))); // actif préservé.
}
[Fact]
public void EnforceBounds_Quota_DeletesOldestFiles()
{
int chunk = 400 * 1024; // 3 × 400 Ko = 1.2 Mo > 1 Mo de quota.
string padding = new string('a', chunk);
ForwardingTestHarness.WriteRawSpoolFile(_dir, File001, padding);
ForwardingTestHarness.WriteRawSpoolFile(_dir, File002, padding);
ForwardingTestHarness.WriteRawSpoolFile(_dir, File003, padding);
var spool = NewSpool(new DiagnosticsForwardingSpoolOptions { MaxTotalSizeMb = 1 });
int deleted = spool.EnforceBounds(DateTimeOffset.UtcNow);
Assert.Equal(1, deleted); // le plus ancien est évincé, total ≤ 1 Mo.
Assert.False(File.Exists(Path.Combine(_dir, File001)));
Assert.True(File.Exists(Path.Combine(_dir, File002)));
Assert.True(File.Exists(Path.Combine(_dir, File003)));
}
[Fact]
public void EnforceBounds_Retention_DeletesExpiredFiles_NotActive()
{
ForwardingTestHarness.WriteSpoolFile(_dir, File001, [ForwardingTestHarness.NewRecord()]);
ForwardingTestHarness.WriteSpoolFile(_dir, File002, [ForwardingTestHarness.NewRecord()]);
// 001 est ancien, 002 est l'actif (et récent).
File.SetLastWriteTimeUtc(Path.Combine(_dir, File001), DateTime.UtcNow.AddDays(-2));
File.SetLastWriteTimeUtc(Path.Combine(_dir, File002), DateTime.UtcNow);
var spool = NewSpool(new DiagnosticsForwardingSpoolOptions { RetentionDays = 1, MaxTotalSizeMb = 1024 });
int deleted = spool.EnforceBounds(DateTimeOffset.UtcNow);
Assert.Equal(1, deleted);
Assert.False(File.Exists(Path.Combine(_dir, File001)));
Assert.True(File.Exists(Path.Combine(_dir, File002)));
}
}