From 1a032d912bee404d0a4cb91c91dcaf632d5b666c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20L=C3=A9caillon?= Date: Fri, 30 Jun 2023 13:51:20 +0200 Subject: [PATCH] Add .NET 7 support (#305) --- build/common.props | 6 +- src/Evolve.Cli/Evolve.Cli.csproj | 2 +- src/Evolve.Cli/Program.cs | 202 +++++++++--------- src/Evolve.Tool/Evolve.Tool.csproj | 5 +- src/Evolve/Evolve.csproj | 2 +- test/Evolve.Tests/Cli/CliTest.cs | 82 +++---- .../Connection/WrappedConnectionTest.cs | 26 +-- test/Evolve.Tests/Evolve.Tests.csproj | 8 +- .../Cassandra/CassandraFixture.cs | 8 - .../{Cassandra => }/CassandraContainer.cs | 26 +-- .../CockroachDb/CockroachDbFixture.cs | 19 -- .../{CockroachDb => }/CockroachDbContainer.cs | 26 +-- .../Infrastructure/MySQL/MySQLFixture.cs | 8 - .../{MySQL => }/MySqlContainer.cs | 26 +-- .../PostgreSql/PostgreSqlFixture.cs | 19 -- .../{PostgreSql => }/PostgreSqlContainer.cs | 32 +-- .../SQLServer/SQLServerFixture.cs | 9 - .../{SQLServer => }/SQLServerContainer.cs | 26 +-- .../_Internal/DbContainerFixture.cs | 53 +++-- .../_Internal/DockerContainer.cs | 39 ++-- .../_Internal/DockerContainerBuilder.cs | 40 +--- .../Infrastructure/_Internal/IDbContainer.cs | 8 +- .../Integration/Cassandra/DialectTest.cs | 8 +- .../Integration/Cassandra/MigrationTest.cs | 32 +-- .../Integration/CockroachDB/DialectTest.cs | 18 +- .../Integration/CockroachDB/MigrationTest.cs | 23 +- .../Integration/MySQL/DialectTest.cs | 20 +- .../Integration/MySQL/MigrationTest.cs | 22 +- .../Integration/PostgreSQL/DialectTest.cs | 20 +- .../Integration/PostgreSQL/MigrationTest.cs | 26 +-- .../Integration/PostgreSQL/Scenario001.cs | 8 +- .../Integration/PostgreSQL/Scenario002.cs | 8 +- .../Integration/PostgreSQL/Scenario003.cs | 5 +- .../Integration/PostgreSQL/Scenario004.cs | 5 +- .../Integration/PostgreSQL/Scenario005.cs | 5 +- .../Integration/PostgreSQL/Scenario006.cs | 5 +- .../Integration/PostgreSQL/Scenario007.cs | 5 +- .../Integration/PostgreSQL/Scenario008.cs | 5 +- .../Integration/PostgreSQL/Scenario009.cs | 5 +- .../Integration/SQLServer/DialectTest.cs | 27 +-- .../Integration/SQLServer/MigrationTest.cs | 30 +-- .../Integration/SQLServer/Scenario101.cs | 5 +- .../Integration/SQLServer/Scenario102.cs | 5 +- test/Evolve.Tests/Integration/ScenarioBase.cs | 87 ++++---- test/Evolve.Tests/TestContext.cs | 30 +-- test/Evolve.Tests/TestUtil.cs | 6 +- 46 files changed, 363 insertions(+), 719 deletions(-) delete mode 100644 test/Evolve.Tests/Infrastructure/Cassandra/CassandraFixture.cs rename test/Evolve.Tests/Infrastructure/{Cassandra => }/CassandraContainer.cs (66%) delete mode 100644 test/Evolve.Tests/Infrastructure/CockroachDb/CockroachDbFixture.cs rename test/Evolve.Tests/Infrastructure/{CockroachDb => }/CockroachDbContainer.cs (63%) delete mode 100644 test/Evolve.Tests/Infrastructure/MySQL/MySQLFixture.cs rename test/Evolve.Tests/Infrastructure/{MySQL => }/MySqlContainer.cs (67%) delete mode 100644 test/Evolve.Tests/Infrastructure/PostgreSql/PostgreSqlFixture.cs rename test/Evolve.Tests/Infrastructure/{PostgreSql => }/PostgreSqlContainer.cs (60%) delete mode 100644 test/Evolve.Tests/Infrastructure/SQLServer/SQLServerFixture.cs rename test/Evolve.Tests/Infrastructure/{SQLServer => }/SQLServerContainer.cs (66%) diff --git a/build/common.props b/build/common.props index 3e7f5d5f..cb83f6bc 100644 --- a/build/common.props +++ b/build/common.props @@ -1,7 +1,7 @@ - 3.2.0-alpha2 - 3.1.0.0 - 3.1.0.0 + 3.2.0 + 3.2.0.0 + 3.2.0.0 \ No newline at end of file diff --git a/src/Evolve.Cli/Evolve.Cli.csproj b/src/Evolve.Cli/Evolve.Cli.csproj index 3028d286..497daae3 100644 --- a/src/Evolve.Cli/Evolve.Cli.csproj +++ b/src/Evolve.Cli/Evolve.Cli.csproj @@ -3,7 +3,7 @@ Exe - net6.0 + net7.0 true EvolveDb.Cli diff --git a/src/Evolve.Cli/Program.cs b/src/Evolve.Cli/Program.cs index e9e89b7a..da79f0e1 100644 --- a/src/Evolve.Cli/Program.cs +++ b/src/Evolve.Cli/Program.cs @@ -1,135 +1,141 @@ -namespace EvolveDb.Cli +namespace EvolveDb.Cli; + +using Configuration; +using Dialect; +using McMaster.Extensions.CommandLineUtils; +using System; +using System.ComponentModel.DataAnnotations; +using System.Linq; + +[Command(ResponseFileHandling = ResponseFileHandling.ParseArgsAsSpaceSeparated)] +class Program { - using System; - using System.ComponentModel.DataAnnotations; - using System.Diagnostics.CodeAnalysis; - using System.Linq; - using Configuration; - using Dialect; - using McMaster.Extensions.CommandLineUtils; - - [Command(ResponseFileHandling = ResponseFileHandling.ParseArgsAsSpaceSeparated)] - class Program + private static readonly Evolve Default = new(new System.Data.SQLite.SQLiteConnection("Data Source=:memory:")); + + static int Main(string[] args) { - private static readonly Evolve Default = new Evolve(new System.Data.SQLite.SQLiteConnection("Data Source=:memory:")); + new Program().OnExecute(null, null); // We do not want OnExecute to be trimmed at publish time + return CommandLineApplication.Execute(args); + } - static int Main(string[] args) => CommandLineApplication.Execute(args); + private int OnExecute(CommandLineApplication app, IConsole console) + { + if (app is null) + { + return 0; + } - [SuppressMessage("Qualité du code", "IDE0051: Supprimer les membres privés non utilisés")] - private int OnExecute(CommandLineApplication app, IConsole console) + try + { + var evolve = EvolveFactory.Build(this, msg => console.WriteLine(msg)); + evolve.ExecuteCommand(); + return 0; + } + catch (Exception ex) { - try - { - var evolve = EvolveFactory.Build(this, msg => console.WriteLine(msg)); - evolve.ExecuteCommand(); - return 0; - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - return 1; - } + Console.WriteLine(ex.Message); + return 1; } + } - [Argument(0, Description = "migrate | erase | repair | info | validate")] - [Required] - [AllowedValues("migrate", "erase", "repair", "info", "validate", IgnoreCase = true)] - public CommandOptions Command { get; } + [Argument(0, Description = "migrate | erase | repair | info | validate")] + [Required] + [AllowedValues("migrate", "erase", "repair", "info", "validate", IgnoreCase = true)] + public CommandOptions Command { get; } - [Argument(1, Description = "postgresql | sqlite | sqlserver | mysql | mariadb | cassandra | cockroachdb")] - [Required] - [AllowedValues("postgresql", "sqlite", "sqlserver", "mysql", "mariadb", "cassandra", "cockroachdb", IgnoreCase = true)] - public DBMS Database { get; } + [Argument(1, Description = "postgresql | sqlite | sqlserver | mysql | mariadb | cassandra | cockroachdb")] + [Required] + [AllowedValues("postgresql", "sqlite", "sqlserver", "mysql", "mariadb", "cassandra", "cockroachdb", IgnoreCase = true)] + public DBMS Database { get; } - [Option("-c|--connection-string", "The connection string to the target database engine. Must have the necessary privileges to execute ddl.", CommandOptionType.SingleValue)] - [Required] - public string ConnectionString { get; } + [Option("-c|--connection-string", "The connection string to the target database engine. Must have the necessary privileges to execute ddl.", CommandOptionType.SingleValue)] + [Required] + public string ConnectionString { get; } - [Option("-l|--location", "Paths to scan recursively for migration scripts. Default: Sql_Scripts", CommandOptionType.MultipleValue)] - public string[] Locations { get; } = Default.Locations?.ToArray(); + [Option("-l|--location", "Paths to scan recursively for migration scripts. Default: Sql_Scripts", CommandOptionType.MultipleValue)] + public string[] Locations { get; } = Default.Locations?.ToArray(); - [Option("-s|--schema", "A list of schemas managed by Evolve. If empty, the default schema for the datasource connection is used.", CommandOptionType.MultipleValue)] - public string[] Schemas { get; } = Default.Schemas?.ToArray(); + [Option("-s|--schema", "A list of schemas managed by Evolve. If empty, the default schema for the datasource connection is used.", CommandOptionType.MultipleValue)] + public string[] Schemas { get; } = Default.Schemas?.ToArray(); - [Option("--metadata-table-schema", "The schema in which the metadata table is/should be. If empty, it is the first schema defined or the one of the datasource connection.", CommandOptionType.SingleValue)] - public string MetadataTableSchema { get; } + [Option("--metadata-table-schema", "The schema in which the metadata table is/should be. If empty, it is the first schema defined or the one of the datasource connection.", CommandOptionType.SingleValue)] + public string MetadataTableSchema { get; } - [Option("--metadata-table", "The name of the metadata table. Default: changelog", CommandOptionType.SingleValue)] - public string MetadataTableName { get; } = Default.MetadataTableName; + [Option("--metadata-table", "The name of the metadata table. Default: changelog", CommandOptionType.SingleValue)] + public string MetadataTableName { get; } = Default.MetadataTableName; - [Option("-p|--placeholder", "Placeholders are strings to replace in migration scripts. Format for commandline is \"key:value\".", CommandOptionType.MultipleValue)] - public string[] Placeholders { get; } + [Option("-p|--placeholder", "Placeholders are strings to replace in migration scripts. Format for commandline is \"key:value\".", CommandOptionType.MultipleValue)] + public string[] Placeholders { get; } - [Option("--placeholder-prefix", "The prefix of the placeholders. Default: ${", CommandOptionType.SingleValue)] - public string PlaceholderPrefix { get; } = Default.PlaceholderPrefix; + [Option("--placeholder-prefix", "The prefix of the placeholders. Default: ${", CommandOptionType.SingleValue)] + public string PlaceholderPrefix { get; } = Default.PlaceholderPrefix; - [Option("--placeholder-suffix", "The suffix of the placeholders. Default: }", CommandOptionType.SingleValue)] - public string PlaceholderSuffix { get; } = Default.PlaceholderSuffix; + [Option("--placeholder-suffix", "The suffix of the placeholders. Default: }", CommandOptionType.SingleValue)] + public string PlaceholderSuffix { get; } = Default.PlaceholderSuffix; - [Option("--target-version", "Target version to reach. If empty it evolves all the way up.", CommandOptionType.SingleValue)] - public string TargetVersion { get; } + [Option("--target-version", "Target version to reach. If empty it evolves all the way up.", CommandOptionType.SingleValue)] + public string TargetVersion { get; } - [Option("--start-version", "Version used as starting point for already existing databases. Default: 0", CommandOptionType.SingleValue)] - public string StartVersion { get; } + [Option("--start-version", "Version used as starting point for already existing databases. Default: 0", CommandOptionType.SingleValue)] + public string StartVersion { get; } - [Option("--scripts-prefix", "Migration scripts file names prefix. Default: V", CommandOptionType.SingleValue)] - public string ScriptsPrefix { get; } = Default.SqlMigrationPrefix; + [Option("--scripts-prefix", "Migration scripts file names prefix. Default: V", CommandOptionType.SingleValue)] + public string ScriptsPrefix { get; } = Default.SqlMigrationPrefix; - [Option("--repeatable-scripts-prefix", "Repeatable migration scripts file names prefix. Default: R", CommandOptionType.SingleValue)] - public string RepeatableScriptsPrefix { get; } = Default.SqlRepeatableMigrationPrefix; + [Option("--repeatable-scripts-prefix", "Repeatable migration scripts file names prefix. Default: R", CommandOptionType.SingleValue)] + public string RepeatableScriptsPrefix { get; } = Default.SqlRepeatableMigrationPrefix; - [Option("--scripts-suffix", "Migration scripts files extension. Default: .sql", CommandOptionType.SingleValue)] - public string ScriptsSuffix { get; } = Default.SqlMigrationSuffix; + [Option("--scripts-suffix", "Migration scripts files extension. Default: .sql", CommandOptionType.SingleValue)] + public string ScriptsSuffix { get; } = Default.SqlMigrationSuffix; - [Option("--scripts-separator", "Migration scripts file names separator. Default: __", CommandOptionType.SingleValue)] - public string ScriptsSeparator { get; } = Default.SqlMigrationSeparator; + [Option("--scripts-separator", "Migration scripts file names separator. Default: __", CommandOptionType.SingleValue)] + public string ScriptsSeparator { get; } = Default.SqlMigrationSeparator; - [Option("--encoding", "The encoding of migration scripts. Default: UTF-8", CommandOptionType.SingleValue)] - public string Encoding { get; } = "UTF-8"; + [Option("--encoding", "The encoding of migration scripts. Default: UTF-8", CommandOptionType.SingleValue)] + public string Encoding { get; } = "UTF-8"; - [Option("--command-timeout", "The wait time in seconds before terminating the attempt to execute a migration and generating an error. Default: 30", CommandOptionType.SingleValue)] - public int? CommandTimeout { get; } = Default.CommandTimeout; + [Option("--command-timeout", "The wait time in seconds before terminating the attempt to execute a migration and generating an error. Default: 30", CommandOptionType.SingleValue)] + public int? CommandTimeout { get; } = Default.CommandTimeout; - [Option("--ambient-tx-timeout", "The wait time in seconds before terminating the attempt to execute a migration and generating an error in the ambient transaction. Default: 60", CommandOptionType.SingleValue)] - public int? AmbientTransactionTimeout { get; } = Default.AmbientTransactionTimeout; + [Option("--ambient-tx-timeout", "The wait time in seconds before terminating the attempt to execute a migration and generating an error in the ambient transaction. Default: 60", CommandOptionType.SingleValue)] + public int? AmbientTransactionTimeout { get; } = Default.AmbientTransactionTimeout; - [Option("--out-of-order", "Allows migration scripts to be run “out of order”. Default: false", CommandOptionType.SingleValue)] - public bool OutOfOrder { get; } = Default.OutOfOrder; + [Option("--out-of-order", "Allows migration scripts to be run “out of order”. Default: false", CommandOptionType.SingleValue)] + public bool OutOfOrder { get; } = Default.OutOfOrder; - [Option("--erase-disabled", "When set, ensures that Evolve will never erase schemas. Highly recommended in production. Default: false", CommandOptionType.SingleValue)] - public bool EraseDisabled { get; } = Default.IsEraseDisabled; + [Option("--erase-disabled", "When set, ensures that Evolve will never erase schemas. Highly recommended in production. Default: false", CommandOptionType.SingleValue)] + public bool EraseDisabled { get; } = Default.IsEraseDisabled; - [Option("--erase-on-validation-error", "When set, Evolve will erase the database schemas and will re-execute migration scripts from scratch if validation phase fails. Intended to be used in development only. Default: fasle", CommandOptionType.SingleValue)] - public bool EraseOnValidationError { get; } = Default.MustEraseOnValidationError; + [Option("--erase-on-validation-error", "When set, Evolve will erase the database schemas and will re-execute migration scripts from scratch if validation phase fails. Intended to be used in development only. Default: fasle", CommandOptionType.SingleValue)] + public bool EraseOnValidationError { get; } = Default.MustEraseOnValidationError; - [Option("--enable-cluster-mode", "By default, Evolve will use a session level lock to coordinate the migration on multiple nodes. Default: true", CommandOptionType.SingleValue)] - public bool EnableClusterMode { get; } = Default.EnableClusterMode; + [Option("--enable-cluster-mode", "By default, Evolve will use a session level lock to coordinate the migration on multiple nodes. Default: true", CommandOptionType.SingleValue)] + public bool EnableClusterMode { get; } = Default.EnableClusterMode; - [Option("-a|--embedded-resource-assembly", "When set, Evolve will scan the given list of assembly to load embedded migration scripts.", CommandOptionType.MultipleValue)] - public string[] EmbeddedResourceLocations { get; } + [Option("-a|--embedded-resource-assembly", "When set, Evolve will scan the given list of assembly to load embedded migration scripts.", CommandOptionType.MultipleValue)] + public string[] EmbeddedResourceLocations { get; } - [Option("-f|--embedded-resource-filter", "When set, exclude embedded migration scripts that do not start with one of these filters.", CommandOptionType.MultipleValue)] - public string[] EmbeddedResourceFilters { get; } - - [Option("--retry-repeatable", "When set, execute repeatedly all repeatable migrations for as long as the number of errors decreases, so that you can name them more easily. Default: false", CommandOptionType.SingleValue)] - public bool RetryRepeatableMigrationsUntilNoError { get; } = Default.RetryRepeatableMigrationsUntilNoError; + [Option("-f|--embedded-resource-filter", "When set, exclude embedded migration scripts that do not start with one of these filters.", CommandOptionType.MultipleValue)] + public string[] EmbeddedResourceFilters { get; } + + [Option("--retry-repeatable", "When set, execute repeatedly all repeatable migrations for as long as the number of errors decreases, so that you can name them more easily. Default: false", CommandOptionType.SingleValue)] + public bool RetryRepeatableMigrationsUntilNoError { get; } = Default.RetryRepeatableMigrationsUntilNoError; - [Option("--transaction-mode", "Scope of the Evolve transaction. Default: CommitEach", CommandOptionType.SingleValue)] - [AllowedValues("CommitEach", "CommitAll", "RollbackAll", IgnoreCase = true)] - public TransactionKind TransactionMode { get; } = Default.TransactionMode; + [Option("--transaction-mode", "Scope of the Evolve transaction. Default: CommitEach", CommandOptionType.SingleValue)] + [AllowedValues("CommitEach", "CommitAll", "RollbackAll", IgnoreCase = true)] + public TransactionKind TransactionMode { get; } = Default.TransactionMode; - [Option("--skip-next-migrations", "When set, mark all subsequent migrations as applied. Default: false", CommandOptionType.SingleValue)] - public bool SkipNextMigrations { get; } + [Option("--skip-next-migrations", "When set, mark all subsequent migrations as applied. Default: false", CommandOptionType.SingleValue)] + public bool SkipNextMigrations { get; } - // Cassandra - [Option("--keyspace", "A list of keyspaces managed by Evolve (Cassandra only).", CommandOptionType.MultipleValue)] - public string[] Keyspaces { get; } + // Cassandra + [Option("--keyspace", "A list of keyspaces managed by Evolve (Cassandra only).", CommandOptionType.MultipleValue)] + public string[] Keyspaces { get; } - [Option("--metadata-table-keyspace", "The keyspace in which the metadata table is/should be (Cassandra only).", CommandOptionType.SingleValue)] - public string MetadataTableKeyspace { get; } + [Option("--metadata-table-keyspace", "The keyspace in which the metadata table is/should be (Cassandra only).", CommandOptionType.SingleValue)] + public string MetadataTableKeyspace { get; } - // SQL Server - [Option("--sql-server-access-token", "An Azure-issued access token to be used when connecting to SQL Server.", CommandOptionType.SingleValue)] - public string SqlServerAccessToken { get; } - } + // SQL Server + [Option("--sql-server-access-token", "An Azure-issued access token to be used when connecting to SQL Server.", CommandOptionType.SingleValue)] + public string SqlServerAccessToken { get; } } diff --git a/src/Evolve.Tool/Evolve.Tool.csproj b/src/Evolve.Tool/Evolve.Tool.csproj index b7416964..339f1843 100644 --- a/src/Evolve.Tool/Evolve.Tool.csproj +++ b/src/Evolve.Tool/Evolve.Tool.csproj @@ -3,7 +3,7 @@ Exe - net5.0;net6.0 + net6.0;net7.0 true evolve EvolveDb.Tool @@ -24,7 +24,8 @@ Every time you build your project, it will automatically ensure that your databa evolve flyway dotnet tool sql database migration mysql sqlserver cassandra mariadb sqlite postgresql cockroachdb ## Features - #293 Add timeout for ambient transactions -- #189 Enabled use of Evolve CLI/Tool Placeholders with ':' in their value +- #189 Enabled use of Evolve CLI/Tool Placeholders with ':' in their value +- Add .NET 7 support, drop .NET 5 support diff --git a/src/Evolve/Evolve.csproj b/src/Evolve/Evolve.csproj index 1a6f370b..3234abe3 100644 --- a/src/Evolve/Evolve.csproj +++ b/src/Evolve/Evolve.csproj @@ -2,7 +2,7 @@ - netstandard2.0;net6.0 + netstandard2.0;net7.0 true true latest diff --git a/test/Evolve.Tests/Cli/CliTest.cs b/test/Evolve.Tests/Cli/CliTest.cs index e7bd172b..b69300e4 100644 --- a/test/Evolve.Tests/Cli/CliTest.cs +++ b/test/Evolve.Tests/Cli/CliTest.cs @@ -2,54 +2,38 @@ using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; +using System.Threading.Tasks; using EvolveDb.Tests.Infrastructure; using Xunit; using Xunit.Abstractions; namespace EvolveDb.Tests.Cli { - [Collection("Database collection")] public class CliTest { - private readonly PostgreSqlFixture _pgContainer; - private readonly MySQLFixture _mySQLContainer; - private readonly SQLServerFixture _sqlServerContainer; - private readonly CassandraFixture _cassandraContainer; - private readonly CockroachDBFixture _cockroachDBContainer; private readonly ITestOutputHelper _output; - public CliTest(PostgreSqlFixture pgContainer, MySQLFixture mySQLContainer, SQLServerFixture sqlServerContainer, CassandraFixture cassandraContainer, CockroachDBFixture cockroachDBContainer, ITestOutputHelper output) + public CliTest(ITestOutputHelper output) { - _pgContainer = pgContainer; - _mySQLContainer = mySQLContainer; - _sqlServerContainer = sqlServerContainer; - _cassandraContainer = cassandraContainer; - _cockroachDBContainer = cockroachDBContainer; _output = output; - - if (TestContext.Local || TestContext.AzureDevOps) - { - pgContainer.Run(); - sqlServerContainer.Run(); - cassandraContainer.Run(); - cockroachDBContainer.Run(); - if (TestContext.Local) - { - mySQLContainer.Run(); - } - } } [FactSkippedOnAppVeyor] [Category(Test.Cli, Test.CockroachDB)] - public void CockroachDB_Should_Run_All_Cli_Commands() + public async Task CockroachDB_Should_Run_All_Cli_Commands() { + var container = new CockroachDBContainer(); + if (TestContext.Local || TestContext.AzureDevOps) + { + await container.Start(); + } + foreach (var command in new[] { "erase", "migrate", "repair", "info" }) { string stderr = RunCli( db: "cockroachdb", command: command, - cnxStr: _cockroachDBContainer.CnxStr, + cnxStr: container.CnxStr, location: TestContext.CockroachDB.MigrationFolder, args: "-s evolve -s defaultdb"); @@ -59,8 +43,14 @@ public void CockroachDB_Should_Run_All_Cli_Commands() [FactSkippedOnAppVeyor] [Category(Test.Cli, Test.Cassandra)] - public void Cassandra_Should_Run_All_Cli_Commands() + public async Task Cassandra_Should_Run_All_Cli_Commands() { + var container = new CassandraContainer(); + if (TestContext.Local || TestContext.AzureDevOps) + { + await container.Start(); + } + string metadataKeyspaceName = "my_keyspace_3"; foreach (var command in new[] { "erase", "migrate", "repair", "info" }) @@ -68,7 +58,7 @@ public void Cassandra_Should_Run_All_Cli_Commands() string stderr = RunCli( db: "cassandra", command: command, - cnxStr: _cassandraContainer.CnxStr, + cnxStr: container.CnxStr, location: TestContext.CassandraDb.MigrationFolder, args: $"--scripts-suffix .cql -p keyspace:{metadataKeyspaceName} --keyspace {metadataKeyspaceName} --metadata-table-keyspace evolve_change_log"); @@ -78,14 +68,20 @@ public void Cassandra_Should_Run_All_Cli_Commands() [Fact] [Category(Test.Cli, Test.MySQL)] - public void MySQL_With_Embedded_Resources_Should_Run_All_Cli_Commands() + public async Task MySQL_With_Embedded_Resources_Should_Run_All_Cli_Commands() { + var container = new MySQLContainer(); + if (TestContext.Local || TestContext.AzureDevOps) + { + await container.Start(); + } + foreach (var command in new[] { "erase", "migrate", "repair", "info" }) { string stderr = RunCli( db: "mysql", command: command, - cnxStr: _mySQLContainer.CnxStr, + cnxStr: container.CnxStr, location: null, args: $"-a Evolve.Tests.dll -f {TestContext.MySQL.MigrationFolderFilter}"); @@ -95,16 +91,22 @@ public void MySQL_With_Embedded_Resources_Should_Run_All_Cli_Commands() [Fact] [Category(Test.Cli, Test.PostgreSQL)] - public void PostgreSql_Should_Run_All_Cli_Commands() + public async Task PostgreSql_Should_Run_All_Cli_Commands() { - foreach (var command in new [] { "erase", "migrate", "repair", "info" }) + var container = new PostgreSqlContainer(); + if (TestContext.Local || TestContext.AzureDevOps) + { + await container.Start(); + } + + foreach (var command in new[] { "erase", "migrate", "repair", "info" }) { string stderr = RunCli( db: "postgresql", command: command, - cnxStr: _pgContainer.CnxStr.Replace(PostgreSqlContainer.DbPwd, "${pwd}"), // add secret to the connection string + cnxStr: container.CnxStr.Replace(PostgreSqlContainer.DbPwd, "${pwd}"), // add secret to the connection string location: TestContext.PostgreSQL.MigrationFolder, - args: $"-s public -s unittest --metadata-table-schema unittest --erase-disabled false -p schema1:unittest -p pwd;{PostgreSqlContainer.DbPwd}"); + args: $"-s public -s unittest --metadata-table-schema unittest --erase-disabled false -p schema1:unittest -p pwd:{PostgreSqlContainer.DbPwd}"); Assert.True(string.IsNullOrEmpty(stderr), stderr); } @@ -112,17 +114,23 @@ public void PostgreSql_Should_Run_All_Cli_Commands() [Fact] [Category(Test.Cli, Test.SQLServer)] - public void SQLServer_Should_Run_All_Cli_Commands() + public async Task SQLServer_Should_Run_All_Cli_Commands() { + var container = new SQLServerContainer(); + if (TestContext.Local || TestContext.AzureDevOps) + { + await container.Start(); + } + string dbName = "my_database_3"; - TestUtil.CreateSqlServerDatabase(dbName, _sqlServerContainer.GetCnxStr("master")); + TestUtil.CreateSqlServerDatabase(dbName, container.CnxStr); foreach (var command in new[] { "erase", "migrate", "repair", "info" }) { string stderr = RunCli( db: "sqlserver", command: command, - cnxStr: _sqlServerContainer.GetCnxStr(dbName), + cnxStr: container.CnxStr, location: TestContext.SqlServer.MigrationFolder, args: $"-p db:{dbName} -p schema2:dbo --target-version 8_9"); diff --git a/test/Evolve.Tests/Connection/WrappedConnectionTest.cs b/test/Evolve.Tests/Connection/WrappedConnectionTest.cs index 36c74ca8..f0479821 100644 --- a/test/Evolve.Tests/Connection/WrappedConnectionTest.cs +++ b/test/Evolve.Tests/Connection/WrappedConnectionTest.cs @@ -7,24 +7,8 @@ namespace EvolveDb.Tests.Connection { - [Collection("PostgreSql collection")] - public class WrappedConnectionTest + public record WrappedConnectionTest : DbContainerFixture { - private static PostgreSqlFixture _pgContainer; - - public WrappedConnectionTest(PostgreSqlFixture pgContainer) - { - if (_pgContainer is null) - { - _pgContainer = pgContainer; - - if (TestContext.Local || TestContext.AzureDevOps) - { - pgContainer.Run(); - } - } - } - [Fact] [Category(Test.Connection)] public void Inner_dbconnection_can_not_be_null() @@ -36,7 +20,7 @@ public void Inner_dbconnection_can_not_be_null() [Category(Test.Connection)] public void When_disposed_inner_dbconnection_is_closed() { - var cnn = _pgContainer.CreateDbConnection(); + var cnn = CreateDbConnection(); using (var wrappedConnection = new WrappedConnection(cnn)) { wrappedConnection.Open(); @@ -49,7 +33,7 @@ public void When_disposed_inner_dbconnection_is_closed() [Category(Test.Connection)] public void Commit_a_null_transaction_throws_InvalidOperationException() { - var cnn = _pgContainer.CreateDbConnection(); + var cnn = CreateDbConnection(); using (var wrappedConnection = new WrappedConnection(cnn)) { Assert.Throws(() => wrappedConnection.Commit()); @@ -62,7 +46,7 @@ public void Commit_a_null_transaction_throws_InvalidOperationException() [Category(Test.Connection)] public void Rollback_a_null_transaction_throws_InvalidOperationException() { - var cnn = _pgContainer.CreateDbConnection(); + var cnn = CreateDbConnection(); using (var wrappedConnection = new WrappedConnection(cnn)) { Assert.Throws(() => wrappedConnection.Rollback()); @@ -75,7 +59,7 @@ public void Rollback_a_null_transaction_throws_InvalidOperationException() [Category(Test.Connection)] public void BeginTransaction_opens_a_connection_and_returns_a_transaction() { - var cnn = _pgContainer.CreateDbConnection(); + var cnn = CreateDbConnection(); using (var wrappedConnection = new WrappedConnection(cnn)) { var tx = wrappedConnection.BeginTransaction(); diff --git a/test/Evolve.Tests/Evolve.Tests.csproj b/test/Evolve.Tests/Evolve.Tests.csproj index 904b7ca3..e8c80e2c 100644 --- a/test/Evolve.Tests/Evolve.Tests.csproj +++ b/test/Evolve.Tests/Evolve.Tests.csproj @@ -1,17 +1,17 @@  - net6.0 + net7.0 false latest EvolveDb.Tests - + - - + + diff --git a/test/Evolve.Tests/Infrastructure/Cassandra/CassandraFixture.cs b/test/Evolve.Tests/Infrastructure/Cassandra/CassandraFixture.cs deleted file mode 100644 index c92895bd..00000000 --- a/test/Evolve.Tests/Infrastructure/Cassandra/CassandraFixture.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace EvolveDb.Tests.Infrastructure -{ - public class CassandraFixture : DbContainerFixture, IDisposable - { - } -} diff --git a/test/Evolve.Tests/Infrastructure/Cassandra/CassandraContainer.cs b/test/Evolve.Tests/Infrastructure/CassandraContainer.cs similarity index 66% rename from test/Evolve.Tests/Infrastructure/Cassandra/CassandraContainer.cs rename to test/Evolve.Tests/Infrastructure/CassandraContainer.cs index da692a4b..4d03e5ce 100644 --- a/test/Evolve.Tests/Infrastructure/Cassandra/CassandraContainer.cs +++ b/test/Evolve.Tests/Infrastructure/CassandraContainer.cs @@ -1,4 +1,5 @@ using System.Data.Common; +using System.Threading.Tasks; using Cassandra.Data; namespace EvolveDb.Tests.Infrastructure @@ -12,15 +13,14 @@ public class CassandraContainer : IDbContainer public const string DbUser = "postgres"; private DockerContainer _container; - private bool _disposedValue = false; public string Id => _container?.Id; public string CnxStr => $"Contact Points=127.0.0.1;Port={HostPort};Cluster Name={ClusterName}"; public int TimeOutInSec => 60; - public bool Start(bool fromScratch = false) + public async Task Start(bool fromScratch = false) { - _container = new DockerContainerBuilder(new DockerContainerBuilderOptions + _container = await new DockerContainerBuilder(new DockerContainerBuilderOptions { FromImage = "cassandra", Tag = "latest", @@ -31,27 +31,9 @@ public bool Start(bool fromScratch = false) RemovePreviousContainer = fromScratch }).Build(); - return _container.Start(); + return await _container.Start(); } public DbConnection CreateDbConnection() => new CqlConnection(CnxStr); - - protected virtual void Dispose(bool disposing) - { - if (!_disposedValue) - { - if (disposing) - { - _container?.Dispose(); - } - - _disposedValue = true; - } - } - - public void Dispose() - { - Dispose(true); - } } } diff --git a/test/Evolve.Tests/Infrastructure/CockroachDb/CockroachDbFixture.cs b/test/Evolve.Tests/Infrastructure/CockroachDb/CockroachDbFixture.cs deleted file mode 100644 index 37002cf0..00000000 --- a/test/Evolve.Tests/Infrastructure/CockroachDb/CockroachDbFixture.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Threading; - -namespace EvolveDb.Tests.Infrastructure -{ - public class CockroachDBFixture : DbContainerFixture, IDisposable - { - public override void Run(bool fromScratch = false) - { - base.Run(fromScratch); - - // Extra margin before executing queries - if (fromScratch) - { - Thread.Sleep(TimeSpan.FromSeconds(5)); - } - } - } -} diff --git a/test/Evolve.Tests/Infrastructure/CockroachDb/CockroachDbContainer.cs b/test/Evolve.Tests/Infrastructure/CockroachDbContainer.cs similarity index 63% rename from test/Evolve.Tests/Infrastructure/CockroachDb/CockroachDbContainer.cs rename to test/Evolve.Tests/Infrastructure/CockroachDbContainer.cs index 036305e9..64103e12 100644 --- a/test/Evolve.Tests/Infrastructure/CockroachDb/CockroachDbContainer.cs +++ b/test/Evolve.Tests/Infrastructure/CockroachDbContainer.cs @@ -1,4 +1,5 @@ using System.Data.Common; +using System.Threading.Tasks; using Npgsql; namespace EvolveDb.Tests.Infrastructure @@ -10,15 +11,14 @@ public class CockroachDBContainer : IDbContainer public const string DbName = "defaultdb"; private DockerContainer _container; - private bool _disposedValue = false; public string Id => _container?.Id; public string CnxStr => $"Host=localhost;Username=root;Port={HostPort};Database={DbName};"; public int TimeOutInSec => 8; - public bool Start(bool fromScratch = false) + public async Task Start(bool fromScratch = false) { - _container = new DockerContainerBuilder(new DockerContainerBuilderOptions + _container = await new DockerContainerBuilder(new DockerContainerBuilderOptions { FromImage = "cockroachdb/cockroach", Tag = "latest", @@ -29,27 +29,9 @@ public bool Start(bool fromScratch = false) Cmd = new[] { "start-single-node", "--insecure" } }).Build(); - return _container.Start(); + return await _container.Start(); } public DbConnection CreateDbConnection() => new NpgsqlConnection(CnxStr); - - protected virtual void Dispose(bool disposing) - { - if (!_disposedValue) - { - if (disposing) - { - _container?.Dispose(); - } - - _disposedValue = true; - } - } - - public void Dispose() - { - Dispose(true); - } } } diff --git a/test/Evolve.Tests/Infrastructure/MySQL/MySQLFixture.cs b/test/Evolve.Tests/Infrastructure/MySQL/MySQLFixture.cs deleted file mode 100644 index 3a5de067..00000000 --- a/test/Evolve.Tests/Infrastructure/MySQL/MySQLFixture.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace EvolveDb.Tests.Infrastructure -{ - public class MySQLFixture : DbContainerFixture, IDisposable - { - } -} diff --git a/test/Evolve.Tests/Infrastructure/MySQL/MySqlContainer.cs b/test/Evolve.Tests/Infrastructure/MySqlContainer.cs similarity index 67% rename from test/Evolve.Tests/Infrastructure/MySQL/MySqlContainer.cs rename to test/Evolve.Tests/Infrastructure/MySqlContainer.cs index edc0de80..b36a3f4e 100644 --- a/test/Evolve.Tests/Infrastructure/MySQL/MySqlContainer.cs +++ b/test/Evolve.Tests/Infrastructure/MySqlContainer.cs @@ -1,4 +1,5 @@ using System.Data.Common; +using System.Threading.Tasks; using MySqlConnector; namespace EvolveDb.Tests.Infrastructure @@ -12,15 +13,14 @@ public class MySQLContainer : IDbContainer public const string DbUser = "root"; private DockerContainer _container; - private bool _disposedValue = false; public string Id => _container?.Id; public string CnxStr => $"Server=127.0.0.1;Port={HostPort};Database={DbName};Uid={DbUser};Pwd={DbPwd};SslMode=none;Allow User Variables=True"; public int TimeOutInSec => 25; - public bool Start(bool fromScratch = false) + public async Task Start(bool fromScratch = false) { - _container = new DockerContainerBuilder(new DockerContainerBuilderOptions + _container = await new DockerContainerBuilder(new DockerContainerBuilderOptions { FromImage = "mariadb", Tag = "latest", @@ -31,27 +31,9 @@ public bool Start(bool fromScratch = false) RemovePreviousContainer = fromScratch }).Build(); - return _container.Start(); + return await _container.Start(); } public DbConnection CreateDbConnection() => new MySqlConnection(CnxStr); - - protected virtual void Dispose(bool disposing) - { - if (!_disposedValue) - { - if (disposing) - { - _container?.Dispose(); - } - - _disposedValue = true; - } - } - - public void Dispose() - { - Dispose(true); - } } } diff --git a/test/Evolve.Tests/Infrastructure/PostgreSql/PostgreSqlFixture.cs b/test/Evolve.Tests/Infrastructure/PostgreSql/PostgreSqlFixture.cs deleted file mode 100644 index 1b276d11..00000000 --- a/test/Evolve.Tests/Infrastructure/PostgreSql/PostgreSqlFixture.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Threading; - -namespace EvolveDb.Tests.Infrastructure -{ - public class PostgreSqlFixture : DbContainerFixture, IDisposable - { - public override void Run(bool fromScratch = false) - { - base.Run(fromScratch); - - // Extra margin before executing queries - if (fromScratch) - { - Thread.Sleep(TimeSpan.FromSeconds(3)); - } - } - } -} diff --git a/test/Evolve.Tests/Infrastructure/PostgreSql/PostgreSqlContainer.cs b/test/Evolve.Tests/Infrastructure/PostgreSqlContainer.cs similarity index 60% rename from test/Evolve.Tests/Infrastructure/PostgreSql/PostgreSqlContainer.cs rename to test/Evolve.Tests/Infrastructure/PostgreSqlContainer.cs index e538bd47..e937f86e 100644 --- a/test/Evolve.Tests/Infrastructure/PostgreSql/PostgreSqlContainer.cs +++ b/test/Evolve.Tests/Infrastructure/PostgreSqlContainer.cs @@ -1,5 +1,6 @@ -using System.Data.Common; -using Npgsql; +using Npgsql; +using System.Data.Common; +using System.Threading.Tasks; namespace EvolveDb.Tests.Infrastructure { @@ -12,15 +13,14 @@ public class PostgreSqlContainer : IDbContainer public const string DbUser = "postgres"; private DockerContainer _container; - private bool _disposedValue = false; public string Id => _container?.Id; - public string CnxStr => $"Server=127.0.0.1;Port={HostPort};Database={DbName};User Id={DbUser};Password={DbPwd};"; + public string CnxStr => $"Server=127.0.0.1;Port={HostPort};Database={DbName};User Id={DbUser};Password={DbPwd};Pooling=false"; public int TimeOutInSec => 5; - public bool Start(bool fromScratch = false) + public async Task Start(bool fromScratch = false) { - _container = new DockerContainerBuilder(new DockerContainerBuilderOptions + _container = await new DockerContainerBuilder(new DockerContainerBuilderOptions { FromImage = "postgres", Tag = "alpine", @@ -31,27 +31,9 @@ public bool Start(bool fromScratch = false) RemovePreviousContainer = fromScratch }).Build(); - return _container.Start(); + return await _container.Start(); } public DbConnection CreateDbConnection() => new NpgsqlConnection(CnxStr); - - protected virtual void Dispose(bool disposing) - { - if (!_disposedValue) - { - if (disposing) - { - _container?.Dispose(); - } - - _disposedValue = true; - } - } - - public void Dispose() - { - Dispose(true); - } } } diff --git a/test/Evolve.Tests/Infrastructure/SQLServer/SQLServerFixture.cs b/test/Evolve.Tests/Infrastructure/SQLServer/SQLServerFixture.cs deleted file mode 100644 index 0df22871..00000000 --- a/test/Evolve.Tests/Infrastructure/SQLServer/SQLServerFixture.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace EvolveDb.Tests.Infrastructure -{ - public class SQLServerFixture : DbContainerFixture, IDisposable - { - public string GetCnxStr(string dbName = "master") => CnxStr.Replace("master", dbName); - } -} diff --git a/test/Evolve.Tests/Infrastructure/SQLServer/SQLServerContainer.cs b/test/Evolve.Tests/Infrastructure/SQLServerContainer.cs similarity index 66% rename from test/Evolve.Tests/Infrastructure/SQLServer/SQLServerContainer.cs rename to test/Evolve.Tests/Infrastructure/SQLServerContainer.cs index df127377..01fe20dd 100644 --- a/test/Evolve.Tests/Infrastructure/SQLServer/SQLServerContainer.cs +++ b/test/Evolve.Tests/Infrastructure/SQLServerContainer.cs @@ -1,5 +1,6 @@ using System.Data.Common; using System.Data.SqlClient; +using System.Threading.Tasks; namespace EvolveDb.Tests.Infrastructure { @@ -12,15 +13,14 @@ public class SQLServerContainer : IDbContainer public const string DbUser = "sa"; private DockerContainer _container; - private bool _disposedValue = false; public string Id => _container?.Id; public string CnxStr => $"Server=127.0.0.1;Database={DbName};User Id={DbUser};Password={DbPwd};TrustServerCertificate=True"; public int TimeOutInSec => 60; - public bool Start(bool fromScratch = false) + public async Task Start(bool fromScratch = false) { - _container = new DockerContainerBuilder(new DockerContainerBuilderOptions + _container = await new DockerContainerBuilder(new DockerContainerBuilderOptions { FromImage = "mcr.microsoft.com/mssql/server", Tag = "latest", @@ -31,27 +31,9 @@ public bool Start(bool fromScratch = false) RemovePreviousContainer = fromScratch }).Build(); - return _container.Start(); + return await _container.Start(); } public DbConnection CreateDbConnection() => new SqlConnection(CnxStr); - - protected virtual void Dispose(bool disposing) - { - if (!_disposedValue) - { - if (disposing) - { - _container?.Dispose(); - } - - _disposedValue = true; - } - } - - public void Dispose() - { - Dispose(true); - } } } diff --git a/test/Evolve.Tests/Infrastructure/_Internal/DbContainerFixture.cs b/test/Evolve.Tests/Infrastructure/_Internal/DbContainerFixture.cs index 27efd92f..cb7a016d 100644 --- a/test/Evolve.Tests/Infrastructure/_Internal/DbContainerFixture.cs +++ b/test/Evolve.Tests/Infrastructure/_Internal/DbContainerFixture.cs @@ -1,33 +1,39 @@ using System; using System.Data; using System.Data.Common; -using System.Diagnostics.CodeAnalysis; using System.Threading; +using System.Threading.Tasks; +using Xunit; namespace EvolveDb.Tests.Infrastructure { - public interface IDbContainerFixture + public abstract record DbContainerFixture : IAsyncLifetime where T : IDbContainer, new() { - string CnxStr { get; } - void Run(bool fromScratch = false); - DbConnection CreateDbConnection(); - void Dispose(); - } + private static readonly SemaphoreSlim Semaphore = new(1); - public abstract class DbContainerFixture : IDbContainerFixture where T : IDbContainer, new() - { protected readonly T _container = new(); public string CnxStr => _container.CnxStr; + public virtual bool FromScratch { get; } = false; + public virtual bool MustRunContainer { get; } = TestContext.Local; + public virtual Action Initialize { get; } - [SuppressMessage("Design", "CA1031: Do not catch general exception types")] - public virtual void Run(bool fromScratch = false) + public DbConnection CreateDbConnection() => _container.CreateDbConnection(); + + public async Task InitializeAsync() { - int retries = 1; - bool isDbStarted = false; + await Semaphore.WaitAsync(); - _container.Start(fromScratch); + if (!MustRunContainer) + { + Initialize?.Invoke(); + return; + } + bool wasAlreadyStarted = !await _container.Start(FromScratch); + + int retries = 1; + bool isDbStarted = false; while (!isDbStarted) { if (retries > _container.TimeOutInSec) @@ -35,7 +41,8 @@ public virtual void Run(bool fromScratch = false) throw new Exception($"{typeof(T).Name} timed-out after {_container.TimeOutInSec} sec."); } - Thread.Sleep(TimeSpan.FromSeconds(1)); + await Task.Delay(TimeSpan.FromSeconds(1)); + try { using var cnn = CreateDbConnection(); @@ -45,10 +52,20 @@ public virtual void Run(bool fromScratch = false) catch { } retries++; } - } - public DbConnection CreateDbConnection() => _container.CreateDbConnection(); + if (!wasAlreadyStarted) + { + // Extra margin before executing queries + await Task.Delay(TimeSpan.FromSeconds(5)); + } + + Initialize?.Invoke(); + } - public void Dispose() => _container.Dispose(); + public Task DisposeAsync() + { + Semaphore.Release(); + return Task.CompletedTask; + } } } diff --git a/test/Evolve.Tests/Infrastructure/_Internal/DockerContainer.cs b/test/Evolve.Tests/Infrastructure/_Internal/DockerContainer.cs index e6e717d2..afba806b 100644 --- a/test/Evolve.Tests/Infrastructure/_Internal/DockerContainer.cs +++ b/test/Evolve.Tests/Infrastructure/_Internal/DockerContainer.cs @@ -1,14 +1,13 @@ -using System; -using Docker.DotNet; +using Docker.DotNet; using Docker.DotNet.Models; using EvolveDb.Utilities; +using System.Threading.Tasks; namespace EvolveDb.Tests.Infrastructure { - internal class DockerContainer : IDisposable + internal class DockerContainer { private readonly DockerClient _client; - private bool _disposedValue = false; public DockerContainer(DockerClient client, string id, bool isRunning) { @@ -20,36 +19,22 @@ public DockerContainer(DockerClient client, string id, bool isRunning) public string Id { get; } public bool IsRunning { get; private set; } - public bool Start() + /// + /// Returns false, if it was already running. Otherwise true. + /// + public async Task Start() { - if (!IsRunning) + if (IsRunning) { - IsRunning = _client.Containers.StartContainerAsync(Id, null).ConfigureAwait(false).GetAwaiter().GetResult(); + return false; } + IsRunning = await _client.Containers.StartContainerAsync(Id, null); return IsRunning; } - public bool Stop() => _client.Containers.StopContainerAsync(Id, new ContainerStopParameters()).ConfigureAwait(false).GetAwaiter().GetResult(); + public async Task Stop() => await _client.Containers.StopContainerAsync(Id, new ContainerStopParameters()); - public void Remove() => _client.Containers.RemoveContainerAsync(Id, new ContainerRemoveParameters()).ConfigureAwait(false).GetAwaiter().GetResult(); - - protected virtual void Dispose(bool disposing) - { - if (!_disposedValue) - { - if (disposing) - { - _client.Dispose(); - } - - _disposedValue = true; - } - } - - public void Dispose() - { - Dispose(true); - } + public async Task Remove() => await _client.Containers.RemoveContainerAsync(Id, new ContainerRemoveParameters()); } } diff --git a/test/Evolve.Tests/Infrastructure/_Internal/DockerContainerBuilder.cs b/test/Evolve.Tests/Infrastructure/_Internal/DockerContainerBuilder.cs index 353d3aea..d6e7ee80 100644 --- a/test/Evolve.Tests/Infrastructure/_Internal/DockerContainerBuilder.cs +++ b/test/Evolve.Tests/Infrastructure/_Internal/DockerContainerBuilder.cs @@ -2,15 +2,15 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; +using System.Threading.Tasks; using Docker.DotNet; using Docker.DotNet.Models; namespace EvolveDb.Tests.Infrastructure { - internal class DockerContainerBuilder : IDisposable + internal class DockerContainerBuilder { private readonly DockerClient _client; - private bool _disposedValue = false; public DockerContainerBuilder(DockerContainerBuilderOptions setupOptions) { @@ -48,10 +48,10 @@ public DockerContainerBuilder(DockerContainerBuilderOptions setupOptions) public bool RemovePreviousContainer { get; } public IList Cmd { get; } - public DockerContainer Build() + public async Task Build() { - var container = _client.Containers.ListContainersAsync(new ContainersListParameters { All = true }).ConfigureAwait(false).GetAwaiter().GetResult() - .FirstOrDefault(x => x.Names.Any(n => n.Equals("/" + Name, StringComparison.OrdinalIgnoreCase))); + var container = (await _client.Containers.ListContainersAsync(new ContainersListParameters { All = true })) + .FirstOrDefault(x => x.Names.Any(n => n.Equals("/" + Name, StringComparison.OrdinalIgnoreCase))); bool isRunning = container?.State == "running"; if (container != null && !RemovePreviousContainer) @@ -61,14 +61,14 @@ public DockerContainer Build() if (container != null && RemovePreviousContainer) { - using var oldContainer = new DockerContainer(_client, container.ID, isRunning); - oldContainer.Stop(); - oldContainer.Remove(); + var oldContainer = new DockerContainer(_client, container.ID, isRunning); + await oldContainer.Stop(); + await oldContainer.Remove(); } - _client.Images.CreateImageAsync(new ImagesCreateParameters { FromImage = FromImage, Tag = Tag }, null, new Progress()).ConfigureAwait(false).GetAwaiter().GetResult(); + await _client.Images.CreateImageAsync(new ImagesCreateParameters { FromImage = FromImage, Tag = Tag }, null, new Progress()); - var newContainer = _client.Containers.CreateContainerAsync(new CreateContainerParameters + var newContainer = await _client.Containers.CreateContainerAsync(new CreateContainerParameters { Image = $"{FromImage}:{Tag ?? "latest"}", Name = Name, @@ -82,27 +82,9 @@ public DockerContainer Build() { ExposedPort, new List { new PortBinding { HostIP = "localhost", HostPort = HostPort } } } } } - }).ConfigureAwait(false).GetAwaiter().GetResult(); + }); return new DockerContainer(_client, newContainer.ID, isRunning: false); } - - protected virtual void Dispose(bool disposing) - { - if (!_disposedValue) - { - if (disposing) - { - _client.Dispose(); - } - - _disposedValue = true; - } - } - - public void Dispose() - { - Dispose(true); - } } } diff --git a/test/Evolve.Tests/Infrastructure/_Internal/IDbContainer.cs b/test/Evolve.Tests/Infrastructure/_Internal/IDbContainer.cs index dd191129..7e1fb398 100644 --- a/test/Evolve.Tests/Infrastructure/_Internal/IDbContainer.cs +++ b/test/Evolve.Tests/Infrastructure/_Internal/IDbContainer.cs @@ -1,11 +1,11 @@ -using System; -using System.Data.Common; +using System.Data.Common; +using System.Threading.Tasks; namespace EvolveDb.Tests.Infrastructure { - public interface IDbContainer : IDisposable + public interface IDbContainer { - bool Start(bool fromScratch = false); + Task Start(bool fromScratch = false); string CnxStr { get; } int TimeOutInSec { get; } DbConnection CreateDbConnection(); diff --git a/test/Evolve.Tests/Integration/Cassandra/DialectTest.cs b/test/Evolve.Tests/Integration/Cassandra/DialectTest.cs index 36098e91..9cdc9dff 100644 --- a/test/Evolve.Tests/Integration/Cassandra/DialectTest.cs +++ b/test/Evolve.Tests/Integration/Cassandra/DialectTest.cs @@ -6,7 +6,7 @@ namespace EvolveDb.Tests.Integration.Cassandra { - public static class DialectTest + public record DialectTest : DbContainerFixture { /// /// Second part of the integration test. @@ -16,10 +16,12 @@ public static class DialectTest /// in the same test context, we merge the integration tests to only use one container. /// My guess, a possible Cassandra driver issue. /// - public static void Run_all_Cassandra_integration_tests_work(CassandraFixture dbContainer) + [FactSkippedOnAppVeyor] + [Category(Test.Cassandra)] + public void Run_all_Cassandra_integration_tests_work() { // Arrange - var cnn = dbContainer.CreateDbConnection(); + var cnn = CreateDbConnection(); var wcnn = new WrappedConnection(cnn).AssertDatabaseServerType(DBMS.Cassandra); var db = DatabaseHelperFactory.GetDatabaseHelper(DBMS.Cassandra, wcnn); string keyspaceName = "my_keyspace_2"; diff --git a/test/Evolve.Tests/Integration/Cassandra/MigrationTest.cs b/test/Evolve.Tests/Integration/Cassandra/MigrationTest.cs index 49b07198..160b5e80 100644 --- a/test/Evolve.Tests/Integration/Cassandra/MigrationTest.cs +++ b/test/Evolve.Tests/Integration/Cassandra/MigrationTest.cs @@ -1,36 +1,20 @@ -using System.Collections.Generic; -using EvolveDb.Tests.Infrastructure; -using Xunit; +using EvolveDb.Tests.Infrastructure; +using System.Collections.Generic; using Xunit.Abstractions; using static EvolveDb.Tests.TestContext; namespace EvolveDb.Tests.Integration.Cassandra { - [Collection("Cassandra collection")] - public class MigrationTest + public record MigrationTest(ITestOutputHelper Output) : DbContainerFixture { - private readonly CassandraFixture _dbContainer; - private readonly ITestOutputHelper _output; - - public MigrationTest(CassandraFixture dbContainer, ITestOutputHelper output) - { - _dbContainer = dbContainer; - _output = output; - - if (Local) - { - dbContainer.Run(fromScratch: true); - } - } - [FactSkippedOnAppVeyor] [Category(Test.Cassandra)] public void Run_all_Cassandra_integration_tests_work() { // Arrange string metadataKeyspaceName = "my_keyspace_1"; // this name must also be declared in _evolve.cassandra.json - var cnn = _dbContainer.CreateDbConnection(); - var evolve = new Evolve(cnn, msg => _output.WriteLine(msg)) + var cnn = CreateDbConnection(); + var evolve = new Evolve(cnn, msg => Output.WriteLine(msg)) { CommandTimeout = 25, MetadataTableSchema = metadataKeyspaceName, @@ -38,6 +22,7 @@ public void Run_all_Cassandra_integration_tests_work() Placeholders = new Dictionary { ["${keyspace}"] = metadataKeyspaceName }, SqlMigrationSuffix = ".cql" }; + evolve.Erase(); // Assert evolve.AssertInfoIsSuccessful(cnn) @@ -60,11 +45,6 @@ public void Run_all_Cassandra_integration_tests_work() evolve.ChangeLocations(CassandraDb.MigrationFolder) .AssertMigrateIsSuccessful(cnn) .AssertInfoIsSuccessful(cnn); - - evolve.AssertEraseIsSuccessful(cnn, e => e.IsEraseDisabled = false); - - // Call the second part of the Cassandra integration tests - DialectTest.Run_all_Cassandra_integration_tests_work(_dbContainer); } } } diff --git a/test/Evolve.Tests/Integration/CockroachDB/DialectTest.cs b/test/Evolve.Tests/Integration/CockroachDB/DialectTest.cs index c4639bbd..9e45fc35 100644 --- a/test/Evolve.Tests/Integration/CockroachDB/DialectTest.cs +++ b/test/Evolve.Tests/Integration/CockroachDB/DialectTest.cs @@ -2,31 +2,17 @@ using EvolveDb.Dialect; using EvolveDb.Dialect.CockroachDB; using EvolveDb.Tests.Infrastructure; -using Xunit; namespace EvolveDb.Tests.Integration.CockroachDb { - [Collection("CockroachDB collection")] - public class DialectTest + public record DialectTest : DbContainerFixture { - private readonly CockroachDBFixture _dbContainer; - - public DialectTest(CockroachDBFixture dbContainer) - { - _dbContainer = dbContainer; - - if (TestContext.Local) - { - dbContainer.Run(fromScratch: true); - } - } - [FactSkippedOnAppVeyor] [Category(Test.CockroachDB)] public void Run_all_CockroachDB_integration_tests_work() { // Arrange - var cnn = _dbContainer.CreateDbConnection(); + var cnn = CreateDbConnection(); var wcnn = new WrappedConnection(cnn).AssertDatabaseServerType(DBMS.CockroachDB); var db = DatabaseHelperFactory.GetDatabaseHelper(DBMS.CockroachDB, wcnn); string schemaName = "MyDatabase"; diff --git a/test/Evolve.Tests/Integration/CockroachDB/MigrationTest.cs b/test/Evolve.Tests/Integration/CockroachDB/MigrationTest.cs index ce2fbfd8..ca016597 100644 --- a/test/Evolve.Tests/Integration/CockroachDB/MigrationTest.cs +++ b/test/Evolve.Tests/Integration/CockroachDB/MigrationTest.cs @@ -1,37 +1,22 @@ using EvolveDb.Tests.Infrastructure; -using Xunit; using Xunit.Abstractions; using static EvolveDb.Tests.TestContext; namespace EvolveDb.Tests.Integration.CockroachDb { - [Collection("CockroachDB collection")] - public class MigrationTests + public record MigrationTests(ITestOutputHelper Output) : DbContainerFixture { - private readonly CockroachDBFixture _dbContainer; - private readonly ITestOutputHelper _output; - - public MigrationTests(CockroachDBFixture dbContainer, ITestOutputHelper output) - { - _dbContainer = dbContainer; - _output = output; - - if (Local) - { - dbContainer.Run(fromScratch: true); - } - } - [FactSkippedOnAppVeyor] [Category(Test.CockroachDB)] public void Run_all_CockroachDB_migrations_work() { // Arrange - var cnn = _dbContainer.CreateDbConnection(); - var evolve = new Evolve(cnn, msg => _output.WriteLine(msg)) + var cnn = CreateDbConnection(); + var evolve = new Evolve(cnn, msg => Output.WriteLine(msg)) { Schemas = new[] { "evolve", "defaultdb" }, // MetadataTableSchema = evolve | migrations = defaultdb }; + evolve.Erase(); // Assert evolve.AssertInfoIsSuccessful(cnn) diff --git a/test/Evolve.Tests/Integration/MySQL/DialectTest.cs b/test/Evolve.Tests/Integration/MySQL/DialectTest.cs index 596c68ff..d800fcc2 100644 --- a/test/Evolve.Tests/Integration/MySQL/DialectTest.cs +++ b/test/Evolve.Tests/Integration/MySQL/DialectTest.cs @@ -6,40 +6,28 @@ namespace EvolveDb.Tests.Integration.MySql { - [Collection("MySQL collection")] - public class DialectTest + public record DialectTest : DbContainerFixture { - private readonly MySQLFixture _dbContainer; - - public DialectTest(MySQLFixture dbContainer) - { - _dbContainer = dbContainer; - - if (TestContext.Local) - { - dbContainer.Run(fromScratch: true); - } - } - [Fact] [Category(Test.MySQL)] public void Run_all_MySQL_integration_tests_work() { // Arrange - var cnn = _dbContainer.CreateDbConnection(); + var cnn = CreateDbConnection(); var wcnn = new WrappedConnection(cnn).AssertDatabaseServerType(DBMS.MySQL); var db = DatabaseHelperFactory.GetDatabaseHelper(DBMS.MySQL, wcnn); string schemaName = "My metadata schema"; var schema = new MySQLSchema(schemaName, wcnn); // Assert + schema.Drop(); schema.AssertIsNotExists(); schema.AssertCreation(); schema.AssertExists(); schema.AssertIsEmpty(); db.AssertDefaultSchemaName(MySQLContainer.DbName) - .AssertApplicationLock(_dbContainer.CreateDbConnection()) + .AssertApplicationLock(CreateDbConnection()) .AssertMetadataTableCreation(schemaName, "change log") .AssertMetadataTableLock() .AssertSchemaIsDroppableWhenNewSchemaFound(schemaName) // id:1 diff --git a/test/Evolve.Tests/Integration/MySQL/MigrationTest.cs b/test/Evolve.Tests/Integration/MySQL/MigrationTest.cs index 1e3d9a29..58c0f492 100644 --- a/test/Evolve.Tests/Integration/MySQL/MigrationTest.cs +++ b/test/Evolve.Tests/Integration/MySQL/MigrationTest.cs @@ -5,35 +5,21 @@ namespace EvolveDb.Tests.Integration.MySql { - [Collection("MySQL collection")] - public class MigrationTest + public record MigrationTest(ITestOutputHelper Output) : DbContainerFixture { - private readonly MySQLFixture _dbContainer; - private readonly ITestOutputHelper _output; - - public MigrationTest(MySQLFixture dbContainer, ITestOutputHelper output) - { - _dbContainer = dbContainer; - _output = output; - - if (Local) - { - dbContainer.Run(fromScratch: true); - } - } - [Fact] [Category(Test.MySQL)] public void Run_all_MySQL_migrations_work() { // Arrange - var cnn = _dbContainer.CreateDbConnection(); - var evolve = new Evolve(cnn, msg => _output.WriteLine(msg)) + var cnn = CreateDbConnection(); + var evolve = new Evolve(cnn, msg => Output.WriteLine(msg)) { EmbeddedResourceAssemblies = new[] { typeof(TestContext).Assembly }, EmbeddedResourceFilters = new[] { MySQL.MigrationFolderFilter }, CommandTimeout = 25 }; + evolve.Erase(); // Assert evolve.ChangeLocations(MySQL.MigrationFolder) diff --git a/test/Evolve.Tests/Integration/PostgreSQL/DialectTest.cs b/test/Evolve.Tests/Integration/PostgreSQL/DialectTest.cs index 49f38d30..7eb274f5 100644 --- a/test/Evolve.Tests/Integration/PostgreSQL/DialectTest.cs +++ b/test/Evolve.Tests/Integration/PostgreSQL/DialectTest.cs @@ -6,31 +6,19 @@ namespace EvolveDb.Tests.Integration.PostgregSql { - [Collection("PostgreSql collection")] - public class DialectTest + public record DialectTest : DbContainerFixture { - private readonly PostgreSqlFixture _dbContainer; - - public DialectTest(PostgreSqlFixture dbContainer) - { - _dbContainer = dbContainer; - - if (TestContext.Local) - { - dbContainer.Run(fromScratch: true); - } - } - [Fact] [Category(Test.PostgreSQL)] public void Run_all_PostgreSQL_integration_tests_work() { // Arrange - var cnn = _dbContainer.CreateDbConnection(); + var cnn = CreateDbConnection(); var wcnn = new WrappedConnection(cnn).AssertDatabaseServerType(DBMS.PostgreSQL); var db = DatabaseHelperFactory.GetDatabaseHelper(DBMS.PostgreSQL, wcnn); string schemaName = "My metadata schema"; var schema = new PostgreSQLSchema(schemaName, wcnn); + schema.Drop(); // Assert schema.AssertIsNotExists(); @@ -39,7 +27,7 @@ public void Run_all_PostgreSQL_integration_tests_work() schema.AssertIsEmpty(); db.AssertDefaultSchemaName("public") - .AssertApplicationLock(_dbContainer.CreateDbConnection()) + .AssertApplicationLock(CreateDbConnection()) .AssertMetadataTableCreation(schemaName, "changelog") .AssertMetadataTableLock() .AssertSchemaIsDroppableWhenNewSchemaFound(schemaName) // id:1 diff --git a/test/Evolve.Tests/Integration/PostgreSQL/MigrationTest.cs b/test/Evolve.Tests/Integration/PostgreSQL/MigrationTest.cs index e8f3dae2..92c7b79b 100644 --- a/test/Evolve.Tests/Integration/PostgreSQL/MigrationTest.cs +++ b/test/Evolve.Tests/Integration/PostgreSQL/MigrationTest.cs @@ -1,42 +1,28 @@ -using System.Collections.Generic; -using EvolveDb.Dialect; +using EvolveDb.Dialect; using EvolveDb.Tests.Infrastructure; +using System.Collections.Generic; using Xunit; using Xunit.Abstractions; using static EvolveDb.Tests.TestContext; namespace EvolveDb.Tests.Integration.PostgregSql { - [Collection("PostgreSql collection")] - public class MigrationTests + public record MigrationTests(ITestOutputHelper Output) : DbContainerFixture { - private readonly PostgreSqlFixture _dbContainer; - private readonly ITestOutputHelper _output; - - public MigrationTests(PostgreSqlFixture dbContainer, ITestOutputHelper output) - { - _dbContainer = dbContainer; - _output = output; - - if (Local) - { - dbContainer.Run(fromScratch: true); - } - } - [Fact] [Category(Test.PostgreSQL)] public void Run_all_PostgreSQL_migrations_work() { // Arrange string[] locations = AppVeyor ? new[] { PostgreSQL.MigrationFolder } : new[] { PostgreSQL.MigrationFolder, PostgreSQL.Migration11Folder }; // Add specific PostgreSQL 11 scripts - var cnn = _dbContainer.CreateDbConnection(); - var evolve = new Evolve(cnn, msg => _output.WriteLine(msg), DBMS.PostgreSQL) + var cnn = CreateDbConnection(); + var evolve = new Evolve(cnn, msg => Output.WriteLine(msg), DBMS.PostgreSQL) { Schemas = new[] { "public", "unittest" }, MetadataTableSchema = "unittest", Placeholders = new Dictionary { ["${schema1}"] = "unittest" } }; + evolve.Erase(); // Assert evolve.AssertInfoIsSuccessful(cnn) diff --git a/test/Evolve.Tests/Integration/PostgreSQL/Scenario001.cs b/test/Evolve.Tests/Integration/PostgreSQL/Scenario001.cs index 6627237c..2e10b1fc 100644 --- a/test/Evolve.Tests/Integration/PostgreSQL/Scenario001.cs +++ b/test/Evolve.Tests/Integration/PostgreSQL/Scenario001.cs @@ -4,14 +4,8 @@ namespace EvolveDb.Tests.Integration.PostgreSql { - [Collection("PostgreSql collection")] - public class Scenario001 : Scenario + public record Scenario001(ITestOutputHelper Output) : Scenario(Output) { - public Scenario001(PostgreSqlFixture dbContainer, ITestOutputHelper output) - : base(dbContainer, output) - { - } - [Fact] [Category(Test.PostgreSQL, Test.Sceanario)] public void Scenario_retry_repeatable_migrations_until_no_error() diff --git a/test/Evolve.Tests/Integration/PostgreSQL/Scenario002.cs b/test/Evolve.Tests/Integration/PostgreSQL/Scenario002.cs index d595c0dd..5733e863 100644 --- a/test/Evolve.Tests/Integration/PostgreSQL/Scenario002.cs +++ b/test/Evolve.Tests/Integration/PostgreSQL/Scenario002.cs @@ -4,14 +4,8 @@ namespace EvolveDb.Tests.Integration.PostgreSql { - [Collection("PostgreSql collection")] - public class Scenario002 : Scenario + public record Scenario002(ITestOutputHelper Output) : Scenario(Output) { - public Scenario002(PostgreSqlFixture dbContainer, ITestOutputHelper output) - : base(dbContainer, output) - { - } - [Fact] [Category(Test.PostgreSQL, Test.Sceanario)] public void Scenario_retry_repeatable_migrations_until_no_progression() diff --git a/test/Evolve.Tests/Integration/PostgreSQL/Scenario003.cs b/test/Evolve.Tests/Integration/PostgreSQL/Scenario003.cs index 90793143..59d666bd 100644 --- a/test/Evolve.Tests/Integration/PostgreSQL/Scenario003.cs +++ b/test/Evolve.Tests/Integration/PostgreSQL/Scenario003.cs @@ -6,11 +6,8 @@ namespace EvolveDb.Tests.Integration.PostgreSql { - [Collection("PostgreSql collection")] - public class Scenario003 : Scenario + public record Scenario003(ITestOutputHelper Output) : Scenario(Output) { - public Scenario003(PostgreSqlFixture dbContainer, ITestOutputHelper output) : base(dbContainer, output) {} - [Fact] [Category(Test.PostgreSQL, Test.Sceanario)] public void Scenario_postresql_tx_commit_all_only_when_every_scripts_succeed() diff --git a/test/Evolve.Tests/Integration/PostgreSQL/Scenario004.cs b/test/Evolve.Tests/Integration/PostgreSQL/Scenario004.cs index 9ba9dd38..76c14021 100644 --- a/test/Evolve.Tests/Integration/PostgreSQL/Scenario004.cs +++ b/test/Evolve.Tests/Integration/PostgreSQL/Scenario004.cs @@ -6,11 +6,8 @@ namespace EvolveDb.Tests.Integration.PostgreSql { - [Collection("PostgreSql collection")] - public class Scenario004 : Scenario + public record Scenario004(ITestOutputHelper Output) : Scenario(Output) { - public Scenario004(PostgreSqlFixture dbContainer, ITestOutputHelper output) : base(dbContainer, output) {} - [Fact] [Category(Test.PostgreSQL, Test.Sceanario)] public void Scenario_postresql_tx_rollback_all_either_when_migration_succeeds_or_fails() diff --git a/test/Evolve.Tests/Integration/PostgreSQL/Scenario005.cs b/test/Evolve.Tests/Integration/PostgreSQL/Scenario005.cs index c6a5dde7..cbb0c0fe 100644 --- a/test/Evolve.Tests/Integration/PostgreSQL/Scenario005.cs +++ b/test/Evolve.Tests/Integration/PostgreSQL/Scenario005.cs @@ -4,11 +4,8 @@ namespace EvolveDb.Tests.Integration.PostgreSql { - [Collection("PostgreSql collection")] - public class Scenario005 : Scenario + public record Scenario005(ITestOutputHelper Output) : Scenario(Output) { - public Scenario005(PostgreSqlFixture dbContainer, ITestOutputHelper output) : base(dbContainer, output) {} - [Fact] [Category(Test.PostgreSQL, Test.Sceanario)] public void Scenario_skip_migration_until_target_version_is_reached() diff --git a/test/Evolve.Tests/Integration/PostgreSQL/Scenario006.cs b/test/Evolve.Tests/Integration/PostgreSQL/Scenario006.cs index c9eada87..66fa1e9f 100644 --- a/test/Evolve.Tests/Integration/PostgreSQL/Scenario006.cs +++ b/test/Evolve.Tests/Integration/PostgreSQL/Scenario006.cs @@ -5,11 +5,8 @@ namespace EvolveDb.Tests.Integration.PostgreSql { - [Collection("PostgreSql collection")] - public class Scenario006 : Scenario + public record Scenario006(ITestOutputHelper Output) : Scenario(Output) { - public Scenario006(PostgreSqlFixture dbContainer, ITestOutputHelper output) : base(dbContainer, output) {} - [Fact] [Category(Test.PostgreSQL, Test.Sceanario)] public void Scenario_repeatable_migration_executed_everytime() diff --git a/test/Evolve.Tests/Integration/PostgreSQL/Scenario007.cs b/test/Evolve.Tests/Integration/PostgreSQL/Scenario007.cs index 21028c1b..c6126643 100644 --- a/test/Evolve.Tests/Integration/PostgreSQL/Scenario007.cs +++ b/test/Evolve.Tests/Integration/PostgreSQL/Scenario007.cs @@ -8,11 +8,8 @@ namespace EvolveDb.Tests.Integration.PostgreSql { - [Collection("PostgreSql collection")] - public class Scenario007 : Scenario + public record Scenario007(ITestOutputHelper Output) : Scenario(Output) { - public Scenario007(PostgreSqlFixture dbContainer, ITestOutputHelper output) : base(dbContainer, output) {} - [Fact] [Category(Test.PostgreSQL, Test.Sceanario)] public void Scenario_use_a_custom_migration_loader_only_when_is_set() diff --git a/test/Evolve.Tests/Integration/PostgreSQL/Scenario008.cs b/test/Evolve.Tests/Integration/PostgreSQL/Scenario008.cs index b1bbee65..2fc4acc9 100644 --- a/test/Evolve.Tests/Integration/PostgreSQL/Scenario008.cs +++ b/test/Evolve.Tests/Integration/PostgreSQL/Scenario008.cs @@ -5,11 +5,8 @@ namespace EvolveDb.Tests.Integration.PostgreSql { - [Collection("PostgreSql collection")] - public class Scenario008 : Scenario + public record Scenario008(ITestOutputHelper Output) : Scenario(Output) { - public Scenario008(PostgreSqlFixture dbContainer, ITestOutputHelper output) : base(dbContainer, output) {} - [Fact] [Category(Test.PostgreSQL, Test.Sceanario)] public void Scenario_check_validation() diff --git a/test/Evolve.Tests/Integration/PostgreSQL/Scenario009.cs b/test/Evolve.Tests/Integration/PostgreSQL/Scenario009.cs index d7e9ca59..64667f59 100644 --- a/test/Evolve.Tests/Integration/PostgreSQL/Scenario009.cs +++ b/test/Evolve.Tests/Integration/PostgreSQL/Scenario009.cs @@ -4,11 +4,8 @@ namespace EvolveDb.Tests.Integration.PostgreSql { - [Collection("PostgreSql collection")] - public class Scenario009 : Scenario + public record Scenario009(ITestOutputHelper Output) : Scenario(Output) { - public Scenario009(PostgreSqlFixture dbContainer, ITestOutputHelper output) : base(dbContainer, output) {} - [Fact] [Category(Test.PostgreSQL, Test.Sceanario)] public void Scenario_drop_extension_should_work() diff --git a/test/Evolve.Tests/Integration/SQLServer/DialectTest.cs b/test/Evolve.Tests/Integration/SQLServer/DialectTest.cs index 978a17ae..3fd8d413 100644 --- a/test/Evolve.Tests/Integration/SQLServer/DialectTest.cs +++ b/test/Evolve.Tests/Integration/SQLServer/DialectTest.cs @@ -1,45 +1,32 @@ -using System.Data.SqlClient; -using EvolveDb.Connection; +using EvolveDb.Connection; using EvolveDb.Dialect; using EvolveDb.Dialect.SQLServer; using EvolveDb.Tests.Infrastructure; +using System.Data.SqlClient; using Xunit; -using static EvolveDb.Tests.TestContext; namespace EvolveDb.Tests.Integration.SQLServer { - [Collection("SQLServer collection")] - public class DialectTest + public record DialectTest : DbContainerFixture { public const string DbName = "my_database_1"; - private readonly SQLServerFixture _dbContainer; - - public DialectTest(SQLServerFixture dbContainer) - { - _dbContainer = dbContainer; - - if (Local) - { - dbContainer.Run(fromScratch: true); - } - - TestUtil.CreateSqlServerDatabase(DbName, _dbContainer.GetCnxStr("master")); - } [Fact] [Category(Test.SQLServer)] public void Run_all_SQLServer_integration_tests_work() { // Arrange - var cnn = new SqlConnection(_dbContainer.GetCnxStr(DbName)); + TestUtil.CreateSqlServerDatabase(DbName, CnxStr); + var cnn = new SqlConnection(CnxStr.Replace("master", DbName)); var wcnn = new WrappedConnection(cnn).AssertDatabaseServerType(DBMS.SQLServer); var db = DatabaseHelperFactory.GetDatabaseHelper(DBMS.SQLServer, wcnn); string schemaName = "dbo"; var schema = new SQLServerSchema(schemaName, wcnn); + schema.Erase(); // Assert db.AssertDefaultSchemaName(schemaName) - .AssertApplicationLock(new SqlConnection(_dbContainer.GetCnxStr(DbName))) + .AssertApplicationLock(new SqlConnection(CnxStr.Replace("master", DbName))) .AssertMetadataTableCreation(schemaName, "changelog") .AssertMetadataTableLock() .AssertSchemaIsErasableWhenEmptySchemaFound(schemaName) // id:1 diff --git a/test/Evolve.Tests/Integration/SQLServer/MigrationTest.cs b/test/Evolve.Tests/Integration/SQLServer/MigrationTest.cs index 9a1fa3f7..1e2e814a 100644 --- a/test/Evolve.Tests/Integration/SQLServer/MigrationTest.cs +++ b/test/Evolve.Tests/Integration/SQLServer/MigrationTest.cs @@ -1,44 +1,30 @@ -using System.Collections.Generic; -using System.Data.SqlClient; -using EvolveDb.Migration; +using EvolveDb.Migration; using EvolveDb.Tests.Infrastructure; +using System.Collections.Generic; +using System.Data.SqlClient; using Xunit; using Xunit.Abstractions; using static EvolveDb.Tests.TestContext; namespace EvolveDb.Tests.Integration.SQLServer { - [Collection("SQLServer collection")] - public class MigrationTest + public record MigrationTest(ITestOutputHelper Output) : DbContainerFixture { public const string DbName = "my_database_2"; - private readonly SQLServerFixture _dbContainer; - private readonly ITestOutputHelper _output; - - public MigrationTest(SQLServerFixture dbContainer, ITestOutputHelper output) - { - _dbContainer = dbContainer; - _output = output; - - if (Local) - { - dbContainer.Run(fromScratch: true); - } - - TestUtil.CreateSqlServerDatabase(DbName, _dbContainer.GetCnxStr("master")); - } [Fact] [Category(Test.SQLServer)] public void Run_all_SQLServer_migrations_work() { // Arrange - var cnn = new SqlConnection(_dbContainer.GetCnxStr(DbName)); - var evolve = new Evolve(cnn, msg => _output.WriteLine(msg)) + TestUtil.CreateSqlServerDatabase(DbName, CnxStr); + var cnn = new SqlConnection(CnxStr.Replace("master", DbName)); + var evolve = new Evolve(cnn, msg => Output.WriteLine(msg)) { Placeholders = new Dictionary { ["${db}"] = DbName, ["${schema2}"] = "dbo" }, TargetVersion = new MigrationVersion("8_9"), }; + evolve.Erase(); // Assert evolve.AssertInfoIsSuccessful(cnn) diff --git a/test/Evolve.Tests/Integration/SQLServer/Scenario101.cs b/test/Evolve.Tests/Integration/SQLServer/Scenario101.cs index 6ea68352..0f1fd973 100644 --- a/test/Evolve.Tests/Integration/SQLServer/Scenario101.cs +++ b/test/Evolve.Tests/Integration/SQLServer/Scenario101.cs @@ -6,10 +6,9 @@ namespace EvolveDb.Tests.Integration.SQLServer { - [Collection("SQLServer collection")] - public class Scenario101 : Scenario + public record Scenario101 : Scenario { - public Scenario101(SQLServerFixture dbContainer, ITestOutputHelper output) : base(dbContainer, output) { } + public Scenario101(ITestOutputHelper output) : base(output) { } [Fact] [Category(Test.SQLServer, Test.Sceanario)] diff --git a/test/Evolve.Tests/Integration/SQLServer/Scenario102.cs b/test/Evolve.Tests/Integration/SQLServer/Scenario102.cs index a833616c..05b07058 100644 --- a/test/Evolve.Tests/Integration/SQLServer/Scenario102.cs +++ b/test/Evolve.Tests/Integration/SQLServer/Scenario102.cs @@ -6,10 +6,9 @@ namespace EvolveDb.Tests.Integration.SQLServer { - [Collection("SQLServer collection")] - public class Scenario102 : Scenario + public record Scenario102 : Scenario { - public Scenario102(SQLServerFixture dbContainer, ITestOutputHelper output) : base(dbContainer, output) { } + public Scenario102(ITestOutputHelper output) : base(output) { } [Fact] [Category(Test.SQLServer, Test.Sceanario)] diff --git a/test/Evolve.Tests/Integration/ScenarioBase.cs b/test/Evolve.Tests/Integration/ScenarioBase.cs index 9939cb58..b483a62c 100644 --- a/test/Evolve.Tests/Integration/ScenarioBase.cs +++ b/test/Evolve.Tests/Integration/ScenarioBase.cs @@ -1,61 +1,30 @@ -using System; -using System.Data.Common; -using System.Data.SqlClient; -using System.IO; -using EvolveDb.Connection; +using EvolveDb.Connection; using EvolveDb.Dialect; using EvolveDb.Metadata; using EvolveDb.Tests.Infrastructure; +using System; +using System.Data.Common; +using System.Data.SqlClient; +using System.IO; using Xunit.Abstractions; using static EvolveDb.Tests.TestContext; namespace EvolveDb.Tests.Integration { - public abstract class Scenario where T : IDbContainerFixture + public abstract record Scenario(ITestOutputHelper Output) : DbContainerFixture where T : IDbContainer, new() { - protected readonly T _dbContainer; - protected readonly ITestOutputHelper _output; - - public Scenario(T dbContainer, ITestOutputHelper output) - { - _dbContainer = dbContainer; - _output = output; - - if (Local) - { - dbContainer.Run(fromScratch: true); - } - - if (Dbms == DBMS.SQLServer) - { - TestUtil.CreateSqlServerDatabase(DbName, (_dbContainer as SQLServerFixture).GetCnxStr("master")); - Cnn = new SqlConnection((_dbContainer as SQLServerFixture).GetCnxStr(DbName)); - } - else - { - Cnn = _dbContainer.CreateDbConnection(); - } - - WrappedConnection = new WrappedConnection(Cnn); - Evolve = new Evolve(Cnn, msg => _output.WriteLine(msg)) - { - Schemas = new[] { SchemaName }, - MetadataTableSchema = SchemaName, - Locations = new[] { ScenarioFolder }, - Placeholders = new() { ["${db}"] = DbName, ["${schema}"] = SchemaName }, - }; - } + protected readonly T _dbContainer = new(); - public DbConnection Cnn { get; } - internal WrappedConnection WrappedConnection { get; } - public Evolve Evolve { get; } + public DbConnection Cnn { get; private set; } + internal WrappedConnection WrappedConnection { get; private set; } + public Evolve Evolve { get; private set; } public DBMS Dbms => typeof(T).Name switch { - "CassandraFixture" => DBMS.Cassandra, - "CockroachDbFixture" => DBMS.CockroachDB, - "MySQLFixture" => DBMS.MySQL, - "PostgreSqlFixture" => DBMS.PostgreSQL, - "SQLServerFixture" => DBMS.SQLServer, + "CassandraContainer" => DBMS.Cassandra, + "CockroachDbContainer" => DBMS.CockroachDB, + "MySQLContainer" => DBMS.MySQL, + "PostgreSqlContainer" => DBMS.PostgreSQL, + "SQLServerContainer" => DBMS.SQLServer, _ => throw new NotSupportedException($"{typeof(T).Name} not supported.") }; public string DbName => Dbms == DBMS.SQLServer ? GetType().Name : ""; @@ -79,5 +48,31 @@ public Scenario(T dbContainer, ITestOutputHelper output) DBMS.SQLServer => Path.Combine(SqlServer.SqlScriptsFolder, GetType().Name), _ => throw new NotSupportedException($"{typeof(T).Name} not supported.") }; + + public override Action Initialize => Init; + + private void Init() + { + if (Dbms == DBMS.SQLServer) + { + TestUtil.CreateSqlServerDatabase(DbName, CnxStr); + Cnn = new SqlConnection(CnxStr.Replace("master", DbName)); + } + else + { + Cnn = _dbContainer.CreateDbConnection(); + } + + WrappedConnection = new WrappedConnection(Cnn); + Evolve = new Evolve(Cnn, msg => Output.WriteLine(msg), Dbms) + { + Schemas = new[] { SchemaName }, + MetadataTableSchema = SchemaName, + Locations = new[] { ScenarioFolder }, + Placeholders = new() { ["${db}"] = DbName, ["${schema}"] = SchemaName }, + }; + + Evolve.Erase(); + } } } diff --git a/test/Evolve.Tests/TestContext.cs b/test/Evolve.Tests/TestContext.cs index 1d2bec48..0d32625c 100644 --- a/test/Evolve.Tests/TestContext.cs +++ b/test/Evolve.Tests/TestContext.cs @@ -1,10 +1,8 @@ -using System; +using EvolveDb.Metadata; +using EvolveDb.Migration; +using System; using System.IO; using System.Reflection; -using EvolveDb.Metadata; -using EvolveDb.Migration; -using EvolveDb.Tests.Infrastructure; -using Xunit; namespace EvolveDb.Tests { @@ -98,26 +96,4 @@ public static class SqlServer public static string RepeatableFolder => Path.Combine(SqlScriptsFolder, "Repeatable"); } } - - [CollectionDefinition("Cassandra collection")] - public class CassandraCollection : IClassFixture { } - - [CollectionDefinition("CockroachDB collection")] - public class CockroachDbCollection : IClassFixture { } - - [CollectionDefinition("MySQL collection")] - public class MySQLCollection : IClassFixture { } - - [CollectionDefinition("PostgreSql collection")] - public class PostgreSqlCollection : IClassFixture { } - - [CollectionDefinition("SQLServer collection")] - public class SQLServerCollection : IClassFixture { } - - [CollectionDefinition("Database collection")] - public class DatabaseCollection : IClassFixture, - IClassFixture, - IClassFixture, - IClassFixture, - IClassFixture { } } diff --git a/test/Evolve.Tests/TestUtil.cs b/test/Evolve.Tests/TestUtil.cs index ed6eb7da..54109d31 100644 --- a/test/Evolve.Tests/TestUtil.cs +++ b/test/Evolve.Tests/TestUtil.cs @@ -17,7 +17,11 @@ public static void CreateSqlServerDatabase(string dbName, string cnxStr) using (var cmd = cnn.CreateCommand()) { - cmd.CommandText = $"CREATE DATABASE {dbName};"; + cmd.CommandText = $"IF NOT EXISTS(SELECT * FROM sys.databases WHERE name = '{dbName}') " + + $"BEGIN " + + $"CREATE DATABASE {dbName} " + + $"END"; + cmd.ExecuteNonQuery(); }