Premiere commit - Omika
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
using Xunit;
|
||||
|
||||
namespace Omika.Tests.Runtime;
|
||||
|
||||
/// <summary>
|
||||
/// Collection de tests partageant l'état statique global
|
||||
/// <see cref="Omika.Core.Runtime.ApplicationRuntimeContext"/>.
|
||||
///
|
||||
/// xUnit exécute les tests d'une même collection séquentiellement, ce qui évite
|
||||
/// que des tests manipulant le contexte statique global (Reset/Configure/
|
||||
/// SetDetectedVersion) interfèrent entre eux lorsqu'ils s'exécutent en parallèle.
|
||||
/// </summary>
|
||||
[CollectionDefinition("ApplicationRuntimeContext")]
|
||||
public class ApplicationRuntimeContextCollection
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Omika.Core.Abstractions;
|
||||
using Omika.Core.Compatibility;
|
||||
using Omika.Core.Runtime;
|
||||
using Omika.Data;
|
||||
using Omika.Data.Runtime;
|
||||
using Omika.Data.SchemaDetection;
|
||||
|
||||
namespace Omika.Tests.Runtime;
|
||||
|
||||
[Collection("ApplicationRuntimeContext")]
|
||||
public class DatabaseRuntimeInitializerTests
|
||||
{
|
||||
|
||||
// --- Auto + détecté Batik => succès --------------------------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_AutoWithDetectedBatik_ReturnsSuccess()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Auto);
|
||||
var detector = new FakeDetector(DatabaseSchemaVersion.Batik);
|
||||
var initializer = new DatabaseRuntimeInitializer(detector);
|
||||
|
||||
var result = await initializer.InitializeAsync();
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.True(ApplicationRuntimeContext.Current.IsBatik);
|
||||
Assert.False(ApplicationRuntimeContext.Current.IsOmika);
|
||||
Assert.Equal(DatabaseSchemaVersion.Batik, ApplicationRuntimeContext.Current.DetectedVersion);
|
||||
}
|
||||
|
||||
// --- Auto + détecté Omika => succès --------------------------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_AutoWithDetectedOmika_ReturnsSuccess()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Auto);
|
||||
var detector = new FakeDetector(DatabaseSchemaVersion.Omika);
|
||||
var initializer = new DatabaseRuntimeInitializer(detector);
|
||||
|
||||
var result = await initializer.InitializeAsync();
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.True(ApplicationRuntimeContext.Current.IsOmika);
|
||||
Assert.False(ApplicationRuntimeContext.Current.IsBatik);
|
||||
Assert.Equal(DatabaseSchemaVersion.Omika, ApplicationRuntimeContext.Current.DetectedVersion);
|
||||
}
|
||||
|
||||
// --- Batik + détecté Batik => succès -------------------------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_BatikWithDetectedBatik_ReturnsSuccess()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Batik);
|
||||
var detector = new FakeDetector(DatabaseSchemaVersion.Batik);
|
||||
var initializer = new DatabaseRuntimeInitializer(detector);
|
||||
|
||||
var result = await initializer.InitializeAsync();
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.True(ApplicationRuntimeContext.Current.IsBatik);
|
||||
Assert.Equal(DatabaseSchemaVersion.Batik, ApplicationRuntimeContext.Current.DetectedVersion);
|
||||
}
|
||||
|
||||
// --- Omika + détecté Omika => succès -------------------------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_OmikaWithDetectedOmika_ReturnsSuccess()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Omika);
|
||||
var detector = new FakeDetector(DatabaseSchemaVersion.Omika);
|
||||
var initializer = new DatabaseRuntimeInitializer(detector);
|
||||
|
||||
var result = await initializer.InitializeAsync();
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.True(ApplicationRuntimeContext.Current.IsOmika);
|
||||
Assert.Equal(DatabaseSchemaVersion.Omika, ApplicationRuntimeContext.Current.DetectedVersion);
|
||||
}
|
||||
|
||||
// --- Batik + détecté Omika => échec --------------------------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_BatikWithDetectedOmika_ReturnsFailureAndKeepsUnknown()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Batik);
|
||||
var detector = new FakeDetector(DatabaseSchemaVersion.Omika);
|
||||
var initializer = new DatabaseRuntimeInitializer(detector);
|
||||
|
||||
var result = await initializer.InitializeAsync();
|
||||
|
||||
Assert.True(result.IsFailure);
|
||||
Assert.NotEmpty(result.Errors);
|
||||
Assert.Equal(DatabaseSchemaVersion.Unknown, ApplicationRuntimeContext.Current.DetectedVersion);
|
||||
Assert.False(ApplicationRuntimeContext.Current.IsBatik);
|
||||
Assert.False(ApplicationRuntimeContext.Current.IsOmika);
|
||||
}
|
||||
|
||||
// --- Omika + détecté Batik => échec --------------------------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_OmikaWithDetectedBatik_ReturnsFailureAndKeepsUnknown()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Omika);
|
||||
var detector = new FakeDetector(DatabaseSchemaVersion.Batik);
|
||||
var initializer = new DatabaseRuntimeInitializer(detector);
|
||||
|
||||
var result = await initializer.InitializeAsync();
|
||||
|
||||
Assert.True(result.IsFailure);
|
||||
Assert.NotEmpty(result.Errors);
|
||||
Assert.Equal(DatabaseSchemaVersion.Unknown, ApplicationRuntimeContext.Current.DetectedVersion);
|
||||
Assert.False(ApplicationRuntimeContext.Current.IsBatik);
|
||||
Assert.False(ApplicationRuntimeContext.Current.IsOmika);
|
||||
}
|
||||
|
||||
// --- Unknown => échec ----------------------------------------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_DetectedUnknown_ReturnsFailureAndKeepsUnknown()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Auto);
|
||||
var detector = new FakeDetector(DatabaseSchemaVersion.Unknown);
|
||||
var initializer = new DatabaseRuntimeInitializer(detector);
|
||||
|
||||
var result = await initializer.InitializeAsync();
|
||||
|
||||
Assert.True(result.IsFailure);
|
||||
Assert.NotEmpty(result.Errors);
|
||||
Assert.Equal(DatabaseSchemaVersion.Unknown, ApplicationRuntimeContext.Current.DetectedVersion);
|
||||
Assert.False(ApplicationRuntimeContext.Current.IsBatik);
|
||||
Assert.False(ApplicationRuntimeContext.Current.IsOmika);
|
||||
}
|
||||
|
||||
// --- échec du détecteur => runtime non activé ----------------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_DetectorFailure_ReturnsFailureAndDoesNotActivateRuntime()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Auto);
|
||||
var detector = new FakeDetector(Result<DatabaseSchemaVersion>.Failure("Échec de lecture des métadonnées."));
|
||||
var initializer = new DatabaseRuntimeInitializer(detector);
|
||||
|
||||
var result = await initializer.InitializeAsync();
|
||||
|
||||
Assert.True(result.IsFailure);
|
||||
Assert.Contains("métadonnées", result.Errors[0], StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Equal(DatabaseSchemaVersion.Unknown, ApplicationRuntimeContext.Current.DetectedVersion);
|
||||
Assert.False(ApplicationRuntimeContext.Current.IsBatik);
|
||||
Assert.False(ApplicationRuntimeContext.Current.IsOmika);
|
||||
}
|
||||
|
||||
// --- cancellation => propagation correcte --------------------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_CancellationRequested_Propagates()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Auto);
|
||||
var detector = new FakeDetector(DatabaseSchemaVersion.Batik);
|
||||
var initializer = new DatabaseRuntimeInitializer(detector);
|
||||
using var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
|
||||
await Assert.ThrowsAnyAsync<OperationCanceledException>(
|
||||
() => initializer.InitializeAsync(cts.Token));
|
||||
}
|
||||
|
||||
// --- détecteur appelé une seule fois par initialisation ------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_DetectorCalledExactlyOnce()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Auto);
|
||||
var detector = new FakeDetector(DatabaseSchemaVersion.Omika);
|
||||
var initializer = new DatabaseRuntimeInitializer(detector);
|
||||
|
||||
await initializer.InitializeAsync();
|
||||
|
||||
Assert.Equal(1, detector.DetectCallCount);
|
||||
}
|
||||
|
||||
// --- DetectedVersion renseigné uniquement après succès -------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_DetectedVersionSetOnlyOnSuccess()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Omika);
|
||||
var detector = new FakeDetector(DatabaseSchemaVersion.Batik);
|
||||
var initializer = new DatabaseRuntimeInitializer(detector);
|
||||
|
||||
var result = await initializer.InitializeAsync();
|
||||
|
||||
Assert.True(result.IsFailure);
|
||||
Assert.Equal(DatabaseSchemaVersion.Unknown, ApplicationRuntimeContext.Current.DetectedVersion);
|
||||
}
|
||||
|
||||
// --- IsBatik correct après Batik -----------------------------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_AfterBatik_IsBatikTrue()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Auto);
|
||||
var initializer = new DatabaseRuntimeInitializer(new FakeDetector(DatabaseSchemaVersion.Batik));
|
||||
|
||||
await initializer.InitializeAsync();
|
||||
|
||||
Assert.True(ApplicationRuntimeContext.Current.IsBatik);
|
||||
Assert.False(ApplicationRuntimeContext.Current.IsOmika);
|
||||
}
|
||||
|
||||
// --- IsOmika correct après Omika -----------------------------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_AfterOmika_IsOmikaTrue()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Auto);
|
||||
var initializer = new DatabaseRuntimeInitializer(new FakeDetector(DatabaseSchemaVersion.Omika));
|
||||
|
||||
await initializer.InitializeAsync();
|
||||
|
||||
Assert.True(ApplicationRuntimeContext.Current.IsOmika);
|
||||
Assert.False(ApplicationRuntimeContext.Current.IsBatik);
|
||||
}
|
||||
|
||||
// --- capabilities cohérentes avec la version détectée --------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_AfterOmika_CapabilitiesReflectDetectedVersion()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Auto);
|
||||
var initializer = new DatabaseRuntimeInitializer(new FakeDetector(DatabaseSchemaVersion.Omika));
|
||||
|
||||
await initializer.InitializeAsync();
|
||||
|
||||
var capabilities = ApplicationRuntimeContext.Current.Capabilities;
|
||||
Assert.Equal(DatabaseSchemaVersion.Omika, capabilities.Version);
|
||||
Assert.True(capabilities.SupportsEntityGuids);
|
||||
Assert.True(capabilities.SupportsRoles);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_AfterBatik_CapabilitiesReflectDetectedVersion()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Auto);
|
||||
var initializer = new DatabaseRuntimeInitializer(new FakeDetector(DatabaseSchemaVersion.Batik));
|
||||
|
||||
await initializer.InitializeAsync();
|
||||
|
||||
var capabilities = ApplicationRuntimeContext.Current.Capabilities;
|
||||
Assert.Equal(DatabaseSchemaVersion.Batik, capabilities.Version);
|
||||
Assert.False(capabilities.SupportsEntityGuids);
|
||||
Assert.False(capabilities.SupportsRoles);
|
||||
}
|
||||
|
||||
// --- aucune sélection configurée utilisée comme version détectée ---------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_SelectionIsNeverUsedAsDetectedVersion()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
// Sélection Omika, mais la base réellement détectée est Batik.
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Omika);
|
||||
var initializer = new DatabaseRuntimeInitializer(new FakeDetector(DatabaseSchemaVersion.Batik));
|
||||
|
||||
var result = await initializer.InitializeAsync();
|
||||
|
||||
// La sélection ne doit jamais être prise pour la version détectée : échec.
|
||||
Assert.True(result.IsFailure);
|
||||
Assert.Equal(DatabaseSchemaVersion.Unknown, ApplicationRuntimeContext.Current.DetectedVersion);
|
||||
}
|
||||
|
||||
// --- aucun secret dans les messages d'erreur -----------------------------
|
||||
|
||||
[Fact]
|
||||
public async Task InitializeAsync_ErrorMessagesDoNotContainSecrets()
|
||||
{
|
||||
ApplicationRuntimeContext.Reset();
|
||||
ApplicationRuntimeContext.Configure(DatabaseSchemaSelection.Batik);
|
||||
var detector = new FakeDetector(DatabaseSchemaVersion.Omika);
|
||||
var initializer = new DatabaseRuntimeInitializer(detector);
|
||||
|
||||
var result = await initializer.InitializeAsync();
|
||||
|
||||
Assert.True(result.IsFailure);
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
Assert.DoesNotContain("password", error, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.DoesNotContain("pwd", error, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.DoesNotContain("connectionstring", error, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.DoesNotContain("dsn", error, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
// --- service d'initialisation enregistré en Scoped -----------------------
|
||||
|
||||
[Fact]
|
||||
public void AddOmikaData_RegistersInitializerAsScoped()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddOmikaData();
|
||||
|
||||
var descriptor = services.Single(d => d.ServiceType == typeof(IDatabaseRuntimeInitializer));
|
||||
|
||||
Assert.Equal(ServiceLifetime.Scoped, descriptor.Lifetime);
|
||||
Assert.Equal(typeof(DatabaseRuntimeInitializer), descriptor.ImplementationType);
|
||||
}
|
||||
|
||||
// --- Program utilise un scope correct pour les services Scoped -----------
|
||||
|
||||
[Fact]
|
||||
public void AddOmikaData_InitializerDependsOnScopedDetector()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddOmikaData();
|
||||
|
||||
var initializerDescriptor = services.Single(d => d.ServiceType == typeof(IDatabaseRuntimeInitializer));
|
||||
var detectorDescriptor = services.Single(d => d.ServiceType == typeof(IDatabaseSchemaDetector));
|
||||
|
||||
// L'initialisateur consomme le détecteur du scope courant : les deux sont Scoped.
|
||||
Assert.Equal(ServiceLifetime.Scoped, initializerDescriptor.Lifetime);
|
||||
Assert.Equal(ServiceLifetime.Scoped, detectorDescriptor.Lifetime);
|
||||
}
|
||||
|
||||
// --- Fake de détecteur ---------------------------------------------------
|
||||
|
||||
private sealed class FakeDetector : IDatabaseSchemaDetector
|
||||
{
|
||||
private readonly Result<DatabaseSchemaVersion> _result;
|
||||
|
||||
public FakeDetector(DatabaseSchemaVersion version)
|
||||
: this(Result<DatabaseSchemaVersion>.Success(version))
|
||||
{
|
||||
}
|
||||
|
||||
public FakeDetector(Result<DatabaseSchemaVersion> result)
|
||||
{
|
||||
_result = result;
|
||||
}
|
||||
|
||||
public int DetectCallCount { get; private set; }
|
||||
|
||||
public Task<Result<DatabaseSchemaVersion>> DetectAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
DetectCallCount++;
|
||||
return Task.FromResult(_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user