124 lines
4.9 KiB
C#
124 lines
4.9 KiB
C#
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Options;
|
|
using Omika.Diagnostics.Configuration;
|
|
using Omika.Diagnostics.Data;
|
|
using Omika.Diagnostics.Import;
|
|
using Omika.Diagnostics.Worker;
|
|
|
|
namespace Omika.Diagnostics.Tests;
|
|
|
|
/// <summary>
|
|
/// Vérifie que le conteneur DI du Diagnostics Worker construit réellement
|
|
/// <see cref="DiagnosticImporter"/> et les hosted services (régression de
|
|
/// l'incident production « Unable to resolve service for type
|
|
/// DiagnosticImportOptions »). Le host est construit avec
|
|
/// <c>ValidateOnBuild</c> + <c>ValidateScopes</c> pour détecter ce type d'erreur
|
|
/// à la construction (le test échouait avec l'ancien code).
|
|
/// </summary>
|
|
public class DiagnosticWorkerDependencyInjectionTests
|
|
{
|
|
[Fact]
|
|
public void WorkerHost_ServiceProviderBuilds_WithValidation()
|
|
{
|
|
// Avec l'ancien constructeur (DiagnosticImportOptions concret), ce Build()
|
|
// levait « Unable to resolve service for type DiagnosticImportOptions ».
|
|
using IHost host = BuildWorkerHost();
|
|
|
|
Assert.NotNull(host.Services);
|
|
}
|
|
|
|
[Fact]
|
|
public void WorkerHost_DiagnosticImporter_IsResolvable()
|
|
{
|
|
using IHost host = BuildWorkerHost();
|
|
|
|
DiagnosticImporter importer = host.Services.GetRequiredService<DiagnosticImporter>();
|
|
|
|
Assert.NotNull(importer);
|
|
}
|
|
|
|
[Fact]
|
|
public void WorkerHost_DiagnosticImportOptions_AreResolvedAndBound()
|
|
{
|
|
using IHost host = BuildWorkerHost();
|
|
|
|
DiagnosticImportOptions options = host.Services
|
|
.GetRequiredService<IOptions<DiagnosticImportOptions>>()
|
|
.Value;
|
|
|
|
Assert.NotNull(options);
|
|
// La configuration in-memory prime sur les valeurs par défaut (BatchSize=100).
|
|
Assert.Equal(50, options.BatchSize);
|
|
Assert.Equal("import-checkpoint.json", options.CheckpointFileName);
|
|
Assert.Equal(@"C:\Omika\Data\DiagnosticsWorker\Checkpoint", options.CheckpointDirectory);
|
|
}
|
|
|
|
[Fact]
|
|
public void WorkerHost_DiagnosticStoreOptions_ConnectionStringOverride_Wins()
|
|
{
|
|
using IHost host = BuildWorkerHost();
|
|
|
|
DiagnosticStoreOptions store = host.Services
|
|
.GetRequiredService<IOptions<DiagnosticStoreOptions>>()
|
|
.Value;
|
|
|
|
// La surcharge standard ConnectionStrings:DiagnosticsDatabase (variable
|
|
// d'environnement serveur) prime sur Diagnostics:ConnectionString.
|
|
Assert.Equal(
|
|
"Host=localhost;Database=omika_diagnostics;Username=diagnostics_worker",
|
|
store.ConnectionString);
|
|
}
|
|
|
|
[Fact]
|
|
public void WorkerHost_HostedServices_AreResolvable()
|
|
{
|
|
using IHost host = BuildWorkerHost();
|
|
|
|
List<IHostedService> hosted = host.Services.GetServices<IHostedService>().ToList();
|
|
|
|
Assert.Contains(hosted, s => s is DiagnosticImportWorker);
|
|
Assert.Contains(hosted, s => s is DiagnosticRetentionWorker);
|
|
Assert.Contains(hosted, s => s is DiagnosticTelemetryRetentionWorker);
|
|
}
|
|
|
|
private static IHost BuildWorkerHost()
|
|
{
|
|
// Configuration in-memory : aucune valeur secrète. La chaîne PostgreSQL
|
|
// est un placeholder sans mot de passe (jamais ouverte : les repositories
|
|
// sont construits sans connexion).
|
|
IConfiguration configuration = new ConfigurationBuilder()
|
|
.AddInMemoryCollection(new Dictionary<string, string?>
|
|
{
|
|
["Diagnostics:ConnectionString"] = "Host=ignored;Database=ignored",
|
|
["Diagnostics:Import:BatchSize"] = "50",
|
|
["Diagnostics:Import:CheckpointFileName"] = "import-checkpoint.json",
|
|
["Diagnostics:Import:CheckpointDirectory"] = @"C:\Omika\Data\DiagnosticsWorker\Checkpoint",
|
|
["Observability:Remote:Directory"] = @"C:\Omika\Data\Api\Diagnostics\Jsonl",
|
|
// Surcharge standard (serveur) : prime sur Diagnostics:ConnectionString.
|
|
["ConnectionStrings:DiagnosticsDatabase"] = "Host=localhost;Database=omika_diagnostics;Username=diagnostics_worker"
|
|
})
|
|
.Build();
|
|
|
|
// Reproduit Program.cs du Diagnostics Worker, avec validation DI stricte
|
|
// (ValidateOnBuild + ValidateScopes) pour piéger les dépendances non
|
|
// enregistrées.
|
|
return new HostBuilder()
|
|
.UseDefaultServiceProvider(options =>
|
|
{
|
|
options.ValidateOnBuild = true;
|
|
options.ValidateScopes = true;
|
|
})
|
|
.ConfigureServices(services =>
|
|
{
|
|
services.AddLogging();
|
|
services.AddOmikaDiagnosticData(configuration);
|
|
services.AddHostedService<DiagnosticImportWorker>();
|
|
services.AddHostedService<DiagnosticRetentionWorker>();
|
|
services.AddHostedService<DiagnosticTelemetryRetentionWorker>();
|
|
})
|
|
.Build();
|
|
}
|
|
}
|