Disposing the test fixtures
All checks were successful
Dotnet build and test / build (push) Successful in 6m49s

This commit is contained in:
Paul Schneider 2026-08-29 04:00:10 +01:00
commit 243c0f2780
Signed by: notazof
GPG key ID: 1DD5D838E5343B06
5 changed files with 26 additions and 28 deletions

View file

@ -44,4 +44,4 @@ jobs:
- name: Test - name: Test
run: | run: |
echo "🚀 Lancement des tests..." echo "🚀 Lancement des tests..."
cd /src/_src && dotnet test --verbosity normal && echo "✅ Success !" cd /src/_src && dotnet test --verbosity normal && echo "✅ Success !" || echo "❌ Fail ($?)!"

View file

@ -14,15 +14,10 @@ namespace Yavsc.Blogs.Tests;
[Collection("JwtClaimMapping")] [Collection("JwtClaimMapping")]
public sealed class BlogApiMappedClaimsTests : public sealed class BlogApiMappedClaimsTests :
IClassFixture<MappedClaimsBlogsWebServerFixture>, IClassFixture<MappedClaimsBlogsWebServerFixture>
IBackendFixture
{ {
private readonly MappedClaimsBlogsWebServerFixture _fixture; private readonly MappedClaimsBlogsWebServerFixture _fixture;
public IReadOnlyList<string> Addresses => throw new NotImplementedException();
public IServiceProvider Services => throw new NotImplementedException();
public BlogApiMappedClaimsTests(MappedClaimsBlogsWebServerFixture fixture) public BlogApiMappedClaimsTests(MappedClaimsBlogsWebServerFixture fixture)
{ {
_fixture = fixture; _fixture = fixture;

View file

@ -25,7 +25,7 @@ public sealed class MappedClaimsBlogsWebServerFixture : IDisposable, IBackendFix
{ {
private readonly InMemoryDatabaseRoot _inMemoryRoot = new(); private readonly InMemoryDatabaseRoot _inMemoryRoot = new();
private readonly Dictionary<string, string> _savedInboundMap; private readonly Dictionary<string, string> _savedInboundMap;
private readonly WebApplication _app; private WebApplication? _app = null;
public MappedClaimsBlogsWebServerFixture() public MappedClaimsBlogsWebServerFixture()
{ {
@ -86,6 +86,7 @@ public sealed class MappedClaimsBlogsWebServerFixture : IDisposable, IBackendFix
public void Dispose() public void Dispose()
{ {
if (_app is null) return;
_app.StopAsync().GetAwaiter().GetResult(); _app.StopAsync().GetAwaiter().GetResult();
_app.DisposeAsync().AsTask().GetAwaiter().GetResult(); _app.DisposeAsync().AsTask().GetAwaiter().GetResult();
@ -96,6 +97,7 @@ public sealed class MappedClaimsBlogsWebServerFixture : IDisposable, IBackendFix
} }
} }
private sealed class NoopFileSystemAuthManager : IFileSystemAuthManager private sealed class NoopFileSystemAuthManager : IFileSystemAuthManager
{ {
public FileAccessRight GetFilePathAccess(System.Security.Claims.ClaimsPrincipal user, string fileRelativePath) public FileAccessRight GetFilePathAccess(System.Security.Claims.ClaimsPrincipal user, string fileRelativePath)

View file

@ -1,5 +1,4 @@
public interface IBackendFixture : IDisposable
public interface IBackendFixture
{ {
/// <summary> /// <summary>
/// The addresses the fixture bound to. /// The addresses the fixture bound to.
@ -10,4 +9,5 @@ public interface IBackendFixture
/// The service provider for the fixture host. /// The service provider for the fixture host.
/// </summary> /// </summary>
IServiceProvider Services { get; } IServiceProvider Services { get; }
} }

View file

@ -30,14 +30,13 @@ namespace Yavsc.Tests.Shared;
/// mapping are the responsibility of the subclass, through /// mapping are the responsibility of the subclass, through
/// <see cref="BuildApp"/>. /// <see cref="BuildApp"/>.
/// </summary> /// </summary>
public abstract class WebHostFixture : IDisposable, IBackendFixture public abstract class WebHostFixture : IBackendFixture
{ {
private static readonly Lazy<X509Certificate2> _selfSignedCertificate = private static readonly Lazy<X509Certificate2> _selfSignedCertificate =
new Lazy<X509Certificate2>(CreateSelfSignedCertificate); new Lazy<X509Certificate2>(CreateSelfSignedCertificate);
private static readonly object _sync = new object(); private static readonly object _sync = new object();
private static WebApplication? _app; private static WebApplication? _app;
private static bool _isInitialized; private static bool _isInitialized;
private static int _instanceCount;
private static readonly List<string> _sharedAddresses = new(); private static readonly List<string> _sharedAddresses = new();
private static IServiceProvider? _sharedServices; private static IServiceProvider? _sharedServices;
@ -57,11 +56,12 @@ public abstract class WebHostFixture : IDisposable, IBackendFixture
/// successfully and the host is running.</summary> /// successfully and the host is running.</summary>
public bool IsInitialized { get; private set; } public bool IsInitialized { get; private set; }
#pragma warning disable CS8618 // Un champ non-nullable doit contenir une valeur autre que Null lors de la fermeture du constructeur. Envisagez dajouter le modificateur « required » ou de déclarer le champ comme pouvant accepter la valeur Null.
protected WebHostFixture() protected WebHostFixture()
#pragma warning restore CS8618 // Un champ non-nullable doit contenir une valeur autre que Null lors de la fermeture du constructeur. Envisagez dajouter le modificateur « required » ou de déclarer le champ comme pouvant accepter la valeur Null.
{ {
lock (_sync) lock (_sync)
{ {
_instanceCount++;
if (!_isInitialized) if (!_isInitialized)
{ {
InitializeAsync().GetAwaiter().GetResult(); InitializeAsync().GetAwaiter().GetResult();
@ -110,6 +110,8 @@ public abstract class WebHostFixture : IDisposable, IBackendFixture
/// listen port.</summary> /// listen port.</summary>
protected virtual int HttpsPort => 5101; protected virtual int HttpsPort => 5101;
public WebApplication App { get; private set; }
private async Task InitializeAsync() private async Task InitializeAsync()
{ {
var builder = WebApplication.CreateBuilder(); var builder = WebApplication.CreateBuilder();
@ -122,14 +124,14 @@ public abstract class WebHostFixture : IDisposable, IBackendFixture
}); });
}); });
var app = BuildApp(builder); this.App = BuildApp(builder);
app = await ConfigurePipelineAsync(app); this.App = await ConfigurePipelineAsync(this.App);
await app.StartAsync(); await this.App.StartAsync();
_app = app; _app = this.App;
_sharedServices = app.Services; _sharedServices = this.App.Services;
var server = app.Services.GetRequiredService<IServer>(); var server = this.App.Services.GetRequiredService<IServer>();
var addressFeatures = server.Features.Get<IServerAddressesFeature>(); var addressFeatures = server.Features.Get<IServerAddressesFeature>();
_sharedAddresses.Clear(); _sharedAddresses.Clear();
if (addressFeatures?.Addresses is not null) if (addressFeatures?.Addresses is not null)
@ -147,15 +149,14 @@ public abstract class WebHostFixture : IDisposable, IBackendFixture
{ {
lock (_sync) lock (_sync)
{ {
_instanceCount--; if (!IsInitialized)
if (_instanceCount == 0 && _app is not null) throw new InvalidOperationException("Cannot tear down a fixture that has not been initialized.");
{ this.App.StopAsync().GetAwaiter().GetResult();
_app.StopAsync().GetAwaiter().GetResult(); IsInitialized = false;
_app = null;
_isInitialized = false; _isInitialized = false;
_sharedAddresses.Clear(); _sharedAddresses.Clear();
_sharedServices = null; _sharedServices = null;
}
} }
} }