168 lines
5.1 KiB
C#
168 lines
5.1 KiB
C#
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
|
|
}
|
|
}
|