diff --git a/.github/workflows/healthchecks_ui_ci.yml b/.github/workflows/healthchecks_ui_ci.yml index bb895564b4..d505938095 100644 --- a/.github/workflows/healthchecks_ui_ci.yml +++ b/.github/workflows/healthchecks_ui_ci.yml @@ -36,27 +36,6 @@ on: jobs: build: runs-on: ubuntu-latest - services: - sqlserver: - image: mcr.microsoft.com/mssql/server - ports: - - 5433:1433 - env: - ACCEPT_EULA: Y - SA_PASSWORD: Password12! - npgsql: - image: postgres - ports: - - 8010:5432 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: Password12! - mysql: - image: mysql - ports: - - 3306:3306 - env: - MYSQL_ROOT_PASSWORD: Password12! steps: - uses: actions/checkout@v3 - name: Setup .NET diff --git a/test/HealthChecks.UI.Tests/Fixtures/MySqlContainerFixture.cs b/test/HealthChecks.UI.Tests/Fixtures/MySqlContainerFixture.cs new file mode 100644 index 0000000000..b2fd80593c --- /dev/null +++ b/test/HealthChecks.UI.Tests/Fixtures/MySqlContainerFixture.cs @@ -0,0 +1,39 @@ +using Testcontainers.MySql; + +namespace HealthChecks.UI.Tests.Fixtures; + +public class MySqlContainerFixture : IAsyncLifetime +{ + private const string Registry = "docker.io"; + + private const string Image = "library/mysql"; + + private const string Tag = "9.4.0"; + + public MySqlContainer? Container { get; private set; } + + public string GetConnectionString() + { + if (Container is null) + { + throw new InvalidOperationException("The test container was not initialized."); + } + + return Container.GetConnectionString(); + } + + public async Task InitializeAsync() => Container = await CreateContainerAsync(); + + public Task DisposeAsync() => Container?.DisposeAsync().AsTask() ?? Task.CompletedTask; + + private static async Task CreateContainerAsync() + { + var container = new MySqlBuilder() + .WithImage($"{Registry}/{Image}:{Tag}") + .Build(); + + await container.StartAsync(); + + return container; + } +} diff --git a/test/HealthChecks.UI.Tests/Fixtures/PostgreSqlContainerFixture.cs b/test/HealthChecks.UI.Tests/Fixtures/PostgreSqlContainerFixture.cs new file mode 100644 index 0000000000..c13f3084ed --- /dev/null +++ b/test/HealthChecks.UI.Tests/Fixtures/PostgreSqlContainerFixture.cs @@ -0,0 +1,39 @@ +using Testcontainers.PostgreSql; + +namespace HealthChecks.UI.Tests.Fixtures; + +public class PostgreSqlContainerFixture : IAsyncLifetime +{ + private const string Registry = "docker.io"; + + private const string Image = "library/postgres"; + + private const string Tag = "17.6-alpine3.22"; + + public PostgreSqlContainer? Container { get; private set; } + + public string GetConnectionString() + { + if (Container is null) + { + throw new InvalidOperationException("The test container was not initialized."); + } + + return Container.GetConnectionString(); + } + + public async Task InitializeAsync() => Container = await CreateContainerAsync(); + + public Task DisposeAsync() => Container?.DisposeAsync().AsTask() ?? Task.CompletedTask; + + private static async Task CreateContainerAsync() + { + var container = new PostgreSqlBuilder() + .WithImage($"{Registry}/{Image}:{Tag}") + .Build(); + + await container.StartAsync(); + + return container; + } +} diff --git a/test/HealthChecks.UI.Tests/Fixtures/SqlServerContainerFixture.cs b/test/HealthChecks.UI.Tests/Fixtures/SqlServerContainerFixture.cs new file mode 100644 index 0000000000..ab29a5fbae --- /dev/null +++ b/test/HealthChecks.UI.Tests/Fixtures/SqlServerContainerFixture.cs @@ -0,0 +1,39 @@ +using Testcontainers.MsSql; + +namespace HealthChecks.UI.Tests.Fixtures; + +public class SqlServerContainerFixture : IAsyncLifetime +{ + private const string Registry = "mcr.microsoft.com"; + + private const string Image = "mssql/server"; + + private const string Tag = "2022-CU20-GDR1-ubuntu-22.04"; + + public MsSqlContainer? Container { get; private set; } + + public string GetConnectionString() + { + if (Container is null) + { + throw new InvalidOperationException("The test container was not initialized."); + } + + return Container.GetConnectionString(); + } + + public async Task InitializeAsync() => Container = await CreateContainerAsync(); + + public Task DisposeAsync() => Container?.DisposeAsync().AsTask() ?? Task.CompletedTask; + + private static async Task CreateContainerAsync() + { + var container = new MsSqlBuilder() + .WithImage($"{Registry}/{Image}:{Tag}") + .Build(); + + await container.StartAsync(); + + return container; + } +} diff --git a/test/HealthChecks.UI.Tests/Functional/Configuration/UIHttpMessageHandlerTests.cs b/test/HealthChecks.UI.Tests/Functional/Configuration/UIHttpMessageHandlerTests.cs index 26ffb13e6b..d5c2db3e4c 100644 --- a/test/HealthChecks.UI.Tests/Functional/Configuration/UIHttpMessageHandlerTests.cs +++ b/test/HealthChecks.UI.Tests/Functional/Configuration/UIHttpMessageHandlerTests.cs @@ -80,7 +80,7 @@ public Task configure_api_endpoint_custom_delegating_handlers() return Task.CompletedTask; } - [Fact(Skip = "Temporarily skipping in https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks/pull/1807")] + [Fact] public Task configure_webhooks_endpoint_custom_delegating_handlers() { var hostReset = new ManualResetEventSlim(false); @@ -101,7 +101,7 @@ public Task configure_webhooks_endpoint_custom_delegating_handlers() setup.UseWebHooksEndpointDelegatingHandler(); setup.UseWebHooksEndpointDelegatingHandler(); - }).AddInMemoryStorage(); + }).AddInMemoryStorage(databaseName: Guid.NewGuid().ToString()); }) .Configure(app => { diff --git a/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/DockerImageStorageProviderTests.cs b/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/DockerImageStorageProviderTests.cs index 10bed25346..1ab146bd51 100644 --- a/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/DockerImageStorageProviderTests.cs +++ b/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/DockerImageStorageProviderTests.cs @@ -1,6 +1,7 @@ using HealthChecks.UI.Data; using HealthChecks.UI.Image; using HealthChecks.UI.Image.Configuration; +using HealthChecks.UI.Tests.Fixtures; using Microsoft.Extensions.Configuration; namespace HealthChecks.UI.Tests; @@ -11,7 +12,6 @@ public class docker_image_storage_provider_configuration_should private const string SqliteProviderName = "Microsoft.EntityFrameworkCore.Sqlite"; private const string PostgreProviderName = "Npgsql.EntityFrameworkCore.PostgreSQL"; private const string InMemoryProviderName = "Microsoft.EntityFrameworkCore.InMemory"; - private const string MySqlProviderName = "Pomelo.EntityFrameworkCore.MySql"; [Fact] public void fail_with_invalid_storage_provider_value() @@ -183,11 +183,16 @@ public void register_inmemory_as_default_provider_when_no_option_is_configured() var context = host.Services.GetRequiredService(); context.Database.ProviderName.ShouldBe(InMemoryProviderName); } +} + +[Collection("execution")] +public class docker_image_storage_provider_mysql_configuration_should(MySqlContainerFixture mySqlFixture) : IClassFixture +{ + private const string MySqlProviderName = "Pomelo.EntityFrameworkCore.MySql"; [Fact] public void register_mysql() { - // var hostBuilder = new WebHostBuilder() .ConfigureAppConfiguration(config => { @@ -196,8 +201,7 @@ public void register_mysql() config.AddInMemoryCollection(new List> { new KeyValuePair("storage_provider", StorageProviderEnum.MySql.ToString()), - new KeyValuePair("storage_connection", "Host=localhost;User Id=root;Password=Password12!;Database=UI"), - + new KeyValuePair("storage_connection", mySqlFixture.GetConnectionString()), }); }) .UseStartup(); @@ -225,5 +229,4 @@ public void fail_to_register_mysql_with_no_connection_string() Should.Throw(() => hostBuilder.Build()); } - } diff --git a/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/InMemoryStorageProviderTests.cs b/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/InMemoryStorageProviderTests.cs index 0df030f029..b637451b9e 100644 --- a/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/InMemoryStorageProviderTests.cs +++ b/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/InMemoryStorageProviderTests.cs @@ -29,7 +29,7 @@ public void register_healthchecksdb_context() customOptionsInvoked.ShouldBeTrue(); } - [Fact(Skip = "conflicts with other tests that use inmemory storage too")] + [Fact] public async Task seed_database_and_serve_stored_executions() { var hostReset = new ManualResetEventSlim(false); @@ -38,7 +38,7 @@ public async Task seed_database_and_serve_stored_executions() var webHostBuilder = HostBuilderHelper.Create( hostReset, collectorReset, - configureUI: config => config.AddInMemoryStorage()); + configureUI: config => config.AddInMemoryStorage(databaseName: Guid.NewGuid().ToString())); using var host = new TestServer(webHostBuilder); diff --git a/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/MySqlStorageProviderTests.cs b/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/MySqlStorageProviderTests.cs index 631f52061c..39131368df 100644 --- a/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/MySqlStorageProviderTests.cs +++ b/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/MySqlStorageProviderTests.cs @@ -1,9 +1,11 @@ using HealthChecks.UI.Data; +using HealthChecks.UI.Tests.Fixtures; using Microsoft.EntityFrameworkCore; namespace HealthChecks.UI.Tests; -public class mysql_storage_should +[Collection("execution")] +public class mysql_storage_should(MySqlContainerFixture mySqlFixture) : IClassFixture { private const string PROVIDER_NAME = "Pomelo.EntityFrameworkCore.MySql"; @@ -17,7 +19,7 @@ public void register_healthchecksdb_context_with_migrations() .ConfigureServices(services => { services.AddHealthChecksUI() - .AddMySqlStorage("Host=localhost;User Id=root;Password=Password12!;Database=UI", options => customOptionsInvoked = true); + .AddMySqlStorage(mySqlFixture.GetConnectionString(), options => customOptionsInvoked = true); }); var services = hostBuilder.Build().Services; @@ -38,7 +40,7 @@ public async Task seed_database_and_serve_stored_executions() var webHostBuilder = HostBuilderHelper.Create( hostReset, collectorReset, - configureUI: config => config.AddMySqlStorage(ProviderTestHelper.MySqlConnectionString())); + configureUI: config => config.AddMySqlStorage(mySqlFixture.GetConnectionString())); using var host = new TestServer(webHostBuilder); diff --git a/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/PostgreSqlStorageProviderTests.cs b/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/PostgreSqlStorageProviderTests.cs index 67ad42f68b..fb78a21831 100644 --- a/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/PostgreSqlStorageProviderTests.cs +++ b/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/PostgreSqlStorageProviderTests.cs @@ -1,10 +1,11 @@ using HealthChecks.UI.Data; +using HealthChecks.UI.Tests.Fixtures; using Microsoft.EntityFrameworkCore; namespace HealthChecks.UI.Tests; [Collection("execution")] -public class postgre_storage_should +public class postgre_storage_should(PostgreSqlContainerFixture postgreSqlFixture) : IClassFixture { private const string ProviderName = "Npgsql.EntityFrameworkCore.PostgreSQL"; @@ -18,7 +19,7 @@ public void register_healthchecksdb_context_with_migrations() .ConfigureServices(services => { services.AddHealthChecksUI() - .AddPostgreSqlStorage("connectionString", options => customOptionsInvoked = true); + .AddPostgreSqlStorage(postgreSqlFixture.GetConnectionString(), _ => customOptionsInvoked = true); }); var services = hostBuilder.Build().Services; @@ -39,7 +40,7 @@ public async Task seed_database_and_serve_stored_executions() var webHostBuilder = HostBuilderHelper.Create( hostReset, collectorReset, - configureUI: config => config.AddPostgreSqlStorage(ProviderTestHelper.PostgresConnectionString())); + configureUI: config => config.AddPostgreSqlStorage(postgreSqlFixture.GetConnectionString())); using var host = new TestServer(webHostBuilder); diff --git a/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/SqlServerStorageProviderTests.cs b/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/SqlServerStorageProviderTests.cs index b7c01c060c..5ce2a31ad8 100644 --- a/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/SqlServerStorageProviderTests.cs +++ b/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/SqlServerStorageProviderTests.cs @@ -1,9 +1,10 @@ using HealthChecks.UI.Data; +using HealthChecks.UI.Tests.Fixtures; using Microsoft.EntityFrameworkCore; namespace HealthChecks.UI.Tests; -public class sqlserver_storage_should +public class sqlserver_storage_should(SqlServerContainerFixture sqlServerFixture) : IClassFixture { private const string ProviderName = "Microsoft.EntityFrameworkCore.SqlServer"; @@ -17,7 +18,7 @@ public void register_healthchecksdb_context_with_migrations() .ConfigureServices(services => { services.AddHealthChecksUI() - .AddSqlServerStorage("connectionString", opt => customOptionsInvoked = true); + .AddSqlServerStorage(sqlServerFixture.GetConnectionString(), opt => customOptionsInvoked = true); }); var services = hostBuilder.Build().Services; @@ -38,7 +39,7 @@ public async Task seed_database_and_serve_stored_executions() var webHostBuilder = HostBuilderHelper.Create( hostReset, collectorReset, - configureUI: config => config.AddSqlServerStorage(ProviderTestHelper.SqlServerConnectionString())); + configureUI: config => config.AddSqlServerStorage(sqlServerFixture.GetConnectionString())); using var host = new TestServer(webHostBuilder); diff --git a/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/SqliteStorageProviderTests.cs b/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/SqliteStorageProviderTests.cs index b96abae896..4c91f943c0 100644 --- a/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/SqliteStorageProviderTests.cs +++ b/test/HealthChecks.UI.Tests/Functional/DatabaseProviders/SqliteStorageProviderTests.cs @@ -38,7 +38,7 @@ public async Task seed_database_and_serve_stored_executions() var webHostBuilder = HostBuilderHelper.Create( hostReset, collectorReset, - configureUI: setup => setup.AddSqliteStorage(ProviderTestHelper.SqliteConnectionString())); + configureUI: setup => setup.AddSqliteStorage("Data Source = sqlite.db")); using var host = new TestServer(webHostBuilder); diff --git a/test/HealthChecks.UI.Tests/HealthChecks.UI.Tests.csproj b/test/HealthChecks.UI.Tests/HealthChecks.UI.Tests.csproj index fe1de35d2d..9ff9690824 100644 --- a/test/HealthChecks.UI.Tests/HealthChecks.UI.Tests.csproj +++ b/test/HealthChecks.UI.Tests/HealthChecks.UI.Tests.csproj @@ -28,4 +28,10 @@ + + + + + + diff --git a/test/HealthChecks.UI.Tests/Seedwork/ProviderTestHelper.cs b/test/HealthChecks.UI.Tests/Seedwork/ProviderTestHelper.cs index d07dbf5caa..229bb260a2 100644 --- a/test/HealthChecks.UI.Tests/Seedwork/ProviderTestHelper.cs +++ b/test/HealthChecks.UI.Tests/Seedwork/ProviderTestHelper.cs @@ -10,9 +10,4 @@ public class ProviderTestHelper ("host1", "http://localhost/health"), ("host2", "http://localhost/health") }; - - public static string SqlServerConnectionString() => "Server=tcp:localhost,5433;Initial Catalog=master;User Id=sa;Password=Password12!;TrustServerCertificate=true"; - public static string PostgresConnectionString() => "Server=127.0.0.1;Port=8010;User ID=postgres;Password=Password12!;database=ui"; - public static string MySqlConnectionString() => "Host=localhost;User Id=root;Password=Password12!;Database=UI"; - public static string SqliteConnectionString() => "Data Source = sqlite.db"; }