fixe tests
Some checks failed
Dotnet build and test / build (pull_request) Failing after 6m27s

This commit is contained in:
Paul Schneider 2026-09-12 16:49:36 +01:00
commit d92456e141
Signed by: notazof
GPG key ID: 1DD5D838E5343B06
6 changed files with 95 additions and 36 deletions

View file

@ -10,10 +10,10 @@ namespace Yavsc.Org.Tests
{ {
[Collection("Yavsc Server")] [Collection("Yavsc Server")]
[Trait("regression", "oui")] [Trait("regression", "oui")]
public class BaseTestContext : IClassFixture<WebServerFixture>, IDisposable public abstract class BaseTestContext : IClassFixture<WebServerFixture>, IDisposable
{ {
public readonly WebServerFixture _serverFixture; protected readonly WebServerFixture _serverFixture;
private readonly ITestOutputHelper _output; protected readonly ITestOutputHelper _output;
public BaseTestContext(ITestOutputHelper output, WebServerFixture fixture) public BaseTestContext(ITestOutputHelper output, WebServerFixture fixture)
{ {

View file

@ -84,9 +84,11 @@ namespace Yavsc.Org.Tests
[Fact] [Fact]
public async Task GetOpenIdConfiguration_returns_ok() public async Task GetOpenIdConfiguration_returns_ok()
{ {
using var client = _serverFixture.CreateHttpClient(); using var client = CreateHttpClient();
var response = await GetRaw(client, "/.well-known/openid-configuration"); var response = await GetRaw(client, "/.well-known/openid-configuration");
var payload = await response.Content.ReadAsStringAsync(); var payload = await response.Content.ReadAsStringAsync(
TestContext.Current.CancellationToken
);
Assert.True( Assert.True(
response.IsSuccessStatusCode, response.IsSuccessStatusCode,

View file

@ -1,14 +1,8 @@
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Yavsc.Models;
namespace Yavsc.Org.Tests.Mandatory namespace Yavsc.Org.Tests.Mandatory
{[Collection("Database")] {[Collection("Database")]
[Trait("regression", "II")] [Trait("regression", "II")]
[Trait("dev", "wip")] [Trait("dev", "wip")]
public class Database: IClassFixture<WebServerFixture>, IDisposable public class Database : IClassFixture<WebServerFixture>
{ {
readonly ITestOutputHelper output; readonly ITestOutputHelper output;
readonly WebServerFixture _serverFixture; readonly WebServerFixture _serverFixture;
@ -24,15 +18,6 @@ namespace Yavsc.Org.Tests.Mandatory
/// Install all our migrations in a fresh new database. /// Install all our migrations in a fresh new database.
/// </summary> /// </summary>
public void Dispose()
{
if (_serverFixture!=null)
{
_serverFixture.Dispose();
}
}
[Fact] [Fact]
public void TestDatabaseMigration() public void TestDatabaseMigration()
{ {

View file

@ -14,11 +14,13 @@ namespace Yavsc.Org.Tests.Smoke;
/// <c>doc/architecture/decoupage-organisation.md</c>. The smoke /// <c>doc/architecture/decoupage-organisation.md</c>. The smoke
/// here asserts the front-end side of the BC. /// here asserts the front-end side of the BC.
/// </summary> /// </summary>
public class BlogSmokeTests : SmokeTestBase, IClassFixture<TestWebApplicationFactory> public class BlogSmokeTests : BaseTestContext, IClassFixture<TestWebApplicationFactory>
{ {
private readonly TestWebApplicationFactory _factory; private readonly TestWebApplicationFactory _factory;
public BlogSmokeTests(TestWebApplicationFactory factory) public BlogSmokeTests(TestWebApplicationFactory factory, ITestOutputHelper output,
WebServerFixture webServerFixture)
: base(output, webServerFixture)
{ {
_factory = factory; _factory = factory;
} }

View file

@ -63,6 +63,7 @@ public sealed class WebServerFixture : WebHostFixture
private static string? _sharedTestingUserName; private static string? _sharedTestingUserName;
private static string? _sharedTestingUserPassword; private static string? _sharedTestingUserPassword;
private static string? _sharedTestingUserEmail; private static string? _sharedTestingUserEmail;
private static string? _sharedHttpsAuthority;
private static RecordingSmtpClientFactory? _sharedSmtpClientFactory; private static RecordingSmtpClientFactory? _sharedSmtpClientFactory;
public IConfiguration? Configuration { get; private set; } public IConfiguration? Configuration { get; private set; }
@ -78,10 +79,19 @@ public sealed class WebServerFixture : WebHostFixture
public RecordingSmtpClientFactory? SmtpClientFactory { get; private set; } public RecordingSmtpClientFactory? SmtpClientFactory { get; private set; }
public ILogger? Logger { get; internal set; } public ILogger? Logger { get; internal set; }
public string? HttpsAuthority => Addresses.FirstOrDefault(u => u.StartsWith("https:")); public string? HttpsAuthority { get; private set; }
protected override WebApplicationOptions CreateBuilderOptions()
{
return new WebApplicationOptions
{
ApplicationName = typeof(Yavsc.Program).Assembly.GetName().Name
};
}
protected override WebApplication BuildApp(WebApplicationBuilder builder) protected override WebApplication BuildApp(WebApplicationBuilder builder)
{ {
var authority = $"https://localhost:{_httpsPort}"; HttpsAuthority = $"https://localhost:{HttpsPort}";
// WebApplication.CreateBuilder defaults WebRootPath to // WebApplication.CreateBuilder defaults WebRootPath to
// {ContentRoot}/wwwroot. The test assembly runs from // {ContentRoot}/wwwroot. The test assembly runs from
@ -100,7 +110,7 @@ public sealed class WebServerFixture : WebHostFixture
["Smtp:Port"] = "465", ["Smtp:Port"] = "465",
["Smtp:UserName"] = "test-user", ["Smtp:UserName"] = "test-user",
["Smtp:Password"] = "test-pass", ["Smtp:Password"] = "test-pass",
["Site:Authority"] = authority ["Site:Authority"] = HttpsAuthority
}); });
Configuration = builder.Configuration; Configuration = builder.Configuration;
@ -183,6 +193,7 @@ public sealed class WebServerFixture : WebHostFixture
_sharedTestingUserName = TestingUserName; _sharedTestingUserName = TestingUserName;
_sharedTestingUserPassword = TestingUserPassword; _sharedTestingUserPassword = TestingUserPassword;
_sharedTestingUserEmail = TestingUserEmail; _sharedTestingUserEmail = TestingUserEmail;
_sharedHttpsAuthority = HttpsAuthority;
_sharedLogger = app.Services.GetRequiredService<ILoggerFactory>().CreateLogger<WebServerFixture>(); _sharedLogger = app.Services.GetRequiredService<ILoggerFactory>().CreateLogger<WebServerFixture>();
Logger = _sharedLogger; Logger = _sharedLogger;
SmtpClientFactory = smtpFactory; SmtpClientFactory = smtpFactory;
@ -195,13 +206,42 @@ public sealed class WebServerFixture : WebHostFixture
using var scope = Services.CreateScope(); using var scope = Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>(); var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
db.Database.EnsureDeleted(); db.Database.EnsureDeleted();
db.Database.EnsureCreated();
if (db.Database.IsRelational()) if (db.Database.IsRelational())
{ {
db.Database.Migrate(); db.Database.Migrate();
ReseedAuthTestData(scope);
return; return;
} }
ReseedAuthTestData(scope);
}
db.Database.EnsureCreated(); private void ReseedAuthTestData(IServiceScope scope)
{
TestingUserName ??= "Tester";
TestingUserPassword ??= "Test123!";
TestingUserEmail ??= "test@no-reply.com";
TestClientId ??= "testClientId";
TestClientSecret ??= Guid.CreateVersion7().ToString();
TestingUser = null;
EnsureUser(TestingUserName, TestingUserPassword, TestingUserEmail, scope);
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
TestingUser = db.Users.FirstOrDefault(u => u.UserName == TestingUserName);
var configDb = scope.ServiceProvider.GetRequiredService<IdentityServer8.EntityFramework.DbContexts.ConfigurationDbContext>();
var hasClient = configDb.Set<Client>().Any(c => c.ClientId == TestClientId);
if (!hasClient)
{
AddAuthorizedClient(scope, TestClientId, TestClientSecret);
}
_sharedTestClientId = TestClientId;
_sharedTestClientSecret = TestClientSecret;
_sharedTestingUserName = TestingUserName;
_sharedTestingUserPassword = TestingUserPassword;
_sharedTestingUserEmail = TestingUserEmail;
} }
protected override async Task<WebApplication> ConfigurePipelineAsync(WebApplication app) protected override async Task<WebApplication> ConfigurePipelineAsync(WebApplication app)
@ -226,6 +266,7 @@ public sealed class WebServerFixture : WebHostFixture
TestingUserName = _sharedTestingUserName; TestingUserName = _sharedTestingUserName;
TestingUserPassword = _sharedTestingUserPassword; TestingUserPassword = _sharedTestingUserPassword;
TestingUserEmail = _sharedTestingUserEmail; TestingUserEmail = _sharedTestingUserEmail;
HttpsAuthority = _sharedHttpsAuthority;
SmtpClientFactory = _sharedSmtpClientFactory; SmtpClientFactory = _sharedSmtpClientFactory;
Configuration = _sharedConfiguration; Configuration = _sharedConfiguration;
SiteSettings = _sharedSiteSettings; SiteSettings = _sharedSiteSettings;

View file

@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System.Net; using System.Net;
using System.Runtime.Loader;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
@ -37,6 +38,7 @@ public abstract class WebHostFixture : IBackendFixture
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 bool _shutdownHooksRegistered;
private static int _instanceCount; 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;
@ -63,6 +65,8 @@ public abstract class WebHostFixture : IBackendFixture
{ {
lock (_sync) lock (_sync)
{ {
RegisterShutdownHooks();
if (!_isInitialized) if (!_isInitialized)
{ {
InitializeAsync().GetAwaiter().GetResult(); InitializeAsync().GetAwaiter().GetResult();
@ -114,11 +118,19 @@ public abstract class WebHostFixture : IBackendFixture
/// listen port.</summary> /// listen port.</summary>
protected virtual int HttpsPort => 5101; protected virtual int HttpsPort => 5101;
/// <summary>Options used to create the WebApplicationBuilder.
/// Derived fixtures can override (for example, to set
/// ApplicationName for MVC controller discovery).</summary>
protected virtual WebApplicationOptions CreateBuilderOptions()
{
return new WebApplicationOptions();
}
public WebApplication App { get; private set; } public WebApplication App { get; private set; }
private async Task InitializeAsync() private async Task InitializeAsync()
{ {
var builder = WebApplication.CreateBuilder(); var builder = WebApplication.CreateBuilder(CreateBuilderOptions());
builder.WebHost.ConfigureKestrel(options => builder.WebHost.ConfigureKestrel(options =>
{ {
@ -158,23 +170,40 @@ public abstract class WebHostFixture : IBackendFixture
_instanceCount--; _instanceCount--;
} }
IsInitialized = false; IsInitialized = _isInitialized;
if (_instanceCount > 0) // Keep the shared host alive for the whole test process.
// Disposing per class/collection can race with other test
// classes and intermittently drop the listener mid-run.
}
}
private static void RegisterShutdownHooks()
{
if (_shutdownHooksRegistered)
{
return;
}
AppDomain.CurrentDomain.ProcessExit += (_, __) => ShutdownSharedHost();
AssemblyLoadContext.Default.Unloading += _ => ShutdownSharedHost();
_shutdownHooksRegistered = true;
}
private static void ShutdownSharedHost()
{
lock (_sync)
{
if (!_isInitialized || _app is null)
{ {
return; return;
} }
if (!_isInitialized) _app.StopAsync().GetAwaiter().GetResult();
{
return;
}
_app?.StopAsync().GetAwaiter().GetResult();
_app = null; _app = null;
_isInitialized = false; _isInitialized = false;
_sharedAddresses.Clear();
_sharedServices = null; _sharedServices = null;
_sharedAddresses.Clear();
} }
} }