diff --git a/src/MccSoft.IntegreSql.EF/DatabaseInitialization/IDatabaseInitializer.cs b/src/MccSoft.IntegreSql.EF/DatabaseInitialization/IDatabaseInitializer.cs
index 08c1820..bf74575 100644
--- a/src/MccSoft.IntegreSql.EF/DatabaseInitialization/IDatabaseInitializer.cs
+++ b/src/MccSoft.IntegreSql.EF/DatabaseInitialization/IDatabaseInitializer.cs
@@ -16,7 +16,8 @@ public interface IDatabaseInitializer : IDisposable, IUseProvider
/// Connection string to a copy of template database
Task CreateDatabaseGetConnectionString(
DatabaseSeedingOptions databaseSeeding = null
- ) where TDbContext : DbContext;
+ )
+ where TDbContext : DbContext;
///
/// Creates a template database (if not created before) using DbContext.Database.EnsureCreated and
@@ -28,7 +29,8 @@ Task CreateDatabaseGetConnectionString(
/// Connection string to a copy of template database
string CreateDatabaseGetConnectionStringSync(
DatabaseSeedingOptions databaseSeeding = null
- ) where TDbContext : DbContext;
+ )
+ where TDbContext : DbContext;
///
/// Creates the DbContextOptionsBuilder for passed connection string.
@@ -36,7 +38,8 @@ string CreateDatabaseGetConnectionStringSync(
///
DbContextOptionsBuilder CreateDbContextOptionsBuilder(
string connectionString
- ) where TDbContext : DbContext;
+ )
+ where TDbContext : DbContext;
///
/// Creates the database using
@@ -45,7 +48,8 @@ string connectionString
///
Task> CreateDatabaseGetDbContextOptionsBuilder(
DatabaseSeedingOptions seedingOptions = null
- ) where TDbContext : DbContext;
+ )
+ where TDbContext : DbContext;
///
/// Creates the database using
@@ -54,10 +58,12 @@ Task> CreateDatabaseGetDbContextOptionsBuild
///
DbContextOptionsBuilder CreateDatabaseGetDbContextOptionsBuilderSync(
DatabaseSeedingOptions seedingOptions = null
- ) where TDbContext : DbContext;
+ )
+ where TDbContext : DbContext;
///
/// Returns test database to a pool.
+ /// You need to cleanup the data in that database yourself!
///
Task ReturnDatabaseToPool(string connectionString);
@@ -85,5 +91,6 @@ DbContextOptionsBuilder CreateDatabaseGetDbContextOptionsBuilderSync
void UseProvider(
DbContextOptionsBuilder options,
DatabaseSeedingOptions databaseSeedingOptions
- ) where TDbContext : DbContext;
+ )
+ where TDbContext : DbContext;
}
diff --git a/src/MccSoft.IntegreSql.EF/IntegreSqlClient.cs b/src/MccSoft.IntegreSql.EF/IntegreSqlClient.cs
index b39d324..346f81e 100644
--- a/src/MccSoft.IntegreSql.EF/IntegreSqlClient.cs
+++ b/src/MccSoft.IntegreSql.EF/IntegreSqlClient.cs
@@ -60,8 +60,8 @@ public async Task InitializeTemplate(string hash)
if (response.IsSuccessStatusCode)
{
- return await response.Content
- .ReadFromJsonAsync()
+ return await response
+ .Content.ReadFromJsonAsync()
.ConfigureAwait(false);
}
@@ -177,6 +177,49 @@ public async Task GetTestDatabase(string hash)
throw new NotImplementedException("We should never reach this point");
}
+ ///
+ /// Returns test database to a pool (which allows consequent tests to reuse this database).
+ /// This method (contrary to ) will tell IntegreSQL to cleanup the database.
+ ///
+ public async Task ReleaseTestDatabase(string hash, int id)
+ {
+ HttpResponseMessage response;
+ try
+ {
+ response = await _httpClient
+ .PostAsync($"templates/{hash}/tests/{id}/recreate", null)
+ .ConfigureAwait(false);
+ }
+ catch (HttpRequestException e)
+ {
+ throw new IntegreSqlNotRunningException(_httpClient.BaseAddress?.ToString(), e);
+ }
+
+ if (response.IsSuccessStatusCode)
+ return;
+
+ if (response.StatusCode == HttpStatusCode.NotFound)
+ {
+ throw new IntegreSqlTemplateNotFoundException(hash);
+ }
+ if (response.StatusCode == HttpStatusCode.ServiceUnavailable)
+ {
+ throw new IntegreSqlPostgresNotAvailableException(_httpClient.BaseAddress?.ToString());
+ }
+
+ response.EnsureSuccessStatusCode();
+ throw new NotImplementedException("We should never reach this point");
+ }
+
+ ///
+ /// Returns test database to a pool (which allows consequent tests to reuse this database).
+ /// Note that you need to clean up database by yourself before returning it to the pool!
+ /// If you return a dirty database, consequent tests might fail!
+ /// If you don't want to clean it up, just don't use this function.
+ /// Dirty databases are automatically deleted by IntegreSQL once database number exceeds a certain limit (500 by default).
+ ///
+ /// Consider using if you want the DB to be deleted/recreated by IntegreSQL
+ ///
public async Task ReturnTestDatabase(string hash, int id)
{
HttpResponseMessage response;
diff --git a/src/MccSoft.IntegreSql.EF/MccSoft.IntegreSql.EF.csproj b/src/MccSoft.IntegreSql.EF/MccSoft.IntegreSql.EF.csproj
index d2a3650..fa1de97 100644
--- a/src/MccSoft.IntegreSql.EF/MccSoft.IntegreSql.EF.csproj
+++ b/src/MccSoft.IntegreSql.EF/MccSoft.IntegreSql.EF.csproj
@@ -1,7 +1,7 @@
- 0.8.16
+ 0.10.1
true
MCC Soft
OpenIddict extension to support Auth code flow fo built-in ASP.Net identity providers
diff --git a/src/MccSoft.IntegreSql.EF/NpgsqlDatabaseInitializer.cs b/src/MccSoft.IntegreSql.EF/NpgsqlDatabaseInitializer.cs
index 5e84216..d927382 100644
--- a/src/MccSoft.IntegreSql.EF/NpgsqlDatabaseInitializer.cs
+++ b/src/MccSoft.IntegreSql.EF/NpgsqlDatabaseInitializer.cs
@@ -32,14 +32,9 @@ public class NpgsqlDatabaseInitializer : BaseDatabaseInitializer
public static bool UseMd5Hash = true;
///
- /// Drop database at the end of each test (when true) or not.
+ /// Release database (call IntegreSQL /api/v1/templates/:hash/tests/:id/recreate) at the end of each test (when true) or not.
///
- /// Old databases will be reused by IntegreSQL automatically.
- /// Previously we were removing databases by default, which actually interfere with IntegreSQL.
- /// It was 'hanging' when tried to reuse the removed databases.
- /// However, it was reported that if not dropped, Postgres starts to consume a lot of RAM.
- /// So one might be willing to drop anyway
- /// (though, for the latter case I'd recommend reducing the `INTEGRESQL_TEST_MAX_POOL_SIZE` in docker).
+ /// This API is available starting from IntegreSQL v1.1
///
public bool DropDatabaseOnRemove { get; set; }
@@ -195,12 +190,12 @@ public override async Task RemoveDatabase(string connectionString)
{
if (DropDatabaseOnRemove)
{
- await using var connection = new NpgsqlConnection(connectionString);
- string database = connection.Database;
- connection.Open();
- connection.ChangeDatabase("postgres");
- var command = new NpgsqlCommand($"DROP DATABASE \"{database}\"", connection);
- command.ExecuteNonQuery();
+ var connectionStringInfo = ConnectionStringInfos[connectionString];
+
+ await _integreSqlClient.ReturnTestDatabase(
+ connectionStringInfo.Hash,
+ connectionStringInfo.Id
+ );
}
else
{
diff --git a/tests/ExampleWeb.IntegrationTests/IntegrationTestBase.cs b/tests/ExampleWeb.IntegrationTests/IntegrationTestBase.cs
index 379af94..58f3a56 100644
--- a/tests/ExampleWeb.IntegrationTests/IntegrationTestBase.cs
+++ b/tests/ExampleWeb.IntegrationTests/IntegrationTestBase.cs
@@ -24,32 +24,28 @@ protected IntegrationTestBase(DatabaseType databaseType)
new DatabaseSeedingOptions(Name: "Integration")
);
- var webAppFactory = new WebApplicationFactory().WithWebHostBuilder(
- builder =>
+ var webAppFactory = new WebApplicationFactory().WithWebHostBuilder(builder =>
+ {
+ builder.ConfigureAppConfiguration(
+ (context, configuration) =>
+ {
+ configuration.AddInMemoryCollection(
+ new KeyValuePair[] { new("DisableSeed", "true") }
+ );
+ }
+ );
+ builder.ConfigureServices(services =>
{
- builder.ConfigureAppConfiguration(
- (context, configuration) =>
- {
- configuration.AddInMemoryCollection(
- new KeyValuePair[] { new("DisableSeed", "true") }
- );
- }
+ var descriptor = services.Single(d =>
+ d.ServiceType == typeof(DbContextOptions)
);
- builder.ConfigureServices(
- services =>
- {
- var descriptor = services.Single(
- d => d.ServiceType == typeof(DbContextOptions)
- );
- services.Remove(descriptor);
+ services.Remove(descriptor);
- services.AddDbContext(
- options => _databaseInitializer.UseProvider(options, _connectionString)
- );
- }
+ services.AddDbContext(options =>
+ _databaseInitializer.UseProvider(options, _connectionString)
);
- }
- );
+ });
+ });
_httpClient = webAppFactory.CreateDefaultClient();
}
@@ -59,11 +55,14 @@ private IDatabaseInitializer CreateDatabaseInitializer(DatabaseType databaseType
return databaseType switch
{
DatabaseType.Postgres
- => new NpgsqlDatabaseInitializer(
- // This is needed if you run tests NOT inside the container.
- // 5434 is the public port number of Postgresql instance
- connectionStringOverride: new() { Host = "localhost", Port = 5434, }
- ),
+ => new NpgsqlDatabaseInitializer(
+ // This is needed if you run tests NOT inside the container.
+ // 5434 is the public port number of Postgresql instance
+ connectionStringOverride: new() { Host = "localhost", Port = 5434, }
+ )
+ {
+ DropDatabaseOnRemove = true,
+ },
DatabaseType.Sqlite => new SqliteDatabaseInitializer(),
_ => throw new ArgumentOutOfRangeException(nameof(databaseType), databaseType, null)
};
diff --git a/tests/ExampleWeb.UnitTests/UnitTestBase.cs b/tests/ExampleWeb.UnitTests/UnitTestBase.cs
index 8cb20d0..14500e9 100644
--- a/tests/ExampleWeb.UnitTests/UnitTestBase.cs
+++ b/tests/ExampleWeb.UnitTests/UnitTestBase.cs
@@ -30,11 +30,14 @@ public UnitTestBase(
{
null => null,
DatabaseType.Postgres
- => new NpgsqlDatabaseInitializer(
- // This is needed if you run tests NOT inside the container.
- // 5434 is the public port number of Postgresql instance
- connectionStringOverride: new() { Host = "localhost", Port = 5434 }
- ),
+ => new NpgsqlDatabaseInitializer(
+ // This is needed if you run tests NOT inside the container.
+ // 5434 is the public port number of Postgresql instance
+ connectionStringOverride: new() { Host = "localhost", Port = 5434 }
+ )
+ {
+ DropDatabaseOnRemove = true,
+ },
DatabaseType.Sqlite => new SqliteDatabaseInitializer(),
_ => throw new ArgumentOutOfRangeException(nameof(databaseType), databaseType, null)
};