Skip to content

Commit 7fdc4e2

Browse files
committed
Add test containers for local test runs
1 parent 4f42a9d commit 7fdc4e2

11 files changed

Lines changed: 138 additions & 10 deletions

.github/workflows/ci.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
strategy:
1919
matrix:
2020
os: [windows-latest, ubuntu-latest]
21-
test-category: [ Default, SqlServer, AzureServiceBus, RabbitMQ, AzureStorageQueues, MSMQ, SQS, PrimaryRavenAcceptance, PrimaryRavenPersistence, PostgreSQL, IBMMQ ]
21+
test-category: [ Default, SqlServer, AzureServiceBus, RabbitMQ, AzureStorageQueues, MSMQ, SQS, PrimaryRavenAcceptance, PrimaryRavenPersistence, PostgreSQL, IBMMQ, PrimarySqlServerPersistence, PrimaryPostgreSqlPersistence ]
2222
include:
2323
- os: windows-latest
2424
os-name: Windows
@@ -29,6 +29,8 @@ jobs:
2929
test-category: MSMQ
3030
- os: windows-latest
3131
test-category: IBMMQ
32+
- os: windows-latest
33+
test-category: PrimaryPostgreSqlPersistence
3234
fail-fast: false
3335
steps:
3436
- name: Check for secrets
@@ -75,6 +77,12 @@ jobs:
7577
with:
7678
connection-string-env-var: ServiceControl_TransportTests_SQL_ConnectionString
7779
catalog: nservicebus
80+
- name: Setup SQL Server (persistence)
81+
uses: Particular/install-sql-server-action@v1.4.0
82+
if: matrix.test-category == 'PrimarySqlServerPersistence'
83+
with:
84+
connection-string-env-var: ServiceControl_Persistence_SqlServer_ConnectionString
85+
catalog: ServiceControl
7886
- name: Setup PostgreSQL
7987
uses: Particular/setup-postgres-action@v1.1.0
8088
if: matrix.test-category == 'PostgreSQL'

src/Directory.Packages.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@
7575
<PackageVersion Include="PropertyChanging.Fody" Version="1.31.0" />
7676
<PackageVersion Include="PublicApiGenerator" Version="11.5.4" />
7777
<PackageVersion Include="RavenDB.Embedded" Version="6.2.17" />
78+
<PackageVersion Include="Testcontainers.MsSql" Version="4.13.0" />
79+
<PackageVersion Include="Testcontainers.PostgreSql" Version="4.13.0" />
7880
<PackageVersion Include="ReactiveUI.WPF" Version="22.3.1" />
7981
<PackageVersion Include="Seq.Extensions.Logging" Version="9.0.0" />
8082
<PackageVersion Include="ServiceControl.Contracts" Version="5.1.0" />

src/ServiceControl.Persistence.Tests.PostgreSql/PersistenceTestsContext.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,17 @@ namespace ServiceControl.Persistence.Tests;
88

99
public class PersistenceTestsContext : IPersistenceTestsContext
1010
{
11-
public Task Setup(IHostApplicationBuilder hostBuilder)
11+
public async Task Setup(IHostApplicationBuilder hostBuilder)
1212
{
13-
PersistenceSettings = new PostgreSqlPersisterSettings()
13+
PersistenceSettings = new PostgreSqlPersisterSettings
1414
{
15-
ConnectionString = "Host=localhost;Database=ServiceControl;Username=postgres;Password=postgres"
15+
ConnectionString = await PostgreSqlSharedContainer.GetConnectionStringAsync()
1616
};
1717

1818
var persistence = new PostgreSqlPersistenceConfiguration().Create(PersistenceSettings);
1919

2020
persistence.AddPersistence(hostBuilder.Services);
2121
persistence.AddInstaller(hostBuilder.Services);
22-
return Task.CompletedTask;
2322
}
2423

2524
public async Task PostSetup(IHost host)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
namespace ServiceControl.Persistence.Tests;
2+
3+
using System;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using Testcontainers.PostgreSql;
7+
8+
static class PostgreSqlSharedContainer
9+
{
10+
public static async Task<string> GetConnectionStringAsync(CancellationToken ct = default)
11+
{
12+
var envConnStr = Environment.GetEnvironmentVariable("ServiceControl_Persistence_PostgreSql_ConnectionString");
13+
if (!string.IsNullOrEmpty(envConnStr))
14+
{
15+
return envConnStr;
16+
}
17+
18+
if (container != null)
19+
{
20+
return container.GetConnectionString();
21+
}
22+
23+
await semaphore.WaitAsync(ct);
24+
try
25+
{
26+
container ??= await StartContainerAsync(ct);
27+
return container.GetConnectionString();
28+
}
29+
finally
30+
{
31+
semaphore.Release();
32+
}
33+
}
34+
35+
public static async Task Stop() => await (container?.DisposeAsync() ?? ValueTask.CompletedTask);
36+
37+
static async Task<PostgreSqlContainer> StartContainerAsync(CancellationToken ct)
38+
{
39+
var c = new PostgreSqlBuilder("postgres:16-alpine")
40+
.Build();
41+
await c.StartAsync(ct);
42+
return c;
43+
}
44+
45+
static PostgreSqlContainer container;
46+
static readonly SemaphoreSlim semaphore = new(1, 1);
47+
}

src/ServiceControl.Persistence.Tests.PostgreSql/ServiceControl.Persistence.Tests.PostgreSql.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
<PackageReference Include="NUnit3TestAdapter" />
2222
<PackageReference Include="Particular.Approvals" />
2323
<PackageReference Include="PublicApiGenerator" />
24+
<PackageReference Include="Testcontainers.PostgreSql" />
2425
</ItemGroup>
2526

2627
<ItemGroup>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace ServiceControl;
2+
3+
using System.Threading.Tasks;
4+
using NUnit.Framework;
5+
using Persistence.Tests;
6+
7+
[SetUpFixture]
8+
public class StopSharedPostgreSql
9+
{
10+
[OneTimeTearDown]
11+
public async Task Teardown() => await PostgreSqlSharedContainer.Stop();
12+
}

src/ServiceControl.Persistence.Tests.SqlServer/PersistenceTestsContext.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,17 @@ namespace ServiceControl.Persistence.Tests;
88

99
public class PersistenceTestsContext : IPersistenceTestsContext
1010
{
11-
public Task Setup(IHostApplicationBuilder hostBuilder)
11+
public async Task Setup(IHostApplicationBuilder hostBuilder)
1212
{
13-
PersistenceSettings = new SqlServerPersisterSettings()
13+
PersistenceSettings = new SqlServerPersisterSettings
1414
{
15-
ConnectionString = "Server=localhost;Database=ServiceControl;User=sa;Password=Password1!;TrustServerCertificate=True"
15+
ConnectionString = await SqlServerSharedContainer.GetConnectionStringAsync()
1616
};
1717

1818
var persistence = new SqlServerPersistenceConfiguration().Create(PersistenceSettings);
1919

2020
persistence.AddPersistence(hostBuilder.Services);
2121
persistence.AddInstaller(hostBuilder.Services);
22-
return Task.CompletedTask;
2322
}
2423

2524
public async Task PostSetup(IHost host)

src/ServiceControl.Persistence.Tests.SqlServer/ScrachTestDbContainer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ public async Task TestDbOperation()
1515
var db = scope.ServiceProvider.GetRequiredService<SqlServerServiceControlDbContext>();
1616

1717
var result = await db.Database.ExecuteSqlAsync($"SELECT 1 as Hello");
18-
Assert.That(result, Is.EqualTo(1));
18+
Assert.That(result, Is.EqualTo(-1));
1919
}
2020
}

src/ServiceControl.Persistence.Tests.SqlServer/ServiceControl.Persistence.Tests.SqlServer.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
<PackageReference Include="NUnit3TestAdapter" />
2222
<PackageReference Include="Particular.Approvals" />
2323
<PackageReference Include="PublicApiGenerator" />
24+
<PackageReference Include="Testcontainers.MsSql" />
2425
</ItemGroup>
2526

2627
<ItemGroup>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
namespace ServiceControl.Persistence.Tests;
2+
3+
using System;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using Testcontainers.MsSql;
7+
8+
static class SqlServerSharedContainer
9+
{
10+
public static async Task<string> GetConnectionStringAsync(CancellationToken ct = default)
11+
{
12+
var envConnStr = Environment.GetEnvironmentVariable("ServiceControl_Persistence_SqlServer_ConnectionString");
13+
if (!string.IsNullOrEmpty(envConnStr))
14+
{
15+
return envConnStr;
16+
}
17+
18+
if (container != null)
19+
{
20+
return container.GetConnectionString();
21+
}
22+
23+
await semaphore.WaitAsync(ct);
24+
try
25+
{
26+
container ??= await StartContainerAsync(ct);
27+
return container.GetConnectionString();
28+
}
29+
finally
30+
{
31+
semaphore.Release();
32+
}
33+
}
34+
35+
public static async Task Stop() => await (container?.DisposeAsync() ?? ValueTask.CompletedTask);
36+
37+
static async Task<MsSqlContainer> StartContainerAsync(CancellationToken ct)
38+
{
39+
var c = new MsSqlBuilder("mcr.microsoft.com/mssql/server:2025-latest")
40+
.Build();
41+
await c.StartAsync(ct);
42+
return c;
43+
}
44+
45+
static MsSqlContainer container;
46+
static readonly SemaphoreSlim semaphore = new(1, 1);
47+
}

0 commit comments

Comments
 (0)