From 96f5e7546050ec6bbef0c4c706ea0529b1fd2fa9 Mon Sep 17 00:00:00 2001
From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com>
Date: Fri, 15 Sep 2023 16:38:02 +0200
Subject: [PATCH] feat: Add Flyway example
---
.config/dotnet-tools.json | 2 +-
.github/workflows/cicd.yml | 2 +-
build.cake | 4 +-
examples/Flyway/.editorconfig | 1 +
examples/Flyway/.gitattributes | 1 +
examples/Flyway/Directory.Build.props | 28 +++++++
examples/Flyway/Flyway.sln | 26 +++++++
examples/Flyway/Packages.props | 11 +++
examples/Flyway/README.md | 9 +++
examples/Flyway/src/.gitkeep | 0
.../Flyway/tests/Flyway.Tests/DbFixture.cs | 74 +++++++++++++++++++
.../tests/Flyway.Tests/Flyway.Tests.csproj | 17 +++++
.../Flyway/tests/Flyway.Tests/FlywayTest.cs | 34 +++++++++
examples/Flyway/tests/Flyway.Tests/Usings.cs | 11 +++
.../migrate/V1.0__create_users_table.sql | 7 ++
.../migrate/V1.1__alter_users_table.sql | 1 +
.../migrate/V2.0__seed_example_users.sql | 1 +
.../Testcontainers.PostgreSql.Tests.csproj | 2 +-
18 files changed, 226 insertions(+), 5 deletions(-)
create mode 100644 examples/Flyway/.editorconfig
create mode 100644 examples/Flyway/.gitattributes
create mode 100644 examples/Flyway/Directory.Build.props
create mode 100644 examples/Flyway/Flyway.sln
create mode 100644 examples/Flyway/Packages.props
create mode 100644 examples/Flyway/README.md
create mode 100644 examples/Flyway/src/.gitkeep
create mode 100644 examples/Flyway/tests/Flyway.Tests/DbFixture.cs
create mode 100644 examples/Flyway/tests/Flyway.Tests/Flyway.Tests.csproj
create mode 100644 examples/Flyway/tests/Flyway.Tests/FlywayTest.cs
create mode 100644 examples/Flyway/tests/Flyway.Tests/Usings.cs
create mode 100644 examples/Flyway/tests/Flyway.Tests/migrate/V1.0__create_users_table.sql
create mode 100644 examples/Flyway/tests/Flyway.Tests/migrate/V1.1__alter_users_table.sql
create mode 100644 examples/Flyway/tests/Flyway.Tests/migrate/V2.0__seed_example_users.sql
diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 23e1c931b..eb8f1d6dc 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"cake.tool": {
- "version": "3.0.0",
+ "version": "3.1.0",
"commands": [
"dotnet-cake"
]
diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml
index 0468edb8f..f5344ccf4 100644
--- a/.github/workflows/cicd.yml
+++ b/.github/workflows/cicd.yml
@@ -131,7 +131,7 @@ jobs:
uses: actions/setup-java@v3
with:
distribution: temurin
- java-version: 11
+ java-version: 17
- name: Setup .NET
uses: actions/setup-dotnet@v3
diff --git a/build.cake b/build.cake
index 9f4dad753..5ef7365ca 100644
--- a/build.cake
+++ b/build.cake
@@ -1,6 +1,6 @@
-#tool nuget:?package=dotnet-sonarscanner&version=5.13.0
+#tool nuget:?package=dotnet-sonarscanner&version=5.13.1
-#addin nuget:?package=Cake.Sonar&version=1.1.31
+#addin nuget:?package=Cake.Sonar&version=1.1.32
#addin nuget:?package=Cake.Git&version=3.0.0
diff --git a/examples/Flyway/.editorconfig b/examples/Flyway/.editorconfig
new file mode 100644
index 000000000..6f066619d
--- /dev/null
+++ b/examples/Flyway/.editorconfig
@@ -0,0 +1 @@
+root = true
\ No newline at end of file
diff --git a/examples/Flyway/.gitattributes b/examples/Flyway/.gitattributes
new file mode 100644
index 000000000..212566614
--- /dev/null
+++ b/examples/Flyway/.gitattributes
@@ -0,0 +1 @@
+* text=auto
\ No newline at end of file
diff --git a/examples/Flyway/Directory.Build.props b/examples/Flyway/Directory.Build.props
new file mode 100644
index 000000000..b28d9e005
--- /dev/null
+++ b/examples/Flyway/Directory.Build.props
@@ -0,0 +1,28 @@
+
+
+
+ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), Flyway.sln))/
+
+
+ 0.1.0
+ $(AssemblyName)
+ $(Version)
+ $(Version)
+ $(Version)
+ en-US
+ Andre Hofmeister
+
+
+
+
+
+
+
+ git
+ https://github.com/testcontainers/testcontainers-dotnet-sample
+
+
+ 10.0
+ enable
+
+
\ No newline at end of file
diff --git a/examples/Flyway/Flyway.sln b/examples/Flyway/Flyway.sln
new file mode 100644
index 000000000..8f623edd8
--- /dev/null
+++ b/examples/Flyway/Flyway.sln
@@ -0,0 +1,26 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{424CFC36-D6F7-4DBB-BD1C-0C84FE30E665}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flyway.Tests", "tests\Flyway.Tests\Flyway.Tests.csproj", "{1E882BFE-4A5E-4E58-A533-81E1BE9E9BFD}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1E882BFE-4A5E-4E58-A533-81E1BE9E9BFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1E882BFE-4A5E-4E58-A533-81E1BE9E9BFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1E882BFE-4A5E-4E58-A533-81E1BE9E9BFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1E882BFE-4A5E-4E58-A533-81E1BE9E9BFD}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {1E882BFE-4A5E-4E58-A533-81E1BE9E9BFD} = {424CFC36-D6F7-4DBB-BD1C-0C84FE30E665}
+ EndGlobalSection
+EndGlobal
diff --git a/examples/Flyway/Packages.props b/examples/Flyway/Packages.props
new file mode 100644
index 000000000..adfd5db4a
--- /dev/null
+++ b/examples/Flyway/Packages.props
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/Flyway/README.md b/examples/Flyway/README.md
new file mode 100644
index 000000000..e00fbc369
--- /dev/null
+++ b/examples/Flyway/README.md
@@ -0,0 +1,9 @@
+# Testcontainers for .NET Flyway example
+
+This example demonstrates how to use Testcontainers in conjunction with Flyway to execute database migrations and prepare a dependent database before running tests. The `FlywayTest` test class executes its tests against the pre-configured PostgreSQL database, interacting with the table that is created, altered, and seeded beforehand. This test class receives a class fixture, which provides access to the prepared database through the `DbConnection` property. The database is started, created, and seeded once and is shared across the tests within the `FlywayTest` test collection. Checkout and run the tests on your machine:
+
+```console
+git clone --branch develop git@github.com:testcontainers/testcontainers-dotnet.git
+cd ./testcontainers-dotnet/examples/Flyway/
+dotnet test Flyway.sln --configuration=Release
+```
\ No newline at end of file
diff --git a/examples/Flyway/src/.gitkeep b/examples/Flyway/src/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/examples/Flyway/tests/Flyway.Tests/DbFixture.cs b/examples/Flyway/tests/Flyway.Tests/DbFixture.cs
new file mode 100644
index 000000000..7359c0350
--- /dev/null
+++ b/examples/Flyway/tests/Flyway.Tests/DbFixture.cs
@@ -0,0 +1,74 @@
+namespace Flyway.Tests;
+
+[UsedImplicitly]
+public sealed class DbFixture : IAsyncLifetime
+{
+ private readonly INetwork _network = new NetworkBuilder().Build();
+
+ private readonly IContainer _postgreSqlContainer;
+
+ private readonly IContainer _flywayContainer;
+
+ public DbFixture()
+ {
+ // Testcontainers starts the dependent database (PostgreSQL) and the database
+ // migration tool Flyway. It establishes a network connection between these two
+ // containers. Before starting the Flyway container, Testcontainers copies the SQL
+ // migration files into it. When the Flyway container starts, it initiates the
+ // dependent database container, connects to it, and begins the database migration
+ // as soon as the database is ready. Once the migration is finished, the Flyway
+ // container exits, and the database container becomes available for tests.
+
+ _postgreSqlContainer = new PostgreSqlBuilder()
+ .WithImage("postgres:15-alpine")
+ .WithNetwork(_network)
+ .WithNetworkAliases(nameof(_postgreSqlContainer))
+ .Build();
+
+ // The member `WithResourceMapping(string, string)` copies the SQL migration files
+ // from the test host into the Flyway container before it starts. This ensures that
+ // the files are available as soon as the container starts. Flyway will
+ // automatically pick them up and start the database migration process.
+
+ _flywayContainer = new ContainerBuilder()
+ .WithImage("flyway/flyway:9-alpine")
+ .WithResourceMapping("migrate/", "/flyway/sql/")
+ .WithCommand("-url=jdbc:postgresql://" + nameof(_postgreSqlContainer) + "/")
+ .WithCommand("-user=" + PostgreSqlBuilder.DefaultUsername)
+ .WithCommand("-password=" + PostgreSqlBuilder.DefaultPassword)
+ .WithCommand("-connectRetries=3")
+ .WithCommand("migrate")
+ .WithNetwork(_network)
+ .DependsOn(_postgreSqlContainer)
+ .WithWaitStrategy(Wait.ForUnixContainer().AddCustomWaitStrategy(new MigrationCompleted()))
+ .Build();
+ }
+
+ public DbConnection DbConnection => new NpgsqlConnection(((PostgreSqlContainer)_postgreSqlContainer).GetConnectionString());
+
+ public Task InitializeAsync()
+ {
+ return _flywayContainer.StartAsync();
+ }
+
+ public Task DisposeAsync()
+ {
+ // We do not need to manually dispose Docker resources. If resources depend on each
+ // other, it is necessary to dispose them in the correct order. Testcontainers'
+ // Resource Reaper (Ryuk) will reliably take care of these resources and dispose
+ // them after the test automatically.
+ return Task.CompletedTask;
+ }
+
+ private sealed class MigrationCompleted : IWaitUntil
+ {
+ // The Flyway container will exit after executing the database migration. We do not
+ // check if the migration was successful. To verify its success, we can either
+ // check the exit code of the container or the console output, respectively the
+ // standard output (stdout) or error output (stderr).
+ public Task UntilAsync(IContainer container)
+ {
+ return Task.FromResult(TestcontainersStates.Exited.Equals(container.State));
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/Flyway/tests/Flyway.Tests/Flyway.Tests.csproj b/examples/Flyway/tests/Flyway.Tests/Flyway.Tests.csproj
new file mode 100644
index 000000000..fbd9cd2b5
--- /dev/null
+++ b/examples/Flyway/tests/Flyway.Tests/Flyway.Tests.csproj
@@ -0,0 +1,17 @@
+
+
+
+ net6.0
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/Flyway/tests/Flyway.Tests/FlywayTest.cs b/examples/Flyway/tests/Flyway.Tests/FlywayTest.cs
new file mode 100644
index 000000000..5aa7804bb
--- /dev/null
+++ b/examples/Flyway/tests/Flyway.Tests/FlywayTest.cs
@@ -0,0 +1,34 @@
+namespace Flyway.Tests;
+
+public sealed class FlywayTest : IClassFixture, IDisposable
+{
+ private readonly DbConnection _dbConnection;
+
+ public FlywayTest(DbFixture db)
+ {
+ _dbConnection = db.DbConnection;
+ _dbConnection.Open();
+ }
+
+ public void Dispose()
+ {
+ _dbConnection.Dispose();
+ }
+
+ [Fact]
+ public void UsersTableContainsJohnDoe()
+ {
+ // Given
+ using var command = _dbConnection.CreateCommand();
+ command.CommandText = "SELECT username, email, age FROM users;";
+
+ // When
+ using var dataReader = command.ExecuteReader();
+
+ // Then
+ Assert.True(dataReader.Read());
+ Assert.Equal("john_doe", dataReader.GetString(0));
+ Assert.Equal("john@example.com", dataReader.GetString(1));
+ Assert.Equal(30, dataReader.GetInt32(2));
+ }
+}
\ No newline at end of file
diff --git a/examples/Flyway/tests/Flyway.Tests/Usings.cs b/examples/Flyway/tests/Flyway.Tests/Usings.cs
new file mode 100644
index 000000000..557c05167
--- /dev/null
+++ b/examples/Flyway/tests/Flyway.Tests/Usings.cs
@@ -0,0 +1,11 @@
+global using System;
+global using System.Data.Common;
+global using System.Threading.Tasks;
+global using DotNet.Testcontainers.Builders;
+global using DotNet.Testcontainers.Configurations;
+global using DotNet.Testcontainers.Containers;
+global using DotNet.Testcontainers.Networks;
+global using JetBrains.Annotations;
+global using Npgsql;
+global using Testcontainers.PostgreSql;
+global using Xunit;
\ No newline at end of file
diff --git a/examples/Flyway/tests/Flyway.Tests/migrate/V1.0__create_users_table.sql b/examples/Flyway/tests/Flyway.Tests/migrate/V1.0__create_users_table.sql
new file mode 100644
index 000000000..8cbb71060
--- /dev/null
+++ b/examples/Flyway/tests/Flyway.Tests/migrate/V1.0__create_users_table.sql
@@ -0,0 +1,7 @@
+CREATE TABLE users
+(
+ id SERIAL PRIMARY KEY,
+ username VARCHAR(50) NOT NULL,
+ email VARCHAR(100) NOT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
\ No newline at end of file
diff --git a/examples/Flyway/tests/Flyway.Tests/migrate/V1.1__alter_users_table.sql b/examples/Flyway/tests/Flyway.Tests/migrate/V1.1__alter_users_table.sql
new file mode 100644
index 000000000..81ee4fe00
--- /dev/null
+++ b/examples/Flyway/tests/Flyway.Tests/migrate/V1.1__alter_users_table.sql
@@ -0,0 +1 @@
+ALTER TABLE users ADD COLUMN age INT;
\ No newline at end of file
diff --git a/examples/Flyway/tests/Flyway.Tests/migrate/V2.0__seed_example_users.sql b/examples/Flyway/tests/Flyway.Tests/migrate/V2.0__seed_example_users.sql
new file mode 100644
index 000000000..0e4dfa7cc
--- /dev/null
+++ b/examples/Flyway/tests/Flyway.Tests/migrate/V2.0__seed_example_users.sql
@@ -0,0 +1 @@
+INSERT INTO users (username, email, age) VALUES ('john_doe', 'john@example.com', 30);
\ No newline at end of file
diff --git a/tests/Testcontainers.PostgreSql.Tests/Testcontainers.PostgreSql.Tests.csproj b/tests/Testcontainers.PostgreSql.Tests/Testcontainers.PostgreSql.Tests.csproj
index cea7f9ed1..863363361 100644
--- a/tests/Testcontainers.PostgreSql.Tests/Testcontainers.PostgreSql.Tests.csproj
+++ b/tests/Testcontainers.PostgreSql.Tests/Testcontainers.PostgreSql.Tests.csproj
@@ -9,7 +9,7 @@
-
+