From 2e9f605ea62d1452965d0d906a0977efc3916e1e Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Wed, 25 Feb 2026 15:22:02 +0100 Subject: [PATCH 1/2] Add default testcontainer support in the tests When the environment variable isn't defined --- .github/workflows/build.yml | 2 ++ Directory.Packages.props | 1 + .../EFCore.PG.FunctionalTests.csproj | 2 +- .../MigrationsInfrastructureNpgsqlTest.cs | 2 +- .../Query/NavigationTest.cs | 2 +- .../TestUtilities/NpgsqlTestStore.cs | 2 +- .../TestUtilities/TestEnvironment.cs | 31 ++++++++++++++++--- .../TestNpgsqlRetryingExecutionStrategy.cs | 2 +- test/EFCore.PG.FunctionalTests/config.json | 7 ----- 9 files changed, 34 insertions(+), 17 deletions(-) delete mode 100644 test/EFCore.PG.FunctionalTests/config.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bd14700af..bc2735c06 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -113,6 +113,8 @@ jobs: - name: Test run: dotnet test -c ${{ matrix.config }} --logger "GitHubActions;report-warnings=false" shell: bash + env: + Test__Npgsql__DefaultConnection: Server=localhost;Username=npgsql_tests;Password=npgsql_tests - id: analyze_tag name: Analyze tag diff --git a/Directory.Packages.props b/Directory.Packages.props index e7ba6c3b7..46d0053a3 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -33,5 +33,6 @@ + diff --git a/test/EFCore.PG.FunctionalTests/EFCore.PG.FunctionalTests.csproj b/test/EFCore.PG.FunctionalTests/EFCore.PG.FunctionalTests.csproj index ae0c6c54d..d40d04c6b 100644 --- a/test/EFCore.PG.FunctionalTests/EFCore.PG.FunctionalTests.csproj +++ b/test/EFCore.PG.FunctionalTests/EFCore.PG.FunctionalTests.csproj @@ -18,11 +18,11 @@ + - diff --git a/test/EFCore.PG.FunctionalTests/Migrations/MigrationsInfrastructureNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Migrations/MigrationsInfrastructureNpgsqlTest.cs index ea94d626e..00a911ec8 100644 --- a/test/EFCore.PG.FunctionalTests/Migrations/MigrationsInfrastructureNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Migrations/MigrationsInfrastructureNpgsqlTest.cs @@ -217,7 +217,7 @@ public class Post public class BloggingContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseNpgsql(TestEnvironment.DefaultConnection); + => optionsBuilder.UseNpgsql(TestEnvironment.ConnectionString); public DbSet Blogs { get; set; } } diff --git a/test/EFCore.PG.FunctionalTests/Query/NavigationTest.cs b/test/EFCore.PG.FunctionalTests/Query/NavigationTest.cs index 3d0be3802..93d0d51ae 100644 --- a/test/EFCore.PG.FunctionalTests/Query/NavigationTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/NavigationTest.cs @@ -83,7 +83,7 @@ public NavigationTestFixture() .AddEntityFrameworkNpgsql() .BuildServiceProvider(); - var connStrBuilder = new NpgsqlConnectionStringBuilder(TestEnvironment.DefaultConnection) { Database = "StateManagerBug" }; + var connStrBuilder = new NpgsqlConnectionStringBuilder(TestEnvironment.ConnectionString) { Database = "StateManagerBug" }; _options = new DbContextOptionsBuilder() .UseNpgsql(connStrBuilder.ConnectionString) diff --git a/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlTestStore.cs b/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlTestStore.cs index b07fddc2c..836ded147 100644 --- a/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlTestStore.cs +++ b/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlTestStore.cs @@ -420,7 +420,7 @@ private static DbCommand CreateCommand( public static string CreateConnectionString(string name, string? options = null) { - var builder = new NpgsqlConnectionStringBuilder(TestEnvironment.DefaultConnection) { Database = name }; + var builder = new NpgsqlConnectionStringBuilder(TestEnvironment.ConnectionString) { Database = name }; if (options is not null) { diff --git a/test/EFCore.PG.FunctionalTests/TestUtilities/TestEnvironment.cs b/test/EFCore.PG.FunctionalTests/TestUtilities/TestEnvironment.cs index 3887eb2ec..e9f2553a5 100644 --- a/test/EFCore.PG.FunctionalTests/TestUtilities/TestEnvironment.cs +++ b/test/EFCore.PG.FunctionalTests/TestUtilities/TestEnvironment.cs @@ -1,5 +1,6 @@ using System.Globalization; using Microsoft.Extensions.Configuration; +using Testcontainers.PostgreSql; namespace Microsoft.EntityFrameworkCore.TestUtilities; @@ -7,6 +8,11 @@ public static class TestEnvironment { public static IConfiguration Config { get; } + public static string ConnectionString { get; } + + // Keep a reference to prevent GC from collecting (and finalizing/stopping) the container while tests are running. + private static readonly PostgreSqlContainer? _postgreSqlContainer; + static TestEnvironment() { var configBuilder = new ConfigurationBuilder() @@ -18,13 +24,28 @@ static TestEnvironment() Config = configBuilder.Build() .GetSection("Test:Npgsql"); - Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); - } + if (Config["DefaultConnection"] is { } connectionString) + { + Console.WriteLine("Using connection string configured via Test:Npgsql:DefaultConnection: " + connectionString); + + ConnectionString = connectionString; + } + else + { + Console.WriteLine("No connection string configured via Test:Npgsql:DefaultConnection, starting up testcontainer..."); + + _postgreSqlContainer = new PostgreSqlBuilder("postgres:latest") + .WithCommand("-c", "max_connections=200") + .Build(); + _postgreSqlContainer.StartAsync().GetAwaiter().GetResult(); + ConnectionString = _postgreSqlContainer.GetConnectionString(); - private const string DefaultConnectionString = "Server=localhost;Username=npgsql_tests;Password=npgsql_tests;Port=5432"; + AppDomain.CurrentDomain.ProcessExit += (_, _) => + _postgreSqlContainer.DisposeAsync().AsTask().GetAwaiter().GetResult(); + } - public static string DefaultConnection - => Config["DefaultConnection"] ?? DefaultConnectionString; + Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); + } private static Version? _postgresVersion; diff --git a/test/EFCore.PG.FunctionalTests/TestUtilities/TestNpgsqlRetryingExecutionStrategy.cs b/test/EFCore.PG.FunctionalTests/TestUtilities/TestNpgsqlRetryingExecutionStrategy.cs index 6b572da0a..f1b60e845 100644 --- a/test/EFCore.PG.FunctionalTests/TestUtilities/TestNpgsqlRetryingExecutionStrategy.cs +++ b/test/EFCore.PG.FunctionalTests/TestUtilities/TestNpgsqlRetryingExecutionStrategy.cs @@ -13,7 +13,7 @@ public TestNpgsqlRetryingExecutionStrategy() new DbContext( new DbContextOptionsBuilder() .EnableServiceProviderCaching(false) - .UseNpgsql(TestEnvironment.DefaultConnection).Options), + .UseNpgsql(TestEnvironment.ConnectionString).Options), DefaultMaxRetryCount, DefaultMaxDelay, AdditionalSqlStates) { } diff --git a/test/EFCore.PG.FunctionalTests/config.json b/test/EFCore.PG.FunctionalTests/config.json deleted file mode 100644 index 4b361bbec..000000000 --- a/test/EFCore.PG.FunctionalTests/config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "Test": { - "Npgsql": { - "DefaultConnection": "Server=localhost;Username=npgsql_tests;Password=npgsql_tests;SSL Mode=disable" - } - } -} From ff432adc21abe4fb393917467a3836133955476b Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Wed, 25 Feb 2026 15:46:37 +0100 Subject: [PATCH 2/2] Update test/EFCore.PG.FunctionalTests/TestUtilities/TestEnvironment.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../TestUtilities/TestEnvironment.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/EFCore.PG.FunctionalTests/TestUtilities/TestEnvironment.cs b/test/EFCore.PG.FunctionalTests/TestUtilities/TestEnvironment.cs index e9f2553a5..47ec455be 100644 --- a/test/EFCore.PG.FunctionalTests/TestUtilities/TestEnvironment.cs +++ b/test/EFCore.PG.FunctionalTests/TestUtilities/TestEnvironment.cs @@ -41,7 +41,16 @@ static TestEnvironment() ConnectionString = _postgreSqlContainer.GetConnectionString(); AppDomain.CurrentDomain.ProcessExit += (_, _) => - _postgreSqlContainer.DisposeAsync().AsTask().GetAwaiter().GetResult(); + { + try + { + _postgreSqlContainer?.DisposeAsync().AsTask().GetAwaiter().GetResult(); + } + catch + { + // Ignore exceptions during process-exit cleanup. + } + }; } Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");