Skip to content

Commit bfecdeb

Browse files
committed
Add throttling on integration tests that are running in parallel
1 parent d1fb4d0 commit bfecdeb

File tree

2 files changed

+34
-13
lines changed

2 files changed

+34
-13
lines changed

test/TestBuildingBlocks/IntegrationTest.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@
22
using System.Text;
33
using System.Text.Json;
44
using JsonApiDotNetCore.Middleware;
5+
using Xunit;
56

67
namespace TestBuildingBlocks;
78

89
/// <summary>
9-
/// A base class for tests that conveniently enables to execute HTTP requests against JSON:API endpoints.
10+
/// A base class for tests that conveniently enables to execute HTTP requests against JSON:API endpoints. It throttles tests that are running in parallel
11+
/// to avoid exceeding the maximum active database connections.
1012
/// </summary>
11-
public abstract class IntegrationTest
13+
public abstract class IntegrationTest : IAsyncLifetime
1214
{
15+
private static readonly SemaphoreSlim ThrottleSemaphore = new(64);
16+
1317
protected abstract JsonSerializerOptions SerializerOptions { get; }
1418

1519
public async Task<(HttpResponseMessage httpResponse, TResponseDocument responseDocument)> ExecuteHeadAsync<TResponseDocument>(string requestUrl,
@@ -105,4 +109,15 @@ public abstract class IntegrationTest
105109
throw new FormatException($"Failed to deserialize response body to JSON:\n{responseText}", exception);
106110
}
107111
}
112+
113+
public async Task InitializeAsync()
114+
{
115+
await ThrottleSemaphore.WaitAsync();
116+
}
117+
118+
public virtual Task DisposeAsync()
119+
{
120+
_ = ThrottleSemaphore.Release();
121+
return Task.CompletedTask;
122+
}
108123
}

test/TestBuildingBlocks/IntegrationTestContext.cs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace TestBuildingBlocks;
2424
/// The Entity Framework Core database context, which can be defined in the test project or API project.
2525
/// </typeparam>
2626
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
27-
public class IntegrationTestContext<TStartup, TDbContext> : IntegrationTest, IDisposable
27+
public class IntegrationTestContext<TStartup, TDbContext> : IntegrationTest
2828
where TStartup : class
2929
where TDbContext : TestableDbContext
3030
{
@@ -103,16 +103,6 @@ private WebApplicationFactory<TStartup> CreateFactory()
103103
return factoryWithConfiguredContentRoot;
104104
}
105105

106-
public void Dispose()
107-
{
108-
if (_lazyFactory.IsValueCreated)
109-
{
110-
RunOnDatabaseAsync(async dbContext => await dbContext.Database.EnsureDeletedAsync()).Wait();
111-
112-
_lazyFactory.Value.Dispose();
113-
}
114-
}
115-
116106
public void ConfigureLogging(Action<ILoggingBuilder> loggingConfiguration)
117107
{
118108
_loggingConfiguration = loggingConfiguration;
@@ -136,6 +126,22 @@ public async Task RunOnDatabaseAsync(Func<TDbContext, Task> asyncAction)
136126
await asyncAction(dbContext);
137127
}
138128

129+
public override async Task DisposeAsync()
130+
{
131+
try
132+
{
133+
if (_lazyFactory.IsValueCreated)
134+
{
135+
await RunOnDatabaseAsync(async dbContext => await dbContext.Database.EnsureDeletedAsync());
136+
await _lazyFactory.Value.DisposeAsync();
137+
}
138+
}
139+
finally
140+
{
141+
await base.DisposeAsync();
142+
}
143+
}
144+
139145
private sealed class IntegrationTestWebApplicationFactory : WebApplicationFactory<TStartup>
140146
{
141147
private Action<ILoggingBuilder>? _loggingConfiguration;

0 commit comments

Comments
 (0)