Premiere commit - Omika
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
using Omika.App.Local.Diagnostics;
|
||||
using Omika.Core.Observability;
|
||||
using Omika.Core.Observability.Outbox;
|
||||
|
||||
namespace Omika.Tests.Observability.Outbox;
|
||||
|
||||
/// <summary>Tests du store SQLite séparé (omika-diagnostics.db) : persistance, rétention, éviction, redémarrage.</summary>
|
||||
public class DiagnosticOutboxSqliteStoreTests : IAsyncLifetime
|
||||
{
|
||||
private readonly string _dir = Path.Combine(Path.GetTempPath(), "omika-diag-sqlite-tests", Guid.NewGuid().ToString("N"));
|
||||
private string DbPath => Path.Combine(_dir, "omika-diagnostics.db");
|
||||
|
||||
public Task InitializeAsync()
|
||||
{
|
||||
Directory.CreateDirectory(_dir);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task DisposeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(_dir))
|
||||
{
|
||||
Directory.Delete(_dir, recursive: true);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Best-effort.
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static DiagnosticOutboxRow NewRow(TelemetryPriority priority = TelemetryPriority.P3, string payload = "{}") =>
|
||||
new()
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
Priority = priority,
|
||||
CreatedAtUtc = DateTimeOffset.UtcNow,
|
||||
ExpiresAtUtc = DateTimeOffset.UtcNow.AddDays(7),
|
||||
PayloadVersion = 1,
|
||||
PayloadJson = payload,
|
||||
AttemptCount = 0,
|
||||
NextAttemptUtc = DateTimeOffset.UtcNow
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public async Task StoreAndRetrieve_RoundTrip()
|
||||
{
|
||||
await using var store = new DiagnosticOutboxSqliteStore(new DiagnosticOutboxOptions { DatabasePath = DbPath });
|
||||
DiagnosticOutboxRow row = NewRow(payload: """{"eventId":"00000000-0000-0000-0000-000000000001"}""");
|
||||
|
||||
await store.StoreAsync([row]);
|
||||
IReadOnlyList<DiagnosticOutboxRow> batch = await store.GetNextBatchAsync(10, 1024 * 1024, DateTimeOffset.UtcNow);
|
||||
|
||||
DiagnosticOutboxRow retrieved = Assert.Single(batch);
|
||||
Assert.Equal(row.EventId, retrieved.EventId);
|
||||
Assert.Equal(row.PayloadJson, retrieved.PayloadJson);
|
||||
Assert.Equal(row.Priority, retrieved.Priority);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetNextBatch_RespectsNextAttemptUtc()
|
||||
{
|
||||
await using var store = new DiagnosticOutboxSqliteStore(new DiagnosticOutboxOptions { DatabasePath = DbPath });
|
||||
DiagnosticOutboxRow future = NewRow();
|
||||
future = new DiagnosticOutboxRow
|
||||
{
|
||||
EventId = future.EventId,
|
||||
Priority = future.Priority,
|
||||
CreatedAtUtc = future.CreatedAtUtc,
|
||||
ExpiresAtUtc = future.ExpiresAtUtc,
|
||||
PayloadVersion = future.PayloadVersion,
|
||||
PayloadJson = future.PayloadJson,
|
||||
NextAttemptUtc = DateTimeOffset.UtcNow.AddMinutes(5)
|
||||
};
|
||||
await store.StoreAsync([future]);
|
||||
|
||||
IReadOnlyList<DiagnosticOutboxRow> batch = await store.GetNextBatchAsync(10, 1024 * 1024, DateTimeOffset.UtcNow);
|
||||
Assert.Empty(batch);
|
||||
|
||||
IReadOnlyList<DiagnosticOutboxRow> later = await store.GetNextBatchAsync(10, 1024 * 1024, DateTimeOffset.UtcNow.AddMinutes(10));
|
||||
Assert.Single(later);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteExpired_RemovesOnlyExpired()
|
||||
{
|
||||
await using var store = new DiagnosticOutboxSqliteStore(new DiagnosticOutboxOptions { DatabasePath = DbPath });
|
||||
DiagnosticOutboxRow expired = NewRow();
|
||||
expired = new DiagnosticOutboxRow
|
||||
{
|
||||
EventId = expired.EventId,
|
||||
Priority = expired.Priority,
|
||||
CreatedAtUtc = expired.CreatedAtUtc,
|
||||
ExpiresAtUtc = DateTimeOffset.UtcNow.AddMinutes(-1),
|
||||
PayloadVersion = expired.PayloadVersion,
|
||||
PayloadJson = expired.PayloadJson
|
||||
};
|
||||
await store.StoreAsync([expired, NewRow()]);
|
||||
|
||||
int removed = await store.DeleteExpiredAsync(DateTimeOffset.UtcNow);
|
||||
|
||||
Assert.Equal(1, removed);
|
||||
Assert.Equal(1, await store.CountAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteOldest_RemovesOldestOfPriority()
|
||||
{
|
||||
await using var store = new DiagnosticOutboxSqliteStore(new DiagnosticOutboxOptions { DatabasePath = DbPath });
|
||||
DiagnosticOutboxRow old = NewRow(TelemetryPriority.P3);
|
||||
await store.StoreAsync([old]);
|
||||
await Task.Delay(10);
|
||||
DiagnosticOutboxRow newer = NewRow(TelemetryPriority.P3);
|
||||
await store.StoreAsync([newer]);
|
||||
|
||||
int removed = await store.DeleteOldestAsync(TelemetryPriority.P3, 1);
|
||||
|
||||
Assert.Equal(1, removed);
|
||||
Assert.False((await store.GetNextBatchAsync(10, 1024 * 1024, DateTimeOffset.UtcNow)).Any(r => r.EventId == old.EventId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Restart_PersistsRowsAcrossSessions()
|
||||
{
|
||||
DiagnosticOutboxRow row = NewRow(payload: """{"eventId":"00000000-0000-0000-0000-00000000000A"}""");
|
||||
await using (var store = new DiagnosticOutboxSqliteStore(new DiagnosticOutboxOptions { DatabasePath = DbPath }))
|
||||
{
|
||||
await store.StoreAsync([row]);
|
||||
}
|
||||
|
||||
// « Redémarrage » : nouvelle connexion sur le même fichier.
|
||||
await using (var store = new DiagnosticOutboxSqliteStore(new DiagnosticOutboxOptions { DatabasePath = DbPath }))
|
||||
{
|
||||
IReadOnlyList<DiagnosticOutboxRow> batch = await store.GetNextBatchAsync(10, 1024 * 1024, DateTimeOffset.UtcNow);
|
||||
Assert.Equal(row.EventId, Assert.Single(batch).EventId);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user