Premiere commit - Omika
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Omika.Diagnostics.Configuration;
|
||||
using Omika.Diagnostics.Models;
|
||||
using Omika.Diagnostics.Repositories;
|
||||
using Omika.Diagnostics.Tests.Fakes;
|
||||
using Omika.Diagnostics.Worker;
|
||||
|
||||
namespace Omika.Diagnostics.Tests;
|
||||
|
||||
/// <summary>Rétention télémétrie (telemetry_metric_hourly) : 6 mois, lots bornés, fail-open.</summary>
|
||||
public class DiagnosticTelemetryRetentionTests
|
||||
{
|
||||
private static TelemetryMetricHourly At(DateTimeOffset bucket) =>
|
||||
new()
|
||||
{
|
||||
BucketUtc = bucket,
|
||||
MetricName = "test.metric",
|
||||
Component = string.Empty,
|
||||
Value = 1,
|
||||
Count = 1,
|
||||
MinValue = 1,
|
||||
MaxValue = 1,
|
||||
TagsJson = "{}"
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------- repo ----
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteOlderThan_RemovesOnlyOlderThanCutoff()
|
||||
{
|
||||
var repo = new FakeTelemetryMetricRepository();
|
||||
DateTimeOffset cutoff = DateTimeOffset.UtcNow.AddDays(-180); // 6 mois
|
||||
|
||||
await repo.UpsertHourlyAsync([
|
||||
At(cutoff.AddDays(-10)),
|
||||
At(cutoff.AddDays(-1)),
|
||||
At(DateTimeOffset.UtcNow)
|
||||
]);
|
||||
|
||||
int deleted = await repo.DeleteOlderThanAsync(cutoff, batchSize: 100);
|
||||
|
||||
Assert.Equal(2, deleted);
|
||||
Assert.Single(repo.All);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteOlderThan_RespectsBatchSize()
|
||||
{
|
||||
var repo = new FakeTelemetryMetricRepository();
|
||||
DateTimeOffset cutoff = DateTimeOffset.UtcNow.AddDays(-180);
|
||||
|
||||
var old = new List<TelemetryMetricHourly>();
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
old.Add(At(cutoff.AddDays(-i - 1)));
|
||||
}
|
||||
|
||||
await repo.UpsertHourlyAsync(old);
|
||||
|
||||
int first = await repo.DeleteOlderThanAsync(cutoff, batchSize: 2);
|
||||
int second = await repo.DeleteOlderThanAsync(cutoff, batchSize: 2);
|
||||
int third = await repo.DeleteOlderThanAsync(cutoff, batchSize: 2);
|
||||
|
||||
Assert.Equal(2, first);
|
||||
Assert.Equal(2, second);
|
||||
Assert.Equal(1, third);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteOlderThan_NonPositiveBatchSize_ReturnsZero()
|
||||
{
|
||||
var repo = new FakeTelemetryMetricRepository();
|
||||
await repo.UpsertHourlyAsync([At(DateTimeOffset.UtcNow.AddDays(-200))]);
|
||||
|
||||
int deleted = await repo.DeleteOlderThanAsync(DateTimeOffset.UtcNow.AddDays(-180), batchSize: 0);
|
||||
|
||||
Assert.Equal(0, deleted);
|
||||
Assert.Single(repo.All);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- worker ----
|
||||
|
||||
private static DiagnosticTelemetryRetentionWorker CreateWorker(
|
||||
ITelemetryMetricRepository repo,
|
||||
DiagnosticStoreOptions options) =>
|
||||
new(repo, Options.Create(options), NullLogger<DiagnosticTelemetryRetentionWorker>.Instance);
|
||||
|
||||
[Fact]
|
||||
public async Task TelemetryRetentionWorker_PurgesOlderAggregates()
|
||||
{
|
||||
var repo = new FakeTelemetryMetricRepository();
|
||||
DateTimeOffset cutoff = DateTimeOffset.UtcNow.AddDays(-180);
|
||||
|
||||
await repo.UpsertHourlyAsync([
|
||||
At(cutoff.AddDays(-5)),
|
||||
At(cutoff.AddDays(-1)),
|
||||
At(DateTimeOffset.UtcNow)
|
||||
]);
|
||||
|
||||
var worker = CreateWorker(repo, new DiagnosticStoreOptions
|
||||
{
|
||||
TelemetryRetentionDays = 180,
|
||||
RetentionBatchSize = 100,
|
||||
RetentionIntervalHours = 1
|
||||
});
|
||||
|
||||
using var cts = new CancellationTokenSource();
|
||||
await worker.StartAsync(cts.Token);
|
||||
|
||||
int remaining = 3;
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
remaining = repo.All.Count;
|
||||
if (remaining == 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
await Task.Delay(100);
|
||||
}
|
||||
|
||||
cts.Cancel();
|
||||
await worker.StopAsync(cts.Token);
|
||||
|
||||
Assert.Equal(1, remaining); // seul l'agrégat récent subsiste
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TelemetryRetentionWorker_Disabled_DoesNotPurge()
|
||||
{
|
||||
var repo = new FakeTelemetryMetricRepository();
|
||||
await repo.UpsertHourlyAsync([At(DateTimeOffset.UtcNow.AddDays(-200))]);
|
||||
|
||||
var worker = CreateWorker(repo, new DiagnosticStoreOptions
|
||||
{
|
||||
TelemetryRetentionDays = 0, // désactivé
|
||||
RetentionBatchSize = 100,
|
||||
RetentionIntervalHours = 1
|
||||
});
|
||||
|
||||
using var cts = new CancellationTokenSource();
|
||||
await worker.StartAsync(cts.Token);
|
||||
await Task.Delay(300);
|
||||
cts.Cancel();
|
||||
await worker.StopAsync(cts.Token);
|
||||
|
||||
Assert.Single(repo.All); // rien de purgé
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TelemetryRetentionWorker_DbDown_DoesNotCrash()
|
||||
{
|
||||
var worker = CreateWorker(new ThrowingTelemetryMetricRepository(), new DiagnosticStoreOptions
|
||||
{
|
||||
TelemetryRetentionDays = 180,
|
||||
RetentionBatchSize = 100,
|
||||
RetentionIntervalHours = 1
|
||||
});
|
||||
|
||||
using var cts = new CancellationTokenSource();
|
||||
await worker.StartAsync(cts.Token); // ne doit pas lever
|
||||
await Task.Delay(300);
|
||||
cts.Cancel();
|
||||
await worker.StopAsync(cts.Token); // arrêt propre
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user