Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions API.IntegrationTests/API.IntegrationTests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../Shared.props" />

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.3" />
<PackageReference Include="Testcontainers.PostgreSql" Version="4.3.0" />
<PackageReference Include="Testcontainers.Redis" Version="4.3.0" />
<PackageReference Include="TUnit" Version="0.18.52" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\API\API.csproj" />
</ItemGroup>

</Project>
29 changes: 29 additions & 0 deletions API.IntegrationTests/AccountTests.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
7 changes: 7 additions & 0 deletions API.IntegrationTests/BaseIntegrationTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace API.IntegrationTests;

public abstract class BaseIntegrationTest
{
[ClassDataSource<IntegrationTestWebAppFactory>(Shared = SharedType.PerTestSession)]
public required IntegrationTestWebAppFactory WebAppFactory { get; init; }
}
91 changes: 91 additions & 0 deletions API.IntegrationTests/IntegrationTestWebAppFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Testcontainers.PostgreSql;
using Testcontainers.Redis;
using TUnit.Core.Interfaces;

namespace API.IntegrationTests;

public class IntegrationTestWebAppFactory : WebApplicationFactory<Program>, IAsyncInitializer
{
private readonly PostgreSqlContainer _dbContainer = new PostgreSqlBuilder()
.WithImage("postgres:latest")
.WithDatabase("openshock")
.WithUsername("openshock")
.WithPassword("superSecurePassword")
.Build();

private readonly RedisContainer _redisContainer = new RedisBuilder()
.WithImage("redis/redis-stack-server:latest")
.Build();


public async Task InitializeAsync()
{
await _dbContainer.StartAsync();
await _redisContainer.StartAsync();
}

protected override IWebHostBuilder? CreateWebHostBuilder()
{
var environmentVariables = new Dictionary<string, string>
{
{ "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 =>
{
// We can replace services here
});
}

public override async ValueTask DisposeAsync()
{
await _dbContainer.DisposeAsync();
await _redisContainer.DisposeAsync();
await base.DisposeAsync();
}
}
4 changes: 4 additions & 0 deletions API/API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,8 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="$(AssemblyName).Tests.Integration" />
</ItemGroup>
</Project>
3 changes: 3 additions & 0 deletions API/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,6 @@
app.MapScalarApiReference(options => options.OpenApiRoutePattern = "/swagger/{documentName}/swagger.json");

app.Run();

// Expose Program class for integrationtests
public partial class Program;
22 changes: 15 additions & 7 deletions Common/OpenShockApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,21 @@ public static WebApplicationBuilder CreateDefaultBuilder<TProgram>(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<TProgram>(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<TProgram>(true)
.AddCommandLine(args);
}

var isDevelopment = builder.Environment.IsDevelopment();
builder.Host.UseDefaultServiceProvider((_, options) =>
Expand Down
5 changes: 2 additions & 3 deletions Common/Utils/ConnectionDetailsFetcher.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft.Extensions.Primitives;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using System.Net;

namespace OpenShock.Common.Utils;
Expand All @@ -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)
Expand Down
9 changes: 9 additions & 0 deletions OpenShockBackend.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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.IntegrationTests", "API.IntegrationTests\API.IntegrationTests.csproj", "{9A9C5529-54A2-490C-A537-242D339054E8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -45,8 +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
{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
Loading