diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ebd41d3..8f6695aa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,7 @@ jobs: run: | dotnet test './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj' -c Release --framework net8.0 dotnet test './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj' -c Release --framework net8.0 + dotnet test './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj' -c Release --framework net8.0 linux-build-and-run: name: Run Tests on Linux @@ -38,6 +39,7 @@ jobs: run: | dotnet test './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj' -c Release --framework net8.0 dotnet test './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj' -c Release --framework net8.0 + dotnet test './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj' -c Release --framework net8.0 - name: Install .NET Aspire workload run: dotnet workload install aspire diff --git a/WireMock.Net Solution.sln b/WireMock.Net Solution.sln index 1f243cb8..ea1480ff 100644 --- a/WireMock.Net Solution.sln +++ b/WireMock.Net Solution.sln @@ -131,7 +131,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Aspire.TestApp EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspireApp1.AppHostOriginal", "examples-Aspire\AspireApp1.AppHostOriginal\AspireApp1.AppHostOriginal.csproj", "{C9210DA3-F390-4598-8512-349A473FE9C9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.TUnit", "src\WireMock.Net.TUnit\WireMock.Net.TUnit.csproj", "{91024A93-848F-4A02-AF53-5EBE5834E23C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.TUnit", "src\WireMock.Net.TUnit\WireMock.Net.TUnit.csproj", "{91024A93-848F-4A02-AF53-5EBE5834E23C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.TUnitTests", "test\WireMock.Net.TUnitTests\WireMock.Net.TUnitTests.csproj", "{4CD237F7-B616-46B8-872F-E49B4BBB3EAE}" EndProject @@ -139,6 +139,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.WebApplication EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.AspNetCore.Middleware", "src\WireMock.Net.AspNetCore.Middleware\WireMock.Net.AspNetCore.Middleware.csproj", "{B6269AAC-170A-4346-8B9A-579DED3D9A13}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.TestWebApplication", "test\WireMock.Net.TestWebApplication\WireMock.Net.TestWebApplication.csproj", "{6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Middleware.Tests", "test\WireMock.Net.Middleware.Tests\WireMock.Net.Middleware.Tests.csproj", "{A5FEF4F7-7DA2-4962-89A8-16BA942886E5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -341,6 +345,14 @@ Global {B6269AAC-170A-4346-8B9A-579DED3D9A13}.Debug|Any CPU.Build.0 = Debug|Any CPU {B6269AAC-170A-4346-8B9A-579DED3D9A13}.Release|Any CPU.ActiveCfg = Release|Any CPU {B6269AAC-170A-4346-8B9A-579DED3D9A13}.Release|Any CPU.Build.0 = Release|Any CPU + {6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE}.Release|Any CPU.Build.0 = Release|Any CPU + {A5FEF4F7-7DA2-4962-89A8-16BA942886E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A5FEF4F7-7DA2-4962-89A8-16BA942886E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A5FEF4F7-7DA2-4962-89A8-16BA942886E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A5FEF4F7-7DA2-4962-89A8-16BA942886E5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -397,6 +409,8 @@ Global {4CD237F7-B616-46B8-872F-E49B4BBB3EAE} = {0BB8B634-407A-4610-A91F-11586990767A} {E72ADFAB-4B42-439E-B1EE-C06E504B35D2} = {985E0ADB-D4B4-473A-AA40-567E279B7946} {B6269AAC-170A-4346-8B9A-579DED3D9A13} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2} + {6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE} = {0BB8B634-407A-4610-A91F-11586990767A} + {A5FEF4F7-7DA2-4962-89A8-16BA942886E5} = {0BB8B634-407A-4610-A91F-11586990767A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458} diff --git a/azure-pipelines-ci.yml b/azure-pipelines-ci.yml index 3b2523fc..498f6bba 100644 --- a/azure-pipelines-ci.yml +++ b/azure-pipelines-ci.yml @@ -54,6 +54,7 @@ jobs: script: | dotnet-coverage collect "dotnet test ./test/WireMock.Net.Tests/WireMock.Net.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-xunit.xml" dotnet-coverage collect "dotnet test ./test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-tunit.xml" + dotnet-coverage collect "dotnet test ./test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-middleware.xml" displayName: 'Execute WireMock.Net.Tests with Coverage' - task: CmdLine@2 diff --git a/src/WireMock.Net.AspNetCore.Middleware/AppConstants.cs b/src/WireMock.Net.AspNetCore.Middleware/AppConstants.cs index 25c34add..954dc8b4 100644 --- a/src/WireMock.Net.AspNetCore.Middleware/AppConstants.cs +++ b/src/WireMock.Net.AspNetCore.Middleware/AppConstants.cs @@ -4,6 +4,6 @@ namespace WireMock.Net.AspNetCore.Middleware; internal static class AppConstants { - internal const string HEADER_STATUS = "X-WireMock-Status"; + internal const string HEADER_REDIRECT = "X-WireMock-Redirect"; internal const string HEADER_RESPONSE_DELAY = "X-WireMock-Response-Delay"; } \ No newline at end of file diff --git a/src/WireMock.Net.AspNetCore.Middleware/HttpDelegatingHandler/WireMockDelegationHandler.cs b/src/WireMock.Net.AspNetCore.Middleware/HttpDelegatingHandler/WireMockDelegationHandler.cs index 3ca081c9..7eefd136 100644 --- a/src/WireMock.Net.AspNetCore.Middleware/HttpDelegatingHandler/WireMockDelegationHandler.cs +++ b/src/WireMock.Net.AspNetCore.Middleware/HttpDelegatingHandler/WireMockDelegationHandler.cs @@ -39,7 +39,7 @@ protected override async Task SendAsync(HttpRequestMessage Guard.NotNull(request); Guard.NotNull(_httpContextAccessor.HttpContext); - if (_settings.AlwaysRedirect || IsWireMockStatusHeaderSetToTrue()) + if (_settings.AlwaysRedirect || IsWireMockRedirectHeaderSetToTrue()) { _logger.LogDebug("Redirecting request to WireMock server"); if (_server.Instance?.Url != null) @@ -56,10 +56,10 @@ protected override async Task SendAsync(HttpRequestMessage return await base.SendAsync(request, cancellationToken); } - private bool IsWireMockStatusHeaderSetToTrue() + private bool IsWireMockRedirectHeaderSetToTrue() { return - _httpContextAccessor.HttpContext!.Request.Headers.TryGetValue(AppConstants.HEADER_STATUS, out var values) && + _httpContextAccessor.HttpContext!.Request.Headers.TryGetValue(AppConstants.HEADER_REDIRECT, out var values) && bool.TryParse(values.ToString(), out var shouldRedirectToWireMock) && shouldRedirectToWireMock; } diff --git a/src/WireMock.Net.AspNetCore.Middleware/ServiceCollectionExtensions.cs b/src/WireMock.Net.AspNetCore.Middleware/ServiceCollectionExtensions.cs index fb5b9cc2..8a933d03 100644 --- a/src/WireMock.Net.AspNetCore.Middleware/ServiceCollectionExtensions.cs +++ b/src/WireMock.Net.AspNetCore.Middleware/ServiceCollectionExtensions.cs @@ -20,7 +20,7 @@ public static class ServiceCollectionExtensions public static IServiceCollection AddWireMockService( this IServiceCollection services, Action configure, - bool alwaysRedirectToWireMock = false, + bool alwaysRedirectToWireMock = true, WireMockServerSettings? settings = null ) { diff --git a/test/WireMock.Net.Middleware.Tests/CustomWebApplicationFactory.cs b/test/WireMock.Net.Middleware.Tests/CustomWebApplicationFactory.cs new file mode 100644 index 00000000..00ebcd7a --- /dev/null +++ b/test/WireMock.Net.Middleware.Tests/CustomWebApplicationFactory.cs @@ -0,0 +1,25 @@ +// Copyright © WireMock.Net + +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; + +namespace WireMock.Net.Middleware.Tests; + +internal class CustomWebApplicationFactory : WebApplicationFactory + where TEntryPoint : class +{ + private readonly List<(string Key, string Value)> _settings = new(); + + public CustomWebApplicationFactory(bool alwaysRedirectToWireMock = true) + { + _settings.Add(("AlwaysRedirectToWireMock", alwaysRedirectToWireMock.ToString().ToLowerInvariant())); + } + + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + foreach (var arg in _settings) + { + builder.UseSetting(arg.Key, arg.Value); + } + } +} \ No newline at end of file diff --git a/test/WireMock.Net.Middleware.Tests/IntegrationTests.cs b/test/WireMock.Net.Middleware.Tests/IntegrationTests.cs new file mode 100644 index 00000000..c2b9f79a --- /dev/null +++ b/test/WireMock.Net.Middleware.Tests/IntegrationTests.cs @@ -0,0 +1,48 @@ +// Copyright © WireMock.Net + +using FluentAssertions; +using WireMock.Net.TestWebApplication; + +namespace WireMock.Net.Middleware.Tests; + +public class IntegrationTests +{ + [Theory] + [InlineData("/real1", "Hello 1 from WireMock.Net !")] + [InlineData("/real2", "Hello 2 from WireMock.Net !")] + public async Task CallingRealApi_WithAlwaysRedirectToWireMockIsTrue(string requestUri, string expectedResponse) + { + // Arrange + await using var factory = new CustomWebApplicationFactory(); + using var client = factory.CreateClient(); + + // Act + var response = await client.GetAsync(requestUri); + + // Assert + response.EnsureSuccessStatusCode(); + var stringResponse = await response.Content.ReadAsStringAsync(); + stringResponse.Should().Be(expectedResponse); + } + + [Theory] + [InlineData("/real1", "Hello 1 from WireMock.Net !")] + [InlineData("/real2", "Hello 2 from WireMock.Net !")] + public async Task CallingRealApi_WithAlwaysRedirectToWireMockIsFalse(string requestUri, string expectedResponse) + { + // Arrange + await using var factory = new CustomWebApplicationFactory(false); + using var client = factory.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, requestUri); + request.Headers.Add("X-WireMock-Redirect", "true"); + + // Act + var response = await client.SendAsync(request); + + // Assert + response.EnsureSuccessStatusCode(); + var stringResponse = await response.Content.ReadAsStringAsync(); + stringResponse.Should().Be(expectedResponse); + } +} \ No newline at end of file diff --git a/test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj b/test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj new file mode 100644 index 00000000..fec8bdf6 --- /dev/null +++ b/test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj @@ -0,0 +1,43 @@ + + + + net8.0 + enable + enable + false + true + true + ../../src/WireMock.Net/WireMock.Net.snk + true + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + \ No newline at end of file diff --git a/test/WireMock.Net.TestWebApplication/Program.cs b/test/WireMock.Net.TestWebApplication/Program.cs new file mode 100644 index 00000000..63320a13 --- /dev/null +++ b/test/WireMock.Net.TestWebApplication/Program.cs @@ -0,0 +1,49 @@ +using WireMock.Net.AspNetCore.Middleware; +using WireMock.RequestBuilders; +using WireMock.ResponseBuilders; + +namespace WireMock.Net.TestWebApplication; + +// Make the implicit Program class public so test projects can access it. +public class Program +{ + public static async Task Main(string[] args) + { + var alwaysRedirectToWireMock = args.Contains("--AlwaysRedirectToWireMock=true"); + + var builder = WebApplication.CreateBuilder(args); + + builder.Services.AddWireMockService(server => + { + server.Given(Request.Create() + .WithPath("/test1") + .UsingAnyMethod() + ).RespondWith(Response.Create() + .WithBody("Hello 1 from WireMock.Net !") + ); + + server.Given(Request.Create() + .WithPath("/test2") + .UsingAnyMethod() + ).RespondWith(Response.Create() + .WithBody("Hello 2 from WireMock.Net !") + ); + }, alwaysRedirectToWireMock); + + var app = builder.Build(); + + app.MapGet("/real1", async (HttpClient client) => + { + var result = await client.GetStringAsync("https://real-api:12345/test1"); + return result; + }); + + app.MapGet("/real2", async (IHttpClientFactory factory) => + { + using var client = factory.CreateClient(); + return await client.GetStringAsync("https://real-api:12345/test2"); + }); + + await app.RunAsync(); + } +} \ No newline at end of file diff --git a/test/WireMock.Net.TestWebApplication/WireMock.Net.TestWebApplication.csproj b/test/WireMock.Net.TestWebApplication/WireMock.Net.TestWebApplication.csproj new file mode 100644 index 00000000..acfdf66c --- /dev/null +++ b/test/WireMock.Net.TestWebApplication/WireMock.Net.TestWebApplication.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/test/WireMock.Net.TestWebApplication/appsettings.json b/test/WireMock.Net.TestWebApplication/appsettings.json new file mode 100644 index 00000000..7cb1bd58 --- /dev/null +++ b/test/WireMock.Net.TestWebApplication/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} \ No newline at end of file