Repository navigation
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The fixture ignores the configured external database connection string and starts a container without first checking the default local database, breaking external-database runs and forcing Docker on existing local setups.
2 open issues
What changed in this PR
Adds Testcontainers-based PostgreSQL setup to simplify running Npgsql tests with a local Docker engine, aiming to preserve existing database configurations.
Changes:
- Adds container fallback and SSL configuration to the NUnit test setup.
- Moves specification fixtures to asynchronous container initialization and cleanup.
- Adds centrally managed Testcontainers dependencies.
| File | Description |
|---|---|
| test/Npgsql.Tests/TestUtil.cs | Allows setup to replace the shared connection string. |
| test/Npgsql.Tests/Support/PostgreSqlContainerExtensions.cs | Generates SSL certificates and enables container SSL. |
| test/Npgsql.Tests/Support/AssemblySetUp.cs | Adds container fallback, image selection, and cleanup. |
| test/Npgsql.Tests/Npgsql.Tests.csproj | References PostgreSQL Testcontainers. |
| test/Npgsql.Specification.Tests/NpgsqlSelectValueFixture.cs | Moves table setup and cleanup into asynchronous lifecycle hooks. |
| test/Npgsql.Specification.Tests/NpgsqlDbFactoryFixture.cs | Introduces container-backed fixtures for specification tests. |
| test/Npgsql.Specification.Tests/NpgsqlConnectionTests.cs | Uses the connection-specific fixture. |
| test/Npgsql.Specification.Tests/NpgsqlCommandTests.cs | Uses the command-specific fixture. |
| test/Npgsql.Specification.Tests/Npgsql.Specification.Tests.csproj | References PostgreSQL and xUnit Testcontainers packages. |
| Directory.Packages.props | Defines shared Testcontainers package versions. |
Review effort: Balanced
There was a problem hiding this comment.
🟡 Changes recommended
The Docker fallback lacks required replication settings, uses fixed container names that collide across concurrent runs, and can override an explicitly configured database in specification tests.
3 open issues
2 resolved since last review
Review effort: Balanced
| catch when (Environment.GetEnvironmentVariable("NPGSQL_TEST_DB") == null) | ||
| { | ||
| // Connection to the default connection string failed, use Docker to run PostgreSQL | ||
| _postgreSqlContainer = new PostgreSqlBuilder(ContainerImage).WithName(ContainerName).Build(); |
|
|
||
| public override string ConnectionString => _connectionString; | ||
|
|
||
| protected override PostgreSqlBuilder Configure() => new PostgreSqlBuilder("postgres:18").WithName(ContainerName); |
| using var rsa = RSA.Create(2048); | ||
| var request = new CertificateRequest(new X500DistinguishedName("CN=localhost"), rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); | ||
| using var certificate = request.CreateSelfSigned(notBefore: now, notAfter: now.AddDays(1)); |
| await container.CopyAsync(Encoding.Default.GetBytes(certPem), sslCertPath, uid, gid, certMode); | ||
| await container.CopyAsync(Encoding.Default.GetBytes(keyPem), sslKeyPath, uid, gid, keyMode); | ||
|
|
||
| await container.ExecScriptAsync(configureSsl); |
Without proper SSL configuration, all the SecurityTests would be skipped.
There was a problem hiding this comment.
🟡 Changes recommended
Teardown fails for external-database runs, missing host authentication breaks physical replication tests, and fixed container names cause collisions between concurrent test runs.
6 open issues
Gate container disposal on whether the fallback database was selected · New Allow password-authenticated host physical replication · New Use unique names for test containers Docker PostgreSQL rejects physical replication connections Docker fallback certificate does not match the test CA Fixture container names collide across concurrent test runs
Review effort: Balanced
| await base.InitializeAsync(); | ||
| _connectionString = base.ConnectionString; | ||
| } | ||
| } | ||
|
|
||
| protected override async Task DisposeAsyncCore() | ||
| { | ||
| if (_connectionString == base.ConnectionString) | ||
| { | ||
| await base.DisposeAsyncCore(); | ||
| } | ||
| } |
| await container.CopyAsync(Encoding.Default.GetBytes(certPem), sslCertPath, uid, gid, certMode); | ||
| await container.CopyAsync(Encoding.Default.GetBytes(keyPem), sslKeyPath, uid, gid, keyMode); | ||
|
|
||
| await container.ExecScriptAsync(configureSsl); |


Note that Testcontainers will only be used if a connection to the default connection string (
Server=localhost;User ID=npgsql_tests;Password=npgsql_tests;Database=npgsql_tests) can't be established and theNPGSQL_TEST_DBenvironment variable is not defined. This way, existing tests setup continue to work as before but someone freshly onboarded can just have a local Docker engine running and the Npgsql tests will run (and pass) without any database setup effort.