From 5048fd36e6a999c6ddc0390a5e676208e98d6f64 Mon Sep 17 00:00:00 2001 From: hhvrc Date: Thu, 6 Feb 2025 11:35:45 +0100 Subject: [PATCH 1/8] Create API integration tests project --- .../API.Tests.Integration.csproj | 19 +++++++++++++++++++ API.Tests.Integration/ApiFactory.cs | 8 ++++++++ API.Tests.Integration/BasicTests.cs | 8 ++++++++ API/API.csproj | 4 ++++ OpenShockBackend.sln | 6 ++++++ 5 files changed, 45 insertions(+) create mode 100644 API.Tests.Integration/API.Tests.Integration.csproj create mode 100644 API.Tests.Integration/ApiFactory.cs create mode 100644 API.Tests.Integration/BasicTests.cs diff --git a/API.Tests.Integration/API.Tests.Integration.csproj b/API.Tests.Integration/API.Tests.Integration.csproj new file mode 100644 index 00000000..99108725 --- /dev/null +++ b/API.Tests.Integration/API.Tests.Integration.csproj @@ -0,0 +1,19 @@ + + + + + false + + + + + + + + + + + + + + diff --git a/API.Tests.Integration/ApiFactory.cs b/API.Tests.Integration/ApiFactory.cs new file mode 100644 index 00000000..8bf1d9fd --- /dev/null +++ b/API.Tests.Integration/ApiFactory.cs @@ -0,0 +1,8 @@ +using Microsoft.AspNetCore.Mvc.Testing; + +namespace OpenShock.API.Tests.Integration; + +internal class ApiFactory : WebApplicationFactory +{ + +} diff --git a/API.Tests.Integration/BasicTests.cs b/API.Tests.Integration/BasicTests.cs new file mode 100644 index 00000000..f2a51d2d --- /dev/null +++ b/API.Tests.Integration/BasicTests.cs @@ -0,0 +1,8 @@ +using Microsoft.AspNetCore.Mvc.Testing; +using Xunit; + +namespace OpenShock.API.Tests.Integration; + +internal class BasicTests : IClassFixture> +{ +} diff --git a/API/API.csproj b/API/API.csproj index fbbeb89b..5594855d 100644 --- a/API/API.csproj +++ b/API/API.csproj @@ -67,4 +67,8 @@ Always + + + + diff --git a/OpenShockBackend.sln b/OpenShockBackend.sln index a7b6f305..eaa0996b 100644 --- a/OpenShockBackend.sln +++ b/OpenShockBackend.sln @@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MigrationHelper", "Migratio EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.Tests", "Common.Tests\Common.Tests.csproj", "{7AED9D47-F0B0-4644-A154-EE386A81C85D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API.Tests.Integration", "API.Tests.Integration\API.Tests.Integration.csproj", "{71017F66-86FD-4B75-BE3C-14544CD59277}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,6 +47,10 @@ Global {7AED9D47-F0B0-4644-A154-EE386A81C85D}.Debug|Any CPU.Build.0 = Debug|Any CPU {7AED9D47-F0B0-4644-A154-EE386A81C85D}.Release|Any CPU.ActiveCfg = Release|Any CPU {7AED9D47-F0B0-4644-A154-EE386A81C85D}.Release|Any CPU.Build.0 = Release|Any CPU + {71017F66-86FD-4B75-BE3C-14544CD59277}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71017F66-86FD-4B75-BE3C-14544CD59277}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71017F66-86FD-4B75-BE3C-14544CD59277}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71017F66-86FD-4B75-BE3C-14544CD59277}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From e0bb68342c8a35b64f7dac63d38a2930485a56fa Mon Sep 17 00:00:00 2001 From: hhvrc Date: Wed, 19 Mar 2025 16:33:56 +0100 Subject: [PATCH 2/8] Start implementing proper integration tests --- .../API.IntegrationTests.csproj | 34 +++++++++++++++++ API.IntegrationTests/BaseIntegrationTest.cs | 23 +++++++++++ .../IntegrationTestWebAppFactory.cs | 38 +++++++++++++++++++ API.IntegrationTests/UserTests.cs | 14 +++++++ .../API.Tests.Integration.csproj | 19 ---------- API.Tests.Integration/ApiFactory.cs | 8 ---- API.Tests.Integration/BasicTests.cs | 8 ---- API/Program.cs | 3 ++ OpenShockBackend.sln | 13 ++++--- 9 files changed, 120 insertions(+), 40 deletions(-) create mode 100644 API.IntegrationTests/API.IntegrationTests.csproj create mode 100644 API.IntegrationTests/BaseIntegrationTest.cs create mode 100644 API.IntegrationTests/IntegrationTestWebAppFactory.cs create mode 100644 API.IntegrationTests/UserTests.cs delete mode 100644 API.Tests.Integration/API.Tests.Integration.csproj delete mode 100644 API.Tests.Integration/ApiFactory.cs delete mode 100644 API.Tests.Integration/BasicTests.cs diff --git a/API.IntegrationTests/API.IntegrationTests.csproj b/API.IntegrationTests/API.IntegrationTests.csproj new file mode 100644 index 00000000..4f48a37a --- /dev/null +++ b/API.IntegrationTests/API.IntegrationTests.csproj @@ -0,0 +1,34 @@ + + + + net9.0 + enable + enable + false + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/API.IntegrationTests/BaseIntegrationTest.cs b/API.IntegrationTests/BaseIntegrationTest.cs new file mode 100644 index 00000000..f4df539e --- /dev/null +++ b/API.IntegrationTests/BaseIntegrationTest.cs @@ -0,0 +1,23 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using OpenShock.Common.OpenShockDb; + +namespace API.IntegrationTests; + +public abstract class BaseIntegrationTest : IClassFixture +{ + private readonly IServiceScope _scope; + protected readonly OpenShockContext DbContext; + + protected BaseIntegrationTest(IntegrationTestWebAppFactory factory) + { + _scope = factory.Services.CreateScope(); + + DbContext = _scope.ServiceProvider.GetRequiredService(); + + if (DbContext.Database.GetPendingMigrations().Any()) + { + DbContext.Database.Migrate(); + } + } +} \ No newline at end of file diff --git a/API.IntegrationTests/IntegrationTestWebAppFactory.cs b/API.IntegrationTests/IntegrationTestWebAppFactory.cs new file mode 100644 index 00000000..6392bc03 --- /dev/null +++ b/API.IntegrationTests/IntegrationTestWebAppFactory.cs @@ -0,0 +1,38 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.AspNetCore.TestHost; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using OpenShock.Common.OpenShockDb; +using StackExchange.Redis; +using Testcontainers.PostgreSql; +using Testcontainers.Redis; + +namespace API.IntegrationTests; + +public class IntegrationTestWebAppFactory : WebApplicationFactory +{ + private readonly PostgreSqlContainer _dbContainer = new PostgreSqlBuilder() + .WithImage("postgresql:latest") + .WithDatabase("openshock") + .WithUsername("openshock") + .WithPassword("superSecurePassword") + .Build(); + + private readonly RedisContainer _redisContainer = new RedisBuilder() + .WithImage("redis:latest") + .Build(); + + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + builder.ConfigureTestServices(services => + { + services.RemoveAll>(); + services.AddDbContext(options => options.UseNpgsql(_dbContainer.GetConnectionString())); + + services.RemoveAll(); + services.AddSingleton(ConnectionMultiplexer.Connect(_redisContainer.GetConnectionString())); + }); + } +} diff --git a/API.IntegrationTests/UserTests.cs b/API.IntegrationTests/UserTests.cs new file mode 100644 index 00000000..16775771 --- /dev/null +++ b/API.IntegrationTests/UserTests.cs @@ -0,0 +1,14 @@ +namespace API.IntegrationTests; + +public class UserTests : BaseIntegrationTest +{ + public UserTests(IntegrationTestWebAppFactory factory) : base(factory) + { + } + + [Fact] + public async Task Create_ShouldAdd_NewUserToDatabase() + { + Console.WriteLine(":D"); + } +} diff --git a/API.Tests.Integration/API.Tests.Integration.csproj b/API.Tests.Integration/API.Tests.Integration.csproj deleted file mode 100644 index 99108725..00000000 --- a/API.Tests.Integration/API.Tests.Integration.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - - false - - - - - - - - - - - - - - diff --git a/API.Tests.Integration/ApiFactory.cs b/API.Tests.Integration/ApiFactory.cs deleted file mode 100644 index 8bf1d9fd..00000000 --- a/API.Tests.Integration/ApiFactory.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Microsoft.AspNetCore.Mvc.Testing; - -namespace OpenShock.API.Tests.Integration; - -internal class ApiFactory : WebApplicationFactory -{ - -} diff --git a/API.Tests.Integration/BasicTests.cs b/API.Tests.Integration/BasicTests.cs deleted file mode 100644 index f2a51d2d..00000000 --- a/API.Tests.Integration/BasicTests.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Microsoft.AspNetCore.Mvc.Testing; -using Xunit; - -namespace OpenShock.API.Tests.Integration; - -internal class BasicTests : IClassFixture> -{ -} diff --git a/API/Program.cs b/API/Program.cs index e3b00ba6..9b413b6a 100644 --- a/API/Program.cs +++ b/API/Program.cs @@ -131,3 +131,6 @@ app.MapScalarApiReference(options => options.OpenApiRoutePattern = "/swagger/{documentName}/swagger.json"); app.Run(); + +// Expose Program class for integrationtests +public partial class Program; \ No newline at end of file diff --git a/OpenShockBackend.sln b/OpenShockBackend.sln index eaa0996b..3f2eb7da 100644 --- a/OpenShockBackend.sln +++ b/OpenShockBackend.sln @@ -15,7 +15,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MigrationHelper", "Migratio EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.Tests", "Common.Tests\Common.Tests.csproj", "{7AED9D47-F0B0-4644-A154-EE386A81C85D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API.Tests.Integration", "API.Tests.Integration\API.Tests.Integration.csproj", "{71017F66-86FD-4B75-BE3C-14544CD59277}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API.IntegrationTests", "API.IntegrationTests\API.IntegrationTests.csproj", "{9A9C5529-54A2-490C-A537-242D339054E8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -47,12 +47,15 @@ Global {7AED9D47-F0B0-4644-A154-EE386A81C85D}.Debug|Any CPU.Build.0 = Debug|Any CPU {7AED9D47-F0B0-4644-A154-EE386A81C85D}.Release|Any CPU.ActiveCfg = Release|Any CPU {7AED9D47-F0B0-4644-A154-EE386A81C85D}.Release|Any CPU.Build.0 = Release|Any CPU - {71017F66-86FD-4B75-BE3C-14544CD59277}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {71017F66-86FD-4B75-BE3C-14544CD59277}.Debug|Any CPU.Build.0 = Debug|Any CPU - {71017F66-86FD-4B75-BE3C-14544CD59277}.Release|Any CPU.ActiveCfg = Release|Any CPU - {71017F66-86FD-4B75-BE3C-14544CD59277}.Release|Any CPU.Build.0 = Release|Any CPU + {9A9C5529-54A2-490C-A537-242D339054E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A9C5529-54A2-490C-A537-242D339054E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A9C5529-54A2-490C-A537-242D339054E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A9C5529-54A2-490C-A537-242D339054E8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AD88368D-9B5B-4FB5-B4AA-7C8946471648} + EndGlobalSection EndGlobal From e2dcd3e444447f12159c4745aaa13acbc38d3806 Mon Sep 17 00:00:00 2001 From: hhvrc Date: Wed, 19 Mar 2025 17:55:26 +0100 Subject: [PATCH 3/8] Fix some issues --- .../IntegrationTestWebAppFactory.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/API.IntegrationTests/IntegrationTestWebAppFactory.cs b/API.IntegrationTests/IntegrationTestWebAppFactory.cs index 6392bc03..26a6f75b 100644 --- a/API.IntegrationTests/IntegrationTestWebAppFactory.cs +++ b/API.IntegrationTests/IntegrationTestWebAppFactory.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; using OpenShock.Common.OpenShockDb; using StackExchange.Redis; using Testcontainers.PostgreSql; @@ -14,7 +15,7 @@ namespace API.IntegrationTests; public class IntegrationTestWebAppFactory : WebApplicationFactory { private readonly PostgreSqlContainer _dbContainer = new PostgreSqlBuilder() - .WithImage("postgresql:latest") + .WithImage("postgres:latest") .WithDatabase("openshock") .WithUsername("openshock") .WithPassword("superSecurePassword") @@ -26,6 +27,9 @@ public class IntegrationTestWebAppFactory : WebApplicationFactory protected override void ConfigureWebHost(IWebHostBuilder builder) { + _dbContainer.StartAsync().ConfigureAwait(false).GetAwaiter().GetResult(); + _redisContainer.StartAsync().ConfigureAwait(false).GetAwaiter().GetResult(); + builder.ConfigureTestServices(services => { services.RemoveAll>(); @@ -35,4 +39,11 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) services.AddSingleton(ConnectionMultiplexer.Connect(_redisContainer.GetConnectionString())); }); } + + public override async ValueTask DisposeAsync() + { + await _dbContainer.DisposeAsync(); + await _redisContainer.DisposeAsync(); + await base.DisposeAsync(); + } } From d903a09a286a85d8d3be392d38a523976b9ec2df Mon Sep 17 00:00:00 2001 From: hhvrc Date: Wed, 19 Mar 2025 19:31:45 +0100 Subject: [PATCH 4/8] Get IntegrationTestWebAppFactory working --- .../IntegrationTestWebAppFactory.cs | 57 ++++++++++++++++--- Common/OpenShockApplication.cs | 22 ++++--- 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/API.IntegrationTests/IntegrationTestWebAppFactory.cs b/API.IntegrationTests/IntegrationTestWebAppFactory.cs index 26a6f75b..dab0fa43 100644 --- a/API.IntegrationTests/IntegrationTestWebAppFactory.cs +++ b/API.IntegrationTests/IntegrationTestWebAppFactory.cs @@ -22,21 +22,64 @@ public class IntegrationTestWebAppFactory : WebApplicationFactory .Build(); private readonly RedisContainer _redisContainer = new RedisBuilder() - .WithImage("redis:latest") + .WithImage("redis/redis-stack-server:latest") .Build(); - protected override void ConfigureWebHost(IWebHostBuilder builder) + protected override IWebHostBuilder? CreateWebHostBuilder() { _dbContainer.StartAsync().ConfigureAwait(false).GetAwaiter().GetResult(); _redisContainer.StartAsync().ConfigureAwait(false).GetAwaiter().GetResult(); + + var environmentVariables = new Dictionary + { + { "ASPNETCORE_UNDER_INTEGRATION_TEST", "1" }, + + { "OPENSHOCK__DB__CONN", _dbContainer.GetConnectionString() }, + { "OPENSHOCK__DB__SKIPMIGRATION", "false" }, + { "OPENSHOCK__DB__DEBUG", "false" }, + + { "OPENSHOCK__REDIS__CONN", _redisContainer.GetConnectionString() }, + { "OPENSHOCK__REDIS__HOST", "" }, + { "OPENSHOCK__REDIS__USER", "" }, + { "OPENSHOCK__REDIS__PASSWORD", "" }, + { "OPENSHOCK__REDIS__PORT", "6379" }, + + { "OPENSHOCK__FRONTEND__BASEURL", "https://openshock.app" }, + { "OPENSHOCK__FRONTEND__SHORTURL", "https://openshock.app" }, + { "OPENSHOCK__FRONTEND__COOKIEDOMAIN", "openshock.app" }, + + { "OPENSHOCK__MAIL__TYPE", "MAILJET" }, + { "OPENSHOCK__MAIL__SENDER__EMAIL", "system@openshock.org" }, + { "OPENSHOCK__MAIL__SENDER__NAME", "OpenShock" }, + { "OPENSHOCK__MAIL__MAILJET__KEY", "mailjet-key" }, + { "OPENSHOCK__MAIL__MAILJET__SECRET", "mailjet-secret" }, + { "OPENSHOCK__MAIL__MAILJET__TEMPLATE__PASSWORDRESET", "12345678" }, + { "OPENSHOCK__MAIL__MAILJET__TEMPLATE__PASSWORDRESETCOMPLETE", "87654321" }, + { "OPENSHOCK__MAIL__MAILJET__TEMPLATE__VERIFYEMAIL", "11223344" }, + { "OPENSHOCK__MAIL__MAILJET__TEMPLATE__VERIFYEMAILCOMPLETE", "44332211" }, + + { "OPENSHOCK__TURNSTILE__ENABLED", "true" }, + { "OPENSHOCK__TURNSTILE__SECRETKEY", "turnstile-secret-key" }, + { "OPENSHOCK__TURNSTILE__SITEKEY", "turnstile-site-key" }, + + { "OPENSHOCK__LCG__FQDN", "de1-gateway.my-openshock-instance.net" }, + { "OPENSHOCK__LCG__COUNTRYCODE", "DE" } + }; + + foreach (var envVar in environmentVariables) + { + Environment.SetEnvironmentVariable(envVar.Key, envVar.Value); + } + + return base.CreateWebHostBuilder(); + } + + protected override void ConfigureWebHost(IWebHostBuilder builder) + { builder.ConfigureTestServices(services => { - services.RemoveAll>(); - services.AddDbContext(options => options.UseNpgsql(_dbContainer.GetConnectionString())); - - services.RemoveAll(); - services.AddSingleton(ConnectionMultiplexer.Connect(_redisContainer.GetConnectionString())); + // We can replace services here }); } diff --git a/Common/OpenShockApplication.cs b/Common/OpenShockApplication.cs index 523fc940..fa5dad10 100644 --- a/Common/OpenShockApplication.cs +++ b/Common/OpenShockApplication.cs @@ -11,13 +11,21 @@ public static WebApplicationBuilder CreateDefaultBuilder(string[] args var builder = WebApplication.CreateSlimBuilder(args); builder.Configuration.Sources.Clear(); - builder.Configuration - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: false) - .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: false) - .AddJsonFile("appsettings.Custom.json", optional: true, reloadOnChange: false) - .AddEnvironmentVariables() - .AddUserSecrets(true) - .AddCommandLine(args); + if (Environment.GetEnvironmentVariable("ASPNETCORE_UNDER_INTEGRATION_TEST") == "1") + { + builder.Configuration + .AddEnvironmentVariables(); + } + else + { + builder.Configuration + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: false) + .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: false) + .AddJsonFile("appsettings.Custom.json", optional: true, reloadOnChange: false) + .AddEnvironmentVariables() + .AddUserSecrets(true) + .AddCommandLine(args); + } var isDevelopment = builder.Environment.IsDevelopment(); builder.Host.UseDefaultServiceProvider((_, options) => From 06e405fa28123a46c7ba581d677c92d7a383a37c Mon Sep 17 00:00:00 2001 From: hhvrc Date: Wed, 19 Mar 2025 19:32:17 +0100 Subject: [PATCH 5/8] Start messing around with tests --- API.IntegrationTests/BaseIntegrationTest.cs | 4 ++++ API.IntegrationTests/UserTests.cs | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/API.IntegrationTests/BaseIntegrationTest.cs b/API.IntegrationTests/BaseIntegrationTest.cs index f4df539e..bf8b84c7 100644 --- a/API.IntegrationTests/BaseIntegrationTest.cs +++ b/API.IntegrationTests/BaseIntegrationTest.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; +using OpenShock.API.Services.Account; using OpenShock.Common.OpenShockDb; namespace API.IntegrationTests; @@ -8,6 +9,7 @@ public abstract class BaseIntegrationTest : IClassFixture(); } } \ No newline at end of file diff --git a/API.IntegrationTests/UserTests.cs b/API.IntegrationTests/UserTests.cs index 16775771..b3e356af 100644 --- a/API.IntegrationTests/UserTests.cs +++ b/API.IntegrationTests/UserTests.cs @@ -1,4 +1,6 @@ -namespace API.IntegrationTests; +using OpenShock.API.Services.Account; + +namespace API.IntegrationTests; public class UserTests : BaseIntegrationTest { @@ -9,6 +11,9 @@ public UserTests(IntegrationTestWebAppFactory factory) : base(factory) [Fact] public async Task Create_ShouldAdd_NewUserToDatabase() { - Console.WriteLine(":D"); + var restult = await AccountService.CreateAccount("test@test.com", "Test123", "MyPassword123"); + if (restult.IsT1) throw new Exception("NO"); + + await AccountService.Login("Test123", "MyPassword123", new LoginContext("AAA", "127.0.0.1")); } } From e0f63a657d7b748c289d27a8ca3d862e08cf780f Mon Sep 17 00:00:00 2001 From: hhvrc Date: Thu, 20 Mar 2025 10:10:08 +0100 Subject: [PATCH 6/8] Swap out xUnit with TUnit --- .../API.IntegrationTests.csproj | 10 +----- API.IntegrationTests/BaseIntegrationTest.cs | 35 ++++++++++--------- .../IntegrationTestWebAppFactory.cs | 19 +++++----- API.IntegrationTests/UserTests.cs | 20 +++++++---- 4 files changed, 43 insertions(+), 41 deletions(-) diff --git a/API.IntegrationTests/API.IntegrationTests.csproj b/API.IntegrationTests/API.IntegrationTests.csproj index 4f48a37a..3274703d 100644 --- a/API.IntegrationTests/API.IntegrationTests.csproj +++ b/API.IntegrationTests/API.IntegrationTests.csproj @@ -16,19 +16,11 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + - - - - diff --git a/API.IntegrationTests/BaseIntegrationTest.cs b/API.IntegrationTests/BaseIntegrationTest.cs index bf8b84c7..a667ea7d 100644 --- a/API.IntegrationTests/BaseIntegrationTest.cs +++ b/API.IntegrationTests/BaseIntegrationTest.cs @@ -1,27 +1,30 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using OpenShock.API.Services.Account; -using OpenShock.Common.OpenShockDb; namespace API.IntegrationTests; -public abstract class BaseIntegrationTest : IClassFixture +public abstract class BaseIntegrationTest { - private readonly IServiceScope _scope; - protected readonly OpenShockContext DbContext; - protected readonly IAccountService AccountService; + public BaseIntegrationTest() + { + Console.WriteLine("Constructor!"); + } + + [ClassDataSource(Shared = SharedType.PerAssembly)] + public required IntegrationTestWebAppFactory WebAppFactory { get; init; } + public IServiceScope ServiceScope { get; set; } - protected BaseIntegrationTest(IntegrationTestWebAppFactory factory) + public IAccountService AccountService { get; set; } + + [Before(Test)] + public Task Initialize() { - _scope = factory.Services.CreateScope(); + Console.WriteLine("Initialize!"); + + ServiceScope = WebAppFactory.Services.CreateScope(); - DbContext = _scope.ServiceProvider.GetRequiredService(); + AccountService = ServiceScope.ServiceProvider.GetRequiredService(); - if (DbContext.Database.GetPendingMigrations().Any()) - { - DbContext.Database.Migrate(); - } - - AccountService = _scope.ServiceProvider.GetRequiredService(); + return Task.CompletedTask; } } \ No newline at end of file diff --git a/API.IntegrationTests/IntegrationTestWebAppFactory.cs b/API.IntegrationTests/IntegrationTestWebAppFactory.cs index dab0fa43..e0d4bd5c 100644 --- a/API.IntegrationTests/IntegrationTestWebAppFactory.cs +++ b/API.IntegrationTests/IntegrationTestWebAppFactory.cs @@ -1,18 +1,13 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Hosting; -using OpenShock.Common.OpenShockDb; -using StackExchange.Redis; using Testcontainers.PostgreSql; using Testcontainers.Redis; +using TUnit.Core.Interfaces; namespace API.IntegrationTests; -public class IntegrationTestWebAppFactory : WebApplicationFactory +public class IntegrationTestWebAppFactory : WebApplicationFactory, IAsyncInitializer { private readonly PostgreSqlContainer _dbContainer = new PostgreSqlBuilder() .WithImage("postgres:latest") @@ -25,11 +20,15 @@ public class IntegrationTestWebAppFactory : WebApplicationFactory .WithImage("redis/redis-stack-server:latest") .Build(); + + public async Task InitializeAsync() + { + await _dbContainer.StartAsync(); + await _redisContainer.StartAsync(); + } + protected override IWebHostBuilder? CreateWebHostBuilder() { - _dbContainer.StartAsync().ConfigureAwait(false).GetAwaiter().GetResult(); - _redisContainer.StartAsync().ConfigureAwait(false).GetAwaiter().GetResult(); - var environmentVariables = new Dictionary { { "ASPNETCORE_UNDER_INTEGRATION_TEST", "1" }, diff --git a/API.IntegrationTests/UserTests.cs b/API.IntegrationTests/UserTests.cs index b3e356af..704f5896 100644 --- a/API.IntegrationTests/UserTests.cs +++ b/API.IntegrationTests/UserTests.cs @@ -1,14 +1,12 @@ -using OpenShock.API.Services.Account; +using Microsoft.Extensions.DependencyInjection; +using OpenShock.API.Services.Account; namespace API.IntegrationTests; public class UserTests : BaseIntegrationTest { - public UserTests(IntegrationTestWebAppFactory factory) : base(factory) - { - } - - [Fact] + [Test] + [NotInParallel] public async Task Create_ShouldAdd_NewUserToDatabase() { var restult = await AccountService.CreateAccount("test@test.com", "Test123", "MyPassword123"); @@ -16,4 +14,14 @@ public async Task Create_ShouldAdd_NewUserToDatabase() await AccountService.Login("Test123", "MyPassword123", new LoginContext("AAA", "127.0.0.1")); } + + [Test] + [NotInParallel] + public async Task Create_ShouldAdd_NewUserToDatabase2() + { + var restult = await AccountService.CreateAccount("test2@test.com", "Test124", "MyPassword123"); + if (restult.IsT1) throw new Exception("NO"); + + await AccountService.Login("Test124", "MyPassword123", new LoginContext("AAA", "127.0.0.1")); + } } From 0e5fe9036be522abb9a618f02a381a2b44a7e58d Mon Sep 17 00:00:00 2001 From: hhvrc Date: Thu, 20 Mar 2025 16:49:24 +0100 Subject: [PATCH 7/8] Make first actual integration test --- API.IntegrationTests/AccountTests.cs | 29 +++++++++++++++++++++ API.IntegrationTests/BaseIntegrationTest.cs | 27 ++----------------- API.IntegrationTests/UserTests.cs | 27 ------------------- Common/Utils/ConnectionDetailsFetcher.cs | 5 ++-- 4 files changed, 33 insertions(+), 55 deletions(-) create mode 100644 API.IntegrationTests/AccountTests.cs delete mode 100644 API.IntegrationTests/UserTests.cs diff --git a/API.IntegrationTests/AccountTests.cs b/API.IntegrationTests/AccountTests.cs new file mode 100644 index 00000000..0d0a9b08 --- /dev/null +++ b/API.IntegrationTests/AccountTests.cs @@ -0,0 +1,29 @@ +using System.Net; +using System.Text; +using System.Text.Json; + +namespace API.IntegrationTests; + +public class AccountTests : BaseIntegrationTest +{ + [Test] + public async Task CreateAccount_ShouldAdd_NewUserToDatabase() + { + using var client = WebAppFactory.CreateClient(); + + var requestBody = JsonSerializer.Serialize(new + { + username = "Bob", + password = "SecurePassword123#", + email = "bob@example.com", + turnstileresponse = "lmao" + }); + + + var response = await client.PostAsync("/2/account/signup", new StringContent(requestBody, Encoding.UTF8, "application/json")); + + var content = await response.Content.ReadAsStringAsync(); + + await Assert.That(response.StatusCode).IsEqualTo(HttpStatusCode.OK); + } +} diff --git a/API.IntegrationTests/BaseIntegrationTest.cs b/API.IntegrationTests/BaseIntegrationTest.cs index a667ea7d..babdbeef 100644 --- a/API.IntegrationTests/BaseIntegrationTest.cs +++ b/API.IntegrationTests/BaseIntegrationTest.cs @@ -1,30 +1,7 @@ -using Microsoft.Extensions.DependencyInjection; -using OpenShock.API.Services.Account; - -namespace API.IntegrationTests; +namespace API.IntegrationTests; public abstract class BaseIntegrationTest { - public BaseIntegrationTest() - { - Console.WriteLine("Constructor!"); - } - - [ClassDataSource(Shared = SharedType.PerAssembly)] + [ClassDataSource(Shared = SharedType.PerTestSession)] public required IntegrationTestWebAppFactory WebAppFactory { get; init; } - public IServiceScope ServiceScope { get; set; } - - public IAccountService AccountService { get; set; } - - [Before(Test)] - public Task Initialize() - { - Console.WriteLine("Initialize!"); - - ServiceScope = WebAppFactory.Services.CreateScope(); - - AccountService = ServiceScope.ServiceProvider.GetRequiredService(); - - return Task.CompletedTask; - } } \ No newline at end of file diff --git a/API.IntegrationTests/UserTests.cs b/API.IntegrationTests/UserTests.cs deleted file mode 100644 index 704f5896..00000000 --- a/API.IntegrationTests/UserTests.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using OpenShock.API.Services.Account; - -namespace API.IntegrationTests; - -public class UserTests : BaseIntegrationTest -{ - [Test] - [NotInParallel] - public async Task Create_ShouldAdd_NewUserToDatabase() - { - var restult = await AccountService.CreateAccount("test@test.com", "Test123", "MyPassword123"); - if (restult.IsT1) throw new Exception("NO"); - - await AccountService.Login("Test123", "MyPassword123", new LoginContext("AAA", "127.0.0.1")); - } - - [Test] - [NotInParallel] - public async Task Create_ShouldAdd_NewUserToDatabase2() - { - var restult = await AccountService.CreateAccount("test2@test.com", "Test124", "MyPassword123"); - if (restult.IsT1) throw new Exception("NO"); - - await AccountService.Login("Test124", "MyPassword123", new LoginContext("AAA", "127.0.0.1")); - } -} diff --git a/Common/Utils/ConnectionDetailsFetcher.cs b/Common/Utils/ConnectionDetailsFetcher.cs index 78480d36..e1738675 100644 --- a/Common/Utils/ConnectionDetailsFetcher.cs +++ b/Common/Utils/ConnectionDetailsFetcher.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.Primitives; -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Net; namespace OpenShock.Common.Utils; @@ -8,7 +7,7 @@ public static class ConnectionDetailsFetcher { public static IPAddress GetRemoteIP(this HttpContext context) { - return context.Connection?.RemoteIpAddress ?? throw new NullReferenceException("Unable to get any IP address, underlying transport type is not TCP???"); // This should never happen, as the underlying transport type will always be TCP + return context.Connection?.RemoteIpAddress ?? IPAddress.Loopback; // IPAddress is null under integration testing } public static string GetUserAgent(this HttpContext context) From e3ac6522f63b28ef3075069ac7feb4b7f9c6b101 Mon Sep 17 00:00:00 2001 From: hhvrc Date: Fri, 21 Mar 2025 02:33:27 +0100 Subject: [PATCH 8/8] Use shared props for API IntegrationTests --- API.IntegrationTests/API.IntegrationTests.csproj | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/API.IntegrationTests/API.IntegrationTests.csproj b/API.IntegrationTests/API.IntegrationTests.csproj index 3274703d..f097190c 100644 --- a/API.IntegrationTests/API.IntegrationTests.csproj +++ b/API.IntegrationTests/API.IntegrationTests.csproj @@ -1,4 +1,5 @@  + net9.0 @@ -8,12 +9,7 @@ - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - -