diff --git a/Examples/AngularAuth/AngularAuth.Backend.Sut/BloggingContext.cs b/Examples/AngularAuth/AngularAuth.Backend.Sut/BloggingContext.cs index 999661c..f9a9f52 100644 --- a/Examples/AngularAuth/AngularAuth.Backend.Sut/BloggingContext.cs +++ b/Examples/AngularAuth/AngularAuth.Backend.Sut/BloggingContext.cs @@ -4,15 +4,20 @@ namespace AngularAuth.Backend.Sut; public class BloggingContext : DbContext { + private readonly string? _connectionString; public DbSet Blogs => Set(); public DbSet Posts => Set(); - public BloggingContext() + public BloggingContext() { } + + public BloggingContext(IConfiguration configuration) { + _connectionString = configuration["DbConnectionString"]; } - public BloggingContext(DbContextOptions context) : base(context) + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { + optionsBuilder.UseNpgsql(_connectionString); } } diff --git a/Examples/AngularAuth/AngularAuth.Backend.Sut/Program.cs b/Examples/AngularAuth/AngularAuth.Backend.Sut/Program.cs index 4c6584d..9fb953d 100644 --- a/Examples/AngularAuth/AngularAuth.Backend.Sut/Program.cs +++ b/Examples/AngularAuth/AngularAuth.Backend.Sut/Program.cs @@ -8,10 +8,7 @@ WebRootPath = "wwwroot/browser" }); -builder.Services.AddDbContext(options => -{ - options.UseNpgsql(builder.Configuration["DbConnectionString"]); -}); +builder.Services.AddDbContext(); builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme); diff --git a/Examples/AngularAuth/AngularAuth.Playwright/TestSetup/AngularAuthSut.cs b/Examples/AngularAuth/AngularAuth.Playwright/TestSetup/AngularAuthSut.cs index 9a23536..cebeb98 100644 --- a/Examples/AngularAuth/AngularAuth.Playwright/TestSetup/AngularAuthSut.cs +++ b/Examples/AngularAuth/AngularAuth.Playwright/TestSetup/AngularAuthSut.cs @@ -56,10 +56,7 @@ protected override IHost CreateHost(IHostBuilder builder) builder.UseEnvironment(Environments.Production); builder.ConfigureHostConfiguration(config => { - config.AddInMemoryCollection(new Dictionary - { - { "DbConnectionString", _pooledDatabase.ConnectionString } - }); + config.AddInMemoryCollection(new Dictionary { { "DbConnectionString", _pooledDatabase.ConnectionString } }); }); builder.ConfigureLogging(loggingBuilder => @@ -90,7 +87,7 @@ protected override IHost CreateHost(IHostBuilder builder) // enough" for the address it is listening on to be available. _host = builder.Build(); _host.Start(); - _pooledDatabase.EnsureInitialized(_host); + _pooledDatabase.EnsureDatabaseIsReadyForTest(_host); // Extract the selected dynamic port out of the Kestrel server // and assign it onto the client options for convenience so it @@ -111,12 +108,6 @@ protected override IHost CreateHost(IHostBuilder builder) return testHost; } - public override async ValueTask DisposeAsync() - { - await base.DisposeAsync(); - await _pooledDatabase.DisposeAsync(); - } - protected override void Dispose(bool disposing) { base.Dispose(disposing); @@ -128,6 +119,7 @@ protected override void Dispose(bool disposing) _host?.Dispose(); } + _pooledDatabase.Dispose(); _disposed = true; } } diff --git a/Examples/Api/MsSql/Api.MsSql.Nunit/TestSetup/ApiMsSqlSut.cs b/Examples/Api/MsSql/Api.MsSql.Nunit/TestSetup/ApiMsSqlSut.cs index a209df1..c6d3a96 100644 --- a/Examples/Api/MsSql/Api.MsSql.Nunit/TestSetup/ApiMsSqlSut.cs +++ b/Examples/Api/MsSql/Api.MsSql.Nunit/TestSetup/ApiMsSqlSut.cs @@ -37,15 +37,15 @@ protected override IHost CreateHost(IHostBuilder builder) }); var app = base.CreateHost(builder); - _pooledDatabase.EnsureInitialized(app); + _pooledDatabase.EnsureDatabaseIsReadyForTest(app); return app; } - public override async ValueTask DisposeAsync() + protected override void Dispose(bool disposing) { - await base.DisposeAsync(); - await _pooledDatabase.DisposeAsync(); + base.Dispose(disposing); + _pooledDatabase.Dispose(); } public void SeedData(Action seedAction) diff --git a/Examples/Api/MsSql/Api.MsSql.Sut/BloggingContext.cs b/Examples/Api/MsSql/Api.MsSql.Sut/BloggingContext.cs index d2d0228..da268c2 100644 --- a/Examples/Api/MsSql/Api.MsSql.Sut/BloggingContext.cs +++ b/Examples/Api/MsSql/Api.MsSql.Sut/BloggingContext.cs @@ -4,17 +4,20 @@ namespace Api.MsSql.Sut; public class BloggingContext : DbContext { + private readonly string? _connectionString; public DbSet Blogs => Set(); public DbSet Posts => Set(); - public BloggingContext() - { + public BloggingContext() { } + public BloggingContext(IConfiguration configuration) + { + _connectionString = configuration["DbConnectionString"]; } - public BloggingContext(DbContextOptions context) : base(context) + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - + optionsBuilder.UseSqlServer(_connectionString); } } diff --git a/Examples/Api/MsSql/Api.MsSql.Sut/Program.cs b/Examples/Api/MsSql/Api.MsSql.Sut/Program.cs index af8b423..78ea3d5 100644 --- a/Examples/Api/MsSql/Api.MsSql.Sut/Program.cs +++ b/Examples/Api/MsSql/Api.MsSql.Sut/Program.cs @@ -3,10 +3,7 @@ var builder = WebApplication.CreateBuilder(args); -builder.Services.AddDbContext(options => -{ - options.UseSqlServer(builder.Configuration["DbConnectionString"]); -}); +builder.Services.AddDbContext(); var app = builder.Build(); diff --git a/Examples/Api/MsSql/Api.MsSql.Xunit/TestSetup/ApiMsSqlSut.cs b/Examples/Api/MsSql/Api.MsSql.Xunit/TestSetup/ApiMsSqlSut.cs index 8a326ef..cad0608 100644 --- a/Examples/Api/MsSql/Api.MsSql.Xunit/TestSetup/ApiMsSqlSut.cs +++ b/Examples/Api/MsSql/Api.MsSql.Xunit/TestSetup/ApiMsSqlSut.cs @@ -37,15 +37,15 @@ protected override IHost CreateHost(IHostBuilder builder) }); var app = base.CreateHost(builder); - _pooledDatabase.EnsureInitialized(app); + _pooledDatabase.EnsureDatabaseIsReadyForTest(app); return app; } - public override async ValueTask DisposeAsync() + protected override void Dispose(bool disposing) { - await base.DisposeAsync(); - await _pooledDatabase.DisposeAsync(); + base.Dispose(disposing); + _pooledDatabase.Dispose(); } public void SeedData(Action seedAction) diff --git a/Examples/Api/PostgreSql/Api.PostgreSql.Nunit/TestSetup/ApiPostgreSqlSut.cs b/Examples/Api/PostgreSql/Api.PostgreSql.Nunit/TestSetup/ApiPostgreSqlSut.cs index a0c832a..0f29357 100644 --- a/Examples/Api/PostgreSql/Api.PostgreSql.Nunit/TestSetup/ApiPostgreSqlSut.cs +++ b/Examples/Api/PostgreSql/Api.PostgreSql.Nunit/TestSetup/ApiPostgreSqlSut.cs @@ -37,15 +37,15 @@ protected override IHost CreateHost(IHostBuilder builder) }); var app = base.CreateHost(builder); - _pooledDatabase.EnsureInitialized(app); + _pooledDatabase.EnsureDatabaseIsReadyForTest(app); return app; } - public override async ValueTask DisposeAsync() + protected override void Dispose(bool disposing) { - await base.DisposeAsync(); - await _pooledDatabase.DisposeAsync(); + base.Dispose(disposing); + _pooledDatabase.Dispose(); } public void SeedData(Action seedAction) diff --git a/Examples/Api/PostgreSql/Api.PostgreSql.Sut/BloggingContext.cs b/Examples/Api/PostgreSql/Api.PostgreSql.Sut/BloggingContext.cs index fd9e56e..633d82f 100644 --- a/Examples/Api/PostgreSql/Api.PostgreSql.Sut/BloggingContext.cs +++ b/Examples/Api/PostgreSql/Api.PostgreSql.Sut/BloggingContext.cs @@ -4,15 +4,20 @@ namespace Api.PostgreSql.Sut; public class BloggingContext : DbContext { + private readonly string? _connectionString; public DbSet Blogs => Set(); public DbSet Posts => Set(); - public BloggingContext() + public BloggingContext() { } + + public BloggingContext(IConfiguration configuration) { + _connectionString = configuration["DbConnectionString"]; } - public BloggingContext(DbContextOptions context) : base(context) + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { + optionsBuilder.UseNpgsql(_connectionString); } } diff --git a/Examples/Api/PostgreSql/Api.PostgreSql.Sut/Program.cs b/Examples/Api/PostgreSql/Api.PostgreSql.Sut/Program.cs index c96b8a8..c7a3718 100644 --- a/Examples/Api/PostgreSql/Api.PostgreSql.Sut/Program.cs +++ b/Examples/Api/PostgreSql/Api.PostgreSql.Sut/Program.cs @@ -3,10 +3,7 @@ var builder = WebApplication.CreateBuilder(args); -builder.Services.AddDbContext(options => -{ - options.UseNpgsql(builder.Configuration["DbConnectionString"]); -}); +builder.Services.AddDbContext(); var app = builder.Build(); diff --git a/Examples/Api/PostgreSql/Api.PostgreSql.Xunit/TestSetup/ApiPostgreSqlSut.cs b/Examples/Api/PostgreSql/Api.PostgreSql.Xunit/TestSetup/ApiPostgreSqlSut.cs index 67aeafc..da9505d 100644 --- a/Examples/Api/PostgreSql/Api.PostgreSql.Xunit/TestSetup/ApiPostgreSqlSut.cs +++ b/Examples/Api/PostgreSql/Api.PostgreSql.Xunit/TestSetup/ApiPostgreSqlSut.cs @@ -37,15 +37,15 @@ protected override IHost CreateHost(IHostBuilder builder) }); var app = base.CreateHost(builder); - _pooledDatabase.EnsureInitialized(app); + _pooledDatabase.EnsureDatabaseIsReadyForTest(app); return app; } - public override async ValueTask DisposeAsync() + protected override void Dispose(bool disposing) { - await base.DisposeAsync(); - await _pooledDatabase.DisposeAsync(); + base.Dispose(disposing); + _pooledDatabase.Dispose(); } public void SeedData(Action seedAction) diff --git a/Examples/ApiJwtAuth/ApiJwtAuth.Nunit/TestSetup/ApiJwtAuthSut.cs b/Examples/ApiJwtAuth/ApiJwtAuth.Nunit/TestSetup/ApiJwtAuthSut.cs index 72911a4..0f417cd 100644 --- a/Examples/ApiJwtAuth/ApiJwtAuth.Nunit/TestSetup/ApiJwtAuthSut.cs +++ b/Examples/ApiJwtAuth/ApiJwtAuth.Nunit/TestSetup/ApiJwtAuthSut.cs @@ -44,15 +44,15 @@ protected override IHost CreateHost(IHostBuilder builder) }); var app = base.CreateHost(builder); - _pooledDatabase.EnsureInitialized(app); + _pooledDatabase.EnsureDatabaseIsReadyForTest(app); return app; } - public override async ValueTask DisposeAsync() + protected override void Dispose(bool disposing) { - await base.DisposeAsync(); - await _pooledDatabase.DisposeAsync(); + base.Dispose(disposing); + _pooledDatabase.Dispose(); } public void SeedData(Action seedAction) diff --git a/Examples/ApiJwtAuth/ApiJwtAuth.Sut/BloggingContext.cs b/Examples/ApiJwtAuth/ApiJwtAuth.Sut/BloggingContext.cs index 41d755b..ae7ea2d 100644 --- a/Examples/ApiJwtAuth/ApiJwtAuth.Sut/BloggingContext.cs +++ b/Examples/ApiJwtAuth/ApiJwtAuth.Sut/BloggingContext.cs @@ -4,15 +4,20 @@ namespace ApiJwtAuth.Sut; public class BloggingContext : DbContext { + private readonly string? _connectionString; public DbSet Blogs => Set(); public DbSet Posts => Set(); - public BloggingContext() + public BloggingContext() { } + + public BloggingContext(IConfiguration configuration) { + _connectionString = configuration["DbConnectionString"]; } - public BloggingContext(DbContextOptions context) : base(context) + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { + optionsBuilder.UseNpgsql(_connectionString); } } diff --git a/Examples/ApiJwtAuth/ApiJwtAuth.Sut/Program.cs b/Examples/ApiJwtAuth/ApiJwtAuth.Sut/Program.cs index 344e2de..51e356e 100644 --- a/Examples/ApiJwtAuth/ApiJwtAuth.Sut/Program.cs +++ b/Examples/ApiJwtAuth/ApiJwtAuth.Sut/Program.cs @@ -10,10 +10,7 @@ builder.Services.AddAuthorization(); -builder.Services.AddDbContext(options => -{ - options.UseNpgsql(builder.Configuration["DbConnectionString"]); -}); +builder.Services.AddDbContext(); var app = builder.Build(); diff --git a/Examples/Migrations.MsSql.EntityFrameworkCore/Migrations.MsSql.EntityFrameworkCore.Nunit/MigrationTests.cs b/Examples/Migrations.MsSql.EntityFrameworkCore/Migrations.MsSql.EntityFrameworkCore.Nunit/MigrationTests.cs index 9f69fc9..333b610 100644 --- a/Examples/Migrations.MsSql.EntityFrameworkCore/Migrations.MsSql.EntityFrameworkCore.Nunit/MigrationTests.cs +++ b/Examples/Migrations.MsSql.EntityFrameworkCore/Migrations.MsSql.EntityFrameworkCore.Nunit/MigrationTests.cs @@ -49,7 +49,7 @@ private sealed class MigrationTestCases : IEnumerable { public IEnumerator GetEnumerator() { - using DbContext context = new BloggingContext(new DbContextOptionsBuilder().UseSqlServer().Options); + using DbContext context = new BloggingContext(); var migrations = context.GenerateMigrationScripts(); foreach (var migration in migrations) diff --git a/Examples/Migrations.MsSql.EntityFrameworkCore/Migrations.MsSql.EntityFrameworkCore.Sut/BloggingContext.cs b/Examples/Migrations.MsSql.EntityFrameworkCore/Migrations.MsSql.EntityFrameworkCore.Sut/BloggingContext.cs index 536d9d1..7b249af 100644 --- a/Examples/Migrations.MsSql.EntityFrameworkCore/Migrations.MsSql.EntityFrameworkCore.Sut/BloggingContext.cs +++ b/Examples/Migrations.MsSql.EntityFrameworkCore/Migrations.MsSql.EntityFrameworkCore.Sut/BloggingContext.cs @@ -4,17 +4,20 @@ namespace Migrations.MsSql.EntityFrameworkCore.Sut; public class BloggingContext : DbContext { + private readonly string? _connectionString; public DbSet Blogs => Set(); public DbSet Posts => Set(); - public BloggingContext() - { + public BloggingContext() { } + public BloggingContext(IConfiguration configuration) + { + _connectionString = configuration["DbConnectionString"]; } - public BloggingContext(DbContextOptions context) : base(context) + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - + optionsBuilder.UseSqlServer(_connectionString); } } diff --git a/Examples/Migrations.MsSql.EntityFrameworkCore/Migrations.MsSql.EntityFrameworkCore.Sut/Program.cs b/Examples/Migrations.MsSql.EntityFrameworkCore/Migrations.MsSql.EntityFrameworkCore.Sut/Program.cs index a5edd74..5f2d9d7 100644 --- a/Examples/Migrations.MsSql.EntityFrameworkCore/Migrations.MsSql.EntityFrameworkCore.Sut/Program.cs +++ b/Examples/Migrations.MsSql.EntityFrameworkCore/Migrations.MsSql.EntityFrameworkCore.Sut/Program.cs @@ -3,10 +3,7 @@ var builder = WebApplication.CreateBuilder(args); -builder.Services.AddDbContext(options => -{ - options.UseSqlServer(builder.Configuration["DbConnectionString"]); -}); +builder.Services.AddDbContext(); var app = builder.Build(); diff --git a/Examples/Razor/Razor.Playwright/TestSetup/RazorSut.cs b/Examples/Razor/Razor.Playwright/TestSetup/RazorSut.cs index e5d5729..8658dc0 100644 --- a/Examples/Razor/Razor.Playwright/TestSetup/RazorSut.cs +++ b/Examples/Razor/Razor.Playwright/TestSetup/RazorSut.cs @@ -86,7 +86,7 @@ protected override IHost CreateHost(IHostBuilder builder) // enough" for the address it is listening on to be available. _host = builder.Build(); _host.Start(); - _pooledDatabase.EnsureInitialized(_host); + _pooledDatabase.EnsureDatabaseIsReadyForTest(_host); // Extract the selected dynamic port out of the Kestrel server // and assign it onto the client options for convenience so it @@ -107,12 +107,6 @@ protected override IHost CreateHost(IHostBuilder builder) return testHost; } - public override async ValueTask DisposeAsync() - { - await base.DisposeAsync(); - await _pooledDatabase.DisposeAsync(); - } - protected override void Dispose(bool disposing) { base.Dispose(disposing); @@ -123,7 +117,7 @@ protected override void Dispose(bool disposing) { _host?.Dispose(); } - + _pooledDatabase.Dispose(); _disposed = true; } } diff --git a/Examples/Razor/Razor.Sut/BloggingContext.cs b/Examples/Razor/Razor.Sut/BloggingContext.cs index e890fab..43d333b 100644 --- a/Examples/Razor/Razor.Sut/BloggingContext.cs +++ b/Examples/Razor/Razor.Sut/BloggingContext.cs @@ -4,15 +4,20 @@ namespace Razor.PostgreSql.Sut; public class BloggingContext : DbContext { + private readonly string? _connectionString; public DbSet Blogs => Set(); public DbSet Posts => Set(); - public BloggingContext() + public BloggingContext() { } + + public BloggingContext(IConfiguration configuration) { + _connectionString = configuration["DbConnectionString"]; } - public BloggingContext(DbContextOptions context) : base(context) + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { + optionsBuilder.UseNpgsql(_connectionString); } } diff --git a/Examples/Razor/Razor.Sut/Program.cs b/Examples/Razor/Razor.Sut/Program.cs index 545039f..395dc1e 100644 --- a/Examples/Razor/Razor.Sut/Program.cs +++ b/Examples/Razor/Razor.Sut/Program.cs @@ -3,10 +3,7 @@ var builder = WebApplication.CreateBuilder(args); -builder.Services.AddDbContext(options => -{ - options.UseNpgsql(builder.Configuration["DbConnectionString"]); -}); +builder.Services.AddDbContext(); builder.Services.AddRazorPages(); diff --git a/Examples/Vue/Vue.Backend.Sut/BloggingContext.cs b/Examples/Vue/Vue.Backend.Sut/BloggingContext.cs index 43e2b54..e422878 100644 --- a/Examples/Vue/Vue.Backend.Sut/BloggingContext.cs +++ b/Examples/Vue/Vue.Backend.Sut/BloggingContext.cs @@ -4,15 +4,20 @@ namespace Vue.Backend.Sut; public class BloggingContext : DbContext { + private readonly string? _connectionString; public DbSet Blogs => Set(); public DbSet Posts => Set(); - public BloggingContext() + public BloggingContext() { } + + public BloggingContext(IConfiguration configuration) { + _connectionString = configuration["DbConnectionString"]; } - public BloggingContext(DbContextOptions context) : base(context) + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { + optionsBuilder.UseNpgsql(_connectionString); } } diff --git a/Examples/Vue/Vue.Backend.Sut/Program.cs b/Examples/Vue/Vue.Backend.Sut/Program.cs index d2ed8e7..d5c98c7 100644 --- a/Examples/Vue/Vue.Backend.Sut/Program.cs +++ b/Examples/Vue/Vue.Backend.Sut/Program.cs @@ -3,10 +3,7 @@ var builder = WebApplication.CreateBuilder(args); -builder.Services.AddDbContext(options => -{ - options.UseNpgsql(builder.Configuration["DbConnectionString"]); -}); +builder.Services.AddDbContext(); var app = builder.Build(); diff --git a/Examples/Vue/Vue.Playwright/TestSetup/VueSut.cs b/Examples/Vue/Vue.Playwright/TestSetup/VueSut.cs index 3041dd6..a24f8d0 100644 --- a/Examples/Vue/Vue.Playwright/TestSetup/VueSut.cs +++ b/Examples/Vue/Vue.Playwright/TestSetup/VueSut.cs @@ -56,10 +56,7 @@ protected override IHost CreateHost(IHostBuilder builder) builder.UseEnvironment(Environments.Production); builder.ConfigureHostConfiguration(config => { - config.AddInMemoryCollection(new Dictionary - { - { "DbConnectionString", _pooledDatabase.ConnectionString } - }); + config.AddInMemoryCollection(new Dictionary { { "DbConnectionString", _pooledDatabase.ConnectionString } }); }); builder.ConfigureLogging(loggingBuilder => @@ -85,7 +82,7 @@ protected override IHost CreateHost(IHostBuilder builder) // enough" for the address it is listening on to be available. _host = builder.Build(); _host.Start(); - _pooledDatabase.EnsureInitialized(_host); + _pooledDatabase.EnsureDatabaseIsReadyForTest(_host); // Extract the selected dynamic port out of the Kestrel server // and assign it onto the client options for convenience so it @@ -106,12 +103,6 @@ protected override IHost CreateHost(IHostBuilder builder) return testHost; } - public override async ValueTask DisposeAsync() - { - await base.DisposeAsync(); - await _pooledDatabase.DisposeAsync(); - } - protected override void Dispose(bool disposing) { base.Dispose(disposing); @@ -122,7 +113,7 @@ protected override void Dispose(bool disposing) { _host?.Dispose(); } - + _pooledDatabase.Dispose(); _disposed = true; } } diff --git a/TestExamplesDotnet.EntityFrameworkCore/DbContextMigrationInitializer.cs b/TestExamplesDotnet.EntityFrameworkCore/DbContextMigrationInitializer.cs index 9084b01..8825c9d 100644 --- a/TestExamplesDotnet.EntityFrameworkCore/DbContextMigrationInitializer.cs +++ b/TestExamplesDotnet.EntityFrameworkCore/DbContextMigrationInitializer.cs @@ -1,4 +1,8 @@ -using Microsoft.EntityFrameworkCore; +using System.Security.Cryptography; +using System.Text; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -7,8 +11,23 @@ namespace TestExamplesDotnet; public sealed class DbContextMigrationInitializer : IDatabaseInitializer - where TDbContext : DbContext + where TDbContext : DbContext, new() { + private int _counter; + private readonly Lazy _databaseHash; + + public DbContextMigrationInitializer() + { + _databaseHash = new Lazy(() => + { + using var context = new TDbContext(); + var createScript = context.GetService().GenerateCreateScript(); +#pragma warning disable CA5351 + return Convert.ToHexString(MD5.HashData(Encoding.UTF8.GetBytes(createScript))); +#pragma warning restore CA5351 + }); + } + public void Initialize(IHost app) { using var serviceScope = app.Services.GetRequiredService().CreateScope(); @@ -21,4 +40,10 @@ public void Initialize(IHost app) configurationRoot["Logging:LogLevel:Microsoft.EntityFrameworkCore"] = LogLevel.Information.ToString(); configurationRoot.Reload(); } + + public string GetUniqueDataBaseName() + { + var counter = Interlocked.Increment(ref _counter); + return $"{_databaseHash.Value}_{counter}"; + } } diff --git a/TestExamplesDotnet.EntityFrameworkCore/ServiceCollectionExtensions.cs b/TestExamplesDotnet.EntityFrameworkCore/ServiceCollectionExtensions.cs index bbc8b5e..25ebea8 100644 --- a/TestExamplesDotnet.EntityFrameworkCore/ServiceCollectionExtensions.cs +++ b/TestExamplesDotnet.EntityFrameworkCore/ServiceCollectionExtensions.cs @@ -6,8 +6,8 @@ namespace TestExamplesDotnet.EntityFrameworkCore; public static class ServiceCollectionExtensions { public static void RegisterMigrationInitializer(this IServiceCollection services) - where TContext : DbContext + where TContext : DbContext, new() { - services.AddTransient>(); + services.AddSingleton>(); } } diff --git a/TestExamplesDotnet.Mssql/MsSqlDatabase.cs b/TestExamplesDotnet.Mssql/MsSqlDatabase.cs index 7809c35..43da1ce 100644 --- a/TestExamplesDotnet.Mssql/MsSqlDatabase.cs +++ b/TestExamplesDotnet.Mssql/MsSqlDatabase.cs @@ -18,10 +18,10 @@ public MsSqlDatabase(MsSqlContainer container, IDatabaseInitializer databaseInit { _databaseInitializer = databaseInitializer; _respawnerOptions = respawnerOptions; - ConnectionString = $"Server=127.0.0.1,{container.GetMappedPublicPort(1433)};Database={Guid.NewGuid()};User Id=sa;Password=yourStrong(!)Password;TrustServerCertificate=True"; + ConnectionString = $"Server=127.0.0.1,{container.GetMappedPublicPort(1433)};Database={databaseInitializer.GetUniqueDataBaseName()};User Id=sa;Password=yourStrong(!)Password;TrustServerCertificate=True"; } - public void Initialize(IHost host) + public void EnsureInitialized(IHost host) { if (!_initialized) { @@ -30,16 +30,13 @@ public void Initialize(IHost host) } } - public async ValueTask Clean() + public async Task Clean() { - if (_initialized) - { - await using var conn = new SqlConnection(ConnectionString); - await conn.OpenAsync(); + await using var conn = new SqlConnection(ConnectionString); + await conn.OpenAsync(); - _respawner ??= await Respawner.CreateAsync(conn, _respawnerOptions); + _respawner ??= await Respawner.CreateAsync(conn, _respawnerOptions); - await _respawner.ResetAsync(conn); - } + await _respawner.ResetAsync(conn); } } diff --git a/TestExamplesDotnet.Mssql/MsSqlDatabasePoolPolicy.cs b/TestExamplesDotnet.Mssql/MsSqlDatabasePoolPolicy.cs index 51b9912..cdcc8bd 100644 --- a/TestExamplesDotnet.Mssql/MsSqlDatabasePoolPolicy.cs +++ b/TestExamplesDotnet.Mssql/MsSqlDatabasePoolPolicy.cs @@ -10,7 +10,6 @@ public sealed class MsSqlDatabasePoolPolicy : IPooledObjectPolicy private readonly IDatabaseInitializer _databaseInitializer; private readonly RespawnerOptions _respawnerOptions; - public MsSqlDatabasePoolPolicy(MsSqlContainer container, IDatabaseInitializer databaseInitializer, RespawnerOptions respawnerOptions) { _container = container; diff --git a/TestExamplesDotnet.Mssql/ServiceCollectionExtensions.cs b/TestExamplesDotnet.Mssql/ServiceCollectionExtensions.cs index 7e86008..b227340 100644 --- a/TestExamplesDotnet.Mssql/ServiceCollectionExtensions.cs +++ b/TestExamplesDotnet.Mssql/ServiceCollectionExtensions.cs @@ -16,7 +16,8 @@ public static void RegisterMssqlContainer(this IServiceCollection services) }); services.AddTransient, MsSqlDatabasePoolPolicy>(); - var container = new MsSqlBuilder().Build(); + var container = new MsSqlBuilder() + .Build(); Utils.RunWithoutSynchronizationContext(() => container.StartAsync().Wait()); services.AddSingleton(container); } diff --git a/TestExamplesDotnet.PostgreSql/PostgreSqlDatabase.cs b/TestExamplesDotnet.PostgreSql/PostgreSqlDatabase.cs index b1895b8..d38b217 100644 --- a/TestExamplesDotnet.PostgreSql/PostgreSqlDatabase.cs +++ b/TestExamplesDotnet.PostgreSql/PostgreSqlDatabase.cs @@ -17,10 +17,10 @@ public PostgreSqlDatabase(PostgreSqlContainer container, IDatabaseInitializer da { _databaseInitializer = databaseInitializer; _respawnerOptions = respawnerOptions; - ConnectionString = $"Host=127.0.0.1;Port={container.GetMappedPublicPort(5432)};Database={Guid.NewGuid()};Username=postgres;Password=postgres;Include Error Detail=true"; + ConnectionString = $"Host=127.0.0.1;Port={container.GetMappedPublicPort(5432)};Database={databaseInitializer.GetUniqueDataBaseName()};Username=postgres;Password=postgres;Include Error Detail=true"; } - public void Initialize(IHost host) + public void EnsureInitialized(IHost host) { if (!_initialized) { @@ -29,16 +29,13 @@ public void Initialize(IHost host) } } - public async ValueTask Clean() + public async Task Clean() { - if (_initialized) - { - await using var conn = new NpgsqlConnection(ConnectionString); - await conn.OpenAsync(); + await using var conn = new NpgsqlConnection(ConnectionString); + await conn.OpenAsync(); - _respawner ??= await Respawner.CreateAsync(conn, _respawnerOptions); + _respawner ??= await Respawner.CreateAsync(conn, _respawnerOptions); - await _respawner.ResetAsync(conn); - } + await _respawner.ResetAsync(conn); } } diff --git a/TestExamplesDotnet.PostgreSql/PostgreSqlDatabasePoolPolicy.cs b/TestExamplesDotnet.PostgreSql/PostgreSqlDatabasePoolPolicy.cs index 7f913a7..6b3b27a 100644 --- a/TestExamplesDotnet.PostgreSql/PostgreSqlDatabasePoolPolicy.cs +++ b/TestExamplesDotnet.PostgreSql/PostgreSqlDatabasePoolPolicy.cs @@ -10,7 +10,6 @@ public sealed class PostgreSqlDatabasePoolPolicy : IPooledObjectPolicy, PostgreSqlDatabasePoolPolicy>(); - var container = new PostgreSqlBuilder().Build(); + var container = new PostgreSqlBuilder() + .Build(); Utils.RunWithoutSynchronizationContext(() => container.StartAsync().Wait()); + services.AddSingleton(container); } } diff --git a/TestExamplesDotnet/IDatabase.cs b/TestExamplesDotnet/IDatabase.cs index a7d3c93..9e46e14 100644 --- a/TestExamplesDotnet/IDatabase.cs +++ b/TestExamplesDotnet/IDatabase.cs @@ -6,6 +6,6 @@ public interface IDatabase { string ConnectionString { get; } - public void Initialize(IHost host); - public ValueTask Clean(); + public void EnsureInitialized(IHost host); + public Task Clean(); } diff --git a/TestExamplesDotnet/IDatabaseInitializer.cs b/TestExamplesDotnet/IDatabaseInitializer.cs index a40c610..879f955 100644 --- a/TestExamplesDotnet/IDatabaseInitializer.cs +++ b/TestExamplesDotnet/IDatabaseInitializer.cs @@ -5,4 +5,5 @@ namespace TestExamplesDotnet; public interface IDatabaseInitializer { void Initialize(IHost app); + string GetUniqueDataBaseName(); } diff --git a/TestExamplesDotnet/PooledDatabase.cs b/TestExamplesDotnet/PooledDatabase.cs index 85f3c07..e9bb261 100644 --- a/TestExamplesDotnet/PooledDatabase.cs +++ b/TestExamplesDotnet/PooledDatabase.cs @@ -3,7 +3,7 @@ namespace TestExamplesDotnet; -public sealed class PooledDatabase : IAsyncDisposable +public sealed class PooledDatabase : IDisposable { private readonly IDatabase _database; @@ -17,14 +17,18 @@ internal PooledDatabase(ObjectPool pool) public string ConnectionString => _database.ConnectionString; - public void EnsureInitialized(IHost host) + public void EnsureDatabaseIsReadyForTest(IHost host) { - _database.Initialize(host); + _database.EnsureInitialized(host); + // Clean the database before and not after the test so that after a test is run you can inspect the database. + Utils.RunWithoutSynchronizationContext(() => + { + _database.Clean().GetAwaiter().GetResult(); + }); } - public async ValueTask DisposeAsync() + public void Dispose() { - await _database.Clean(); _pool.Return(_database); } }