Skip to content

Commit c4445d2

Browse files
fix(tests): serialize SQLite EnsureCreated and disable auto redirect in functional tests
Add a static SemaphoreSlim gate around EnsureCreatedHostedService.StartAsync so parallel host startup cannot race while creating schema in shared in-memory SQLite. Also use CreateClientWithoutAutoRedirect in FunctionalTests so redirect handling stays explicit in GetFollowingGetRedirectsAsync.
1 parent dff58d7 commit c4445d2

2 files changed

Lines changed: 17 additions & 7 deletions

File tree

EssentialCSharp.Web.Tests/FunctionalTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class FunctionalTests : IntegrationTestBase
1313
[Arguments("/alive")]
1414
public async Task WhenTheApplicationStarts_ItCanLoadLoadPages(string relativeUrl)
1515
{
16-
using HttpClient client = Factory.CreateClient();
16+
using HttpClient client = CreateClientWithoutAutoRedirect();
1717
using HttpResponseMessage response = await GetFollowingGetRedirectsAsync(client, relativeUrl);
1818

1919
await Assert.That(response.StatusCode).IsEqualTo(HttpStatusCode.OK);
@@ -29,7 +29,7 @@ public async Task WhenTheApplicationStarts_ItCanLoadLoadPages(string relativeUrl
2929
[Arguments("/about?someOtherParam=value")]
3030
public async Task WhenPagesAreAccessed_TheyReturnHtml(string relativeUrl)
3131
{
32-
using HttpClient client = Factory.CreateClient();
32+
using HttpClient client = CreateClientWithoutAutoRedirect();
3333
using HttpResponseMessage response = await GetFollowingGetRedirectsAsync(client, relativeUrl);
3434

3535
await Assert.That(response.StatusCode).IsEqualTo(HttpStatusCode.OK);
@@ -45,7 +45,7 @@ public async Task WhenPagesAreAccessed_TheyReturnHtml(string relativeUrl)
4545
[Test]
4646
public async Task WhenTheApplicationStarts_NonExistingPage_GivesCorrectStatusCode()
4747
{
48-
using HttpClient client = Factory.CreateClient();
48+
using HttpClient client = CreateClientWithoutAutoRedirect();
4949
using HttpResponseMessage response = await GetFollowingGetRedirectsAsync(client, "/non-existing-page1234");
5050

5151
await Assert.That(response.StatusCode).IsEqualTo(HttpStatusCode.NotFound);

EssentialCSharp.Web.Tests/WebApplicationFactory.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
using Microsoft.Extensions.DependencyInjection;
1010
using Microsoft.Extensions.DependencyInjection.Extensions;
1111
using Microsoft.Extensions.Hosting;
12+
using System.Threading;
1213

1314
namespace EssentialCSharp.Web.Tests;
1415

1516
public sealed class WebApplicationFactory : TestWebApplicationFactory<Program>
1617
{
18+
private static readonly SemaphoreSlim SchemaInitializationGate = new(1, 1);
1719
// One GUID per factory instance → each factory gets its own isolated in-memory database.
1820
private readonly string _sqlConnectionString =
1921
$"DataSource=file:{Guid.NewGuid():N}?mode=memory&cache=shared";
@@ -129,10 +131,18 @@ private sealed class EnsureCreatedHostedService(IServiceProvider serviceProvider
129131
{
130132
public async Task StartAsync(CancellationToken cancellationToken)
131133
{
132-
using IServiceScope scope = serviceProvider.CreateScope();
133-
EssentialCSharpWebContext dbContext =
134-
scope.ServiceProvider.GetRequiredService<EssentialCSharpWebContext>();
135-
await dbContext.Database.EnsureCreatedAsync(cancellationToken);
134+
await SchemaInitializationGate.WaitAsync(cancellationToken);
135+
try
136+
{
137+
using IServiceScope scope = serviceProvider.CreateScope();
138+
EssentialCSharpWebContext dbContext =
139+
scope.ServiceProvider.GetRequiredService<EssentialCSharpWebContext>();
140+
await dbContext.Database.EnsureCreatedAsync(cancellationToken);
141+
}
142+
finally
143+
{
144+
SchemaInitializationGate.Release();
145+
}
136146
}
137147

138148
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;

0 commit comments

Comments
 (0)