From b99a80e78281b38529b0472a1b3e8f8629ba8030 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 6 Sep 2024 15:11:30 +0200 Subject: [PATCH 1/9] Update README.md (Fix NuGet and MyGet badges) --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 04d2a921..df1f66b1 100644 --- a/README.md +++ b/README.md @@ -39,16 +39,16 @@ For more info, see also this WIKI page: [What is WireMock.Net](https://github.co | | Official | Preview [:information_source:](https://github.com/WireMock-Net/WireMock.Net/wiki/MyGet-preview-versions) | | - | - | - | -|   **WireMock.Net** | [![NuGet Badge WireMock.Net](https://buildstats.info/nuget/WireMock.Net)](https://www.nuget.org/packages/WireMock.Net) | [![MyGet Badge WireMock.Net](https://buildstats.info/myget/wiremock-net/WireMock.Net?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net) -|   **WireMock.Net.StandAlone** | [![NuGet Badge WireMock.Net](https://buildstats.info/nuget/WireMock.Net.StandAlone)](https://www.nuget.org/packages/WireMock.Net.StandAlone) | [![MyGet Badge WireMock.Net.StandAlone](https://buildstats.info/myget/wiremock-net/WireMock.Net.StandAlone?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.StandAlone) -|   **WireMock.Net.FluentAssertions** | [![NuGet Badge WireMock.Net.FluentAssertions](https://buildstats.info/nuget/WireMock.Net.FluentAssertions)](https://www.nuget.org/packages/WireMock.Net.FluentAssertions) | [![MyGet Badge WireMock.Net.FluentAssertions](https://buildstats.info/myget/wiremock-net/WireMock.Net.FluentAssertions?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.FluentAssertions) -|   **WireMock.Net.Matchers.CSharpCode** | [![NuGet Badge WireMock.Net.Matchers.CSharpCode](https://buildstats.info/nuget/WireMock.Net.Matchers.CSharpCode)](https://www.nuget.org/packages/WireMock.Net.Matchers.CSharpCode) | [![MyGet Badge WireMock.Net.Matchers.CSharpCode](https://buildstats.info/myget/wiremock-net/WireMock.Net.Matchers.CSharpCode?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Matchers.CSharpCode) -|   **WireMock.Net.OpenApiParser** | [![NuGet Badge WireMock.Net.OpenApiParser](https://buildstats.info/nuget/WireMock.Net.OpenApiParser)](https://www.nuget.org/packages/WireMock.Net.OpenApiParser) | [![MyGet Badge WireMock.Net.OpenApiParser](https://buildstats.info/myget/wiremock-net/WireMock.Net.OpenApiParser?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.OpenApiParser) -|   **WireMock.Net.RestClient** | [![NuGet Badge WireMock.Net.RestClient](https://buildstats.info/nuget/WireMock.Net.RestClient)](https://www.nuget.org/packages/WireMock.Net.RestClient) | [![MyGet Badge WireMock.Net.RestClient](https://buildstats.info/myget/wiremock-net/WireMock.Net.RestClient?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.RestClient) -|   **WireMock.Net.xUnit** | [![NuGet Badge WireMock.Net.xUnit](https://buildstats.info/nuget/WireMock.Net.xUnit)](https://www.nuget.org/packages/WireMock.Net.xUnit) | [![MyGet Badge WireMock.Net.xUnit](https://buildstats.info/myget/wiremock-net/WireMock.Net.xUnit?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.xUnit) -|   **WireMock.Net.Testcontainers** | [![NuGet Badge WireMock.Net.Testcontainers](https://buildstats.info/nuget/WireMock.Net.Testcontainers)](https://www.nuget.org/packages/WireMock.Net.Testcontainers) | [![MyGet Badge WireMock.Net.Testcontainers](https://buildstats.info/myget/wiremock-net/WireMock.Net.Testcontainers?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Testcontainers) -|   **WireMock.Net.Aspire** | [![NuGet Badge WireMock.Net.Aspire](https://buildstats.info/nuget/WireMock.Net.Aspire)](https://www.nuget.org/packages/WireMock.Net.Aspire) | [![MyGet Badge WireMock.Net.Aspire](https://buildstats.info/myget/wiremock-net/WireMock.Net.Aspire?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Aspire) -|   **WireMock.Org.RestClient** | [![NuGet Badge WireMock.Org.RestClient](https://buildstats.info/nuget/WireMock.Org.RestClient)](https://www.nuget.org/packages/WireMock.Org.RestClient) | [![MyGet Badge WireMock.Org.RestClient](https://buildstats.info/myget/wiremock-net/WireMock.Org.RestClient?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Org.RestClient) +|   **WireMock.Net** | [![NuGet Badge WireMock.Net](https://img.shields.io/nuget/v/WireMock.Net)](https://www.nuget.org/packages/WireMock.Net) | [![MyGet Badge WireMock.Net](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net) +|   **WireMock.Net.StandAlone** | [![NuGet Badge WireMock.Net](https://img.shields.io/nuget/v/WireMock.Net.StandAlone)](https://www.nuget.org/packages/WireMock.Net.StandAlone) | [![MyGet Badge WireMock.Net.StandAlone](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.StandAlone?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.StandAlone) +|   **WireMock.Net.FluentAssertions** | [![NuGet Badge WireMock.Net.FluentAssertions](https://img.shields.io/nuget/v/WireMock.Net.FluentAssertions)](https://www.nuget.org/packages/WireMock.Net.FluentAssertions) | [![MyGet Badge WireMock.Net.FluentAssertions](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.FluentAssertions?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.FluentAssertions) +|   **WireMock.Net.Matchers.CSharpCode** | [![NuGet Badge WireMock.Net.Matchers.CSharpCode](https://img.shields.io/nuget/v/WireMock.Net.Matchers.CSharpCode)](https://www.nuget.org/packages/WireMock.Net.Matchers.CSharpCode) | [![MyGet Badge WireMock.Net.Matchers.CSharpCode](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.Matchers.CSharpCode?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Matchers.CSharpCode) +|   **WireMock.Net.OpenApiParser** | [![NuGet Badge WireMock.Net.OpenApiParser](https://img.shields.io/nuget/v/WireMock.Net.OpenApiParser)](https://www.nuget.org/packages/WireMock.Net.OpenApiParser) | [![MyGet Badge WireMock.Net.OpenApiParser](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.OpenApiParser?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.OpenApiParser) +|   **WireMock.Net.RestClient** | [![NuGet Badge WireMock.Net.RestClient](https://img.shields.io/nuget/v/WireMock.Net.RestClient)](https://www.nuget.org/packages/WireMock.Net.RestClient) | [![MyGet Badge WireMock.Net.RestClient](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.RestClient?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.RestClient) +|   **WireMock.Net.xUnit** | [![NuGet Badge WireMock.Net.xUnit](https://img.shields.io/nuget/v/WireMock.Net.xUnit)](https://www.nuget.org/packages/WireMock.Net.xUnit) | [![MyGet Badge WireMock.Net.xUnit](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.xUnit?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.xUnit) +|   **WireMock.Net.Testcontainers** | [![NuGet Badge WireMock.Net.Testcontainers](https://img.shields.io/nuget/v/WireMock.Net.Testcontainers)](https://www.nuget.org/packages/WireMock.Net.Testcontainers) | [![MyGet Badge WireMock.Net.Testcontainers](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.Testcontainers?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Testcontainers) +|   **WireMock.Net.Aspire** | [![NuGet Badge WireMock.Net.Aspire](https://img.shields.io/nuget/v/WireMock.Net.Aspire)](https://www.nuget.org/packages/WireMock.Net.Aspire) | [![MyGet Badge WireMock.Net.Aspire](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.Aspire?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Aspire) +|   **WireMock.Org.RestClient** | [![NuGet Badge WireMock.Org.RestClient](https://img.shields.io/nuget/v/WireMock.Org.RestClient)](https://www.nuget.org/packages/WireMock.Org.RestClient) | [![MyGet Badge WireMock.Org.RestClient](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Org.RestClient?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Org.RestClient) ## :memo: Development From 60931f627312de652c65e0d6baaf941f24cf8a8f Mon Sep 17 00:00:00 2001 From: cocoon Date: Sat, 7 Sep 2024 09:31:19 +0200 Subject: [PATCH 2/9] Fix listen on AnyIP for url 0.0.0.0 (#1165) * fix listen to AnyIP if url is 0.0.0.0 * Add Test for listenin on AnyIP for url 0.0.0.0 * add missing using, use var, indent, remove empty line * remove assert for ipv4/v6 address list * test only if NET6_0_OR_GREATER * use same code style * add missing + * Asser. to Assert * split single test into one for IPv4 and one for IPv6 * Create IgnoreOnContinuousIntegrationFact.cs * Ignore tests if CI/CD * change to file - scoped namespace and add GITHUB_ACTIONS * use PortUtils.FindFreeTcpPort() * add and use GetIPAddressesByFamily * add using System.Net.Sockets * use #if for both unit tests and include new helper method inside --- .../Owin/AspNetCoreSelfHost.NETStandard.cs | 11 ++- .../IgnoreOnContinuousIntegrationFact.cs | 22 ++++++ .../WireMock.Net.Tests/WireMockServerTests.cs | 75 ++++++++++++++++++- 3 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 test/WireMock.Net.Tests/Facts/IgnoreOnContinuousIntegrationFact.cs diff --git a/src/WireMock.Net/Owin/AspNetCoreSelfHost.NETStandard.cs b/src/WireMock.Net/Owin/AspNetCoreSelfHost.NETStandard.cs index 26536ece..0cbbed20 100644 --- a/src/WireMock.Net/Owin/AspNetCoreSelfHost.NETStandard.cs +++ b/src/WireMock.Net/Owin/AspNetCoreSelfHost.NETStandard.cs @@ -75,8 +75,15 @@ private static void SetHttpsAndUrls(KestrelServerOptions kestrelOptions, IWireMo private static void Listen(KestrelServerOptions kestrelOptions, HostUrlDetails urlDetail, Action configure) { + // Listens on any IP with the given port. + if (urlDetail is { Port: > 0, Host: "0.0.0.0" }) + { + kestrelOptions.ListenAnyIP(urlDetail.Port, configure); + return; + } + // Listens on ::1 and 127.0.0.1 with the given port. - if (urlDetail is { Port: > 0, Host: "localhost" or "127.0.0.1" or "0.0.0.0" or "::1" }) + if (urlDetail is { Port: > 0, Host: "localhost" or "127.0.0.1" or "::1" }) { kestrelOptions.ListenLocalhost(urlDetail.Port, configure); return; @@ -113,4 +120,4 @@ internal static IWebHostBuilder ConfigureKestrelServerOptions(this IWebHostBuild } } } -#endif \ No newline at end of file +#endif diff --git a/test/WireMock.Net.Tests/Facts/IgnoreOnContinuousIntegrationFact.cs b/test/WireMock.Net.Tests/Facts/IgnoreOnContinuousIntegrationFact.cs new file mode 100644 index 00000000..d1254d94 --- /dev/null +++ b/test/WireMock.Net.Tests/Facts/IgnoreOnContinuousIntegrationFact.cs @@ -0,0 +1,22 @@ +// Copyright © WireMock.Net + +using System; +using Xunit; + +namespace WireMock.Net.Tests.Facts; + +public sealed class IgnoreOnContinuousIntegrationFact : FactAttribute +{ + private static readonly string _skipReason = "Ignore when run via CI/CD"; + private static readonly bool _isContinuousIntegrationAzure = bool.TryParse(Environment.GetEnvironmentVariable("TF_BUILD"), out var isTF) && isTF; + private static readonly bool _isContinuousIntegrationGithub = bool.TryParse(Environment.GetEnvironmentVariable("GITHUB_ACTIONS"), out var isGH) && isGH; + private static bool IsContinuousIntegration() => _isContinuousIntegrationAzure || _isContinuousIntegrationGithub; + + public IgnoreOnContinuousIntegrationFact() + { + if (IsContinuousIntegration()) + { + Skip = _skipReason; + } + } +} diff --git a/test/WireMock.Net.Tests/WireMockServerTests.cs b/test/WireMock.Net.Tests/WireMockServerTests.cs index c53a7aa3..dfe24c63 100644 --- a/test/WireMock.Net.Tests/WireMockServerTests.cs +++ b/test/WireMock.Net.Tests/WireMockServerTests.cs @@ -8,6 +8,8 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; +using System.Net.NetworkInformation; +using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using FluentAssertions; @@ -16,6 +18,7 @@ using WireMock.Admin.Mappings; using WireMock.Http; using WireMock.Matchers; +using WireMock.Net.Tests.Facts; using WireMock.Net.Tests.Serialization; using WireMock.Net.Xunit; using WireMock.RequestBuilders; @@ -37,7 +40,7 @@ public WireMockServerTests(ITestOutputHelper testOutputHelper) { _testOutputHelper = testOutputHelper; } - + [Fact] public void WireMockServer_Start() { @@ -196,6 +199,70 @@ public async Task WireMockServer_When_HttpClientWithWebProxyCallsHttp_Should_Wor } #endif +#if NET6_0_OR_GREATER + private static string[] GetIPAddressesByFamily(AddressFamily addressFamily) + { + return NetworkInterface.GetAllNetworkInterfaces() + .Where(ni => ni.OperationalStatus == OperationalStatus.Up) + .SelectMany(ni => ni.GetIPProperties().UnicastAddresses) + .Where(addr => addr.Address.AddressFamily == addressFamily) + .Select(addr => addr.Address.ToString()) + .ToArray(); + } + + [IgnoreOnContinuousIntegrationFact] + public async Task WireMockServer_WithUrl0000_Should_Listen_On_All_IPs_IPv4() + { + // Arrange + var port = PortUtils.FindFreeTcpPort(); + var IPv4 = GetIPAddressesByFamily(System.Net.Sockets.AddressFamily.InterNetwork); + var settings = new WireMockServerSettings + { + Urls = new string[] { "http://0.0.0.0:" + port }, + }; + var server = WireMockServer.Start(settings); + + server.Given(Request.Create().WithPath("/*")).RespondWith(Response.Create().WithBody("x")); + + foreach (var addr in IPv4) + { + // Act + var response = await new HttpClient().GetStringAsync("http://" + addr + ":" + server.Ports[0] + "/foo").ConfigureAwait(false); + + // Assert + response.Should().Be("x"); + } + + server.Stop(); + } + + [IgnoreOnContinuousIntegrationFact] + public async Task WireMockServer_WithUrl0000_Should_Listen_On_All_IPs_IPv6() + { + // Arrange + var port = PortUtils.FindFreeTcpPort(); + var IPv6 = GetIPAddressesByFamily(System.Net.Sockets.AddressFamily.InterNetworkV6); + var settings = new WireMockServerSettings + { + Urls = new string[] { "http://0.0.0.0:" + port }, + }; + var server = WireMockServer.Start(settings); + + server.Given(Request.Create().WithPath("/*")).RespondWith(Response.Create().WithBody("x")); + + foreach (var addr in IPv6) + { + // Act + var response = await new HttpClient().GetStringAsync("http://[" + addr + "]:" + server.Ports[0] + "/foo").ConfigureAwait(false); + + // Assert + response.Should().Be("x"); + } + + server.Stop(); + } +#endif + [Fact] public async Task WireMockServer_Should_respond_a_redirect_without_body() { @@ -248,7 +315,7 @@ public async Task WireMockServer_WithCorsPolicyOptions_Should_Work_Correct() // Act var response = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + "/foo").ConfigureAwait(false); - // Asser. + // Assert response.Should().Be("x"); server.Stop(); @@ -274,7 +341,7 @@ public async Task WireMockServer_Should_delay_responses_for_a_given_route() await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + "/foo").ConfigureAwait(false); watch.Stop(); - // Asser. + // Assert watch.ElapsedMilliseconds.Should().BeGreaterOrEqualTo(0); server.Stop(); @@ -662,4 +729,4 @@ public async Task WireMockServer_Using_JsonMapping_And_CustomMatcher_WithIncorre server.Stop(); } #endif -} \ No newline at end of file +} From af124d556db4a9fb94b3dce0811cf83200cf9034 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 7 Sep 2024 09:36:33 +0200 Subject: [PATCH 3/9] 1.6.3 --- CHANGELOG.md | 4 ++++ Directory.Build.props | 2 +- Generate-ReleaseNotes.cmd | 2 +- PackageReleaseNotes.txt | 9 +++------ 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d567d66..16863ae9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.6.3 (07 September 2024) +- [#1165](https://github.com/WireMock-Net/WireMock.Net/pull/1165) - Fix listen on AnyIP for url 0.0.0.0 contributed by [cocoon](https://github.com/cocoon) +- [#1154](https://github.com/WireMock-Net/WireMock.Net/issues/1154) - Listen on all ips [bug] + # 1.6.2 (04 September 2024) - [#1152](https://github.com/WireMock-Net/WireMock.Net/pull/1152) - Update MappingConverter to correctly write the Matcher as C# code [bug] contributed by [StefH](https://github.com/StefH) - [#1163](https://github.com/WireMock-Net/WireMock.Net/pull/1163) - Upgrade Aspire to version 8.2.0 [feature] contributed by [StefH](https://github.com/StefH) diff --git a/Directory.Build.props b/Directory.Build.props index 6ac74555..b653450e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ - 1.6.2 + 1.6.3 WireMock.Net-Logo.png https://github.com/WireMock-Net/WireMock.Net Apache-2.0 diff --git a/Generate-ReleaseNotes.cmd b/Generate-ReleaseNotes.cmd index 8bce4728..5bcb8bbe 100644 --- a/Generate-ReleaseNotes.cmd +++ b/Generate-ReleaseNotes.cmd @@ -1,6 +1,6 @@ rem https://github.com/StefH/GitHubReleaseNotes -SET version=1.6.2 +SET version=1.6.3 GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc duplicate example environment --version %version% --token %GH_TOKEN% diff --git a/PackageReleaseNotes.txt b/PackageReleaseNotes.txt index 1e9868e8..62f89117 100644 --- a/PackageReleaseNotes.txt +++ b/PackageReleaseNotes.txt @@ -1,8 +1,5 @@ -# 1.6.2 (04 September 2024) -- #1152 Update MappingConverter to correctly write the Matcher as C# code [bug] -- #1163 Upgrade Aspire to version 8.2.0 [feature] -- #1166 Also update IWireMockMiddlewareOptions when settings are updated via admin interface [bug] -- #1151 MappingsToCSharpCode should use RegexMatcher when specified [bug] -- #1164 WithParam not working. [bug] +# 1.6.3 (07 September 2024) +- #1165 Fix listen on AnyIP for url 0.0.0.0 +- #1154 Listen on all ips [bug] The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md \ No newline at end of file From 7d7f1f8fbbfa56151b81d0c41a79cb4ec22d4847 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Mon, 9 Sep 2024 20:48:09 +0200 Subject: [PATCH 4/9] Allow mapping without Path or Url (#1169) --- .../Server/WireMockServer.Admin.cs | 2 +- .../Server/WireMockServer.ConvertMapping.cs | 27 ++++---------- .../WireMockServer.Admin.cs | 36 ++++++++++++++++++- 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/WireMock.Net/Server/WireMockServer.Admin.cs b/src/WireMock.Net/Server/WireMockServer.Admin.cs index 7ffe78e9..a7cf33ca 100644 --- a/src/WireMock.Net/Server/WireMockServer.Admin.cs +++ b/src/WireMock.Net/Server/WireMockServer.Admin.cs @@ -623,7 +623,7 @@ private IResponseMessage RequestsFind(IRequestMessage requestMessage) { var requestModel = DeserializeObject(requestMessage); - var request = (Request)InitRequestBuilder(requestModel, false)!; + var request = (Request)InitRequestBuilder(requestModel); var dict = new Dictionary(); foreach (var logEntry in LogEntries.Where(le => !le.RequestMessage.Path.StartsWith("/__admin/"))) diff --git a/src/WireMock.Net/Server/WireMockServer.ConvertMapping.cs b/src/WireMock.Net/Server/WireMockServer.ConvertMapping.cs index 10c042dd..c3fa6dff 100644 --- a/src/WireMock.Net/Server/WireMockServer.ConvertMapping.cs +++ b/src/WireMock.Net/Server/WireMockServer.ConvertMapping.cs @@ -36,17 +36,13 @@ private void ConvertMappingsAndRegisterAsRespondProvider(IReadOnlyList().ToArray()); - pathOrUrlMatchersValid = true; } } } @@ -170,7 +163,6 @@ private void ConvertMappingsAndRegisterAsRespondProvider(IReadOnlyList().ToArray()); - pathOrUrlMatchersValid = true; } } } - if (pathOrUrlRequired && !pathOrUrlMatchersValid) - { - _settings.Logger.Error("Path or Url matcher is missing for this mapping, this mapping will not be added."); - return null; - } - if (requestModel.Methods != null) { var matchBehaviour = requestModel.MethodsRejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch; @@ -233,7 +218,7 @@ private void ConvertMappingsAndRegisterAsRespondProvider(IReadOnlyList p is { Matchers: { } })) { - bool ignoreCase = paramModel.IgnoreCase == true; + var ignoreCase = paramModel.IgnoreCase == true; requestBuilder = requestBuilder.WithParam(paramModel.Name, ignoreCase, paramModel.Matchers!.Select(_matcherMapper.Map).OfType().ToArray()); } } @@ -253,7 +238,7 @@ private void ConvertMappingsAndRegisterAsRespondProvider(IReadOnlyList 0) { diff --git a/test/WireMock.Net.Tests/WireMockServer.Admin.cs b/test/WireMock.Net.Tests/WireMockServer.Admin.cs index 2e80e1b9..b1a919ef 100644 --- a/test/WireMock.Net.Tests/WireMockServer.Admin.cs +++ b/test/WireMock.Net.Tests/WireMockServer.Admin.cs @@ -11,9 +11,11 @@ using Moq; using Newtonsoft.Json; using NFluent; -using WireMock.Admin.Settings; +using RestEase; +using WireMock.Client; using WireMock.Handlers; using WireMock.Logging; +using WireMock.Matchers.Request; using WireMock.RequestBuilders; using WireMock.ResponseBuilders; using WireMock.Server; @@ -244,6 +246,38 @@ public void WireMockServer_Admin_ReadStaticMappings_FolderDoesNotExist() loggerMock.Verify(l => l.Info(It.Is(s => s.StartsWith("The Static Mapping folder")), It.IsAny()), Times.Once); } + [Fact] + public async Task WireMockServer_Admin_Mapping_WithoutPathOrUrl() + { + // Arrange + using var server = WireMockServer.StartWithAdminInterface(); + + // Act + server.Given(Request.Create().UsingGet()) + .RespondWith(Response.Create()); + + // Assert + var mapping = server.Mappings.First(m => !m.IsAdminInterface); + var request = (Request) mapping.RequestMatcher; + var pathMatcher = request.GetRequestMessageMatcher(); + pathMatcher.Should().BeNull(); + + var api = RestClient.For(server.Url); + var mappingModels = await api.GetMappingsAsync(); + var mappingModel = mappingModels.First(); + mappingModel.Request.Path.Should().BeNull(); + mappingModel.Request.Url.Should().BeNull(); + + await api.DeleteMappingsAsync(); + + await api.PostMappingAsync(mappingModel); + await api.GetMappingsAsync(); + mappingModels = await api.GetMappingsAsync(); + mappingModel = mappingModels.First(); + mappingModel.Request.Path.Should().BeNull(); + mappingModel.Request.Url.Should().BeNull(); + } + [Fact] public void WireMockServer_Admin_Mappings_WithGuid_Get() { From 527278e60c04ce21a4bb2520ffa06970b3c57cf2 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Tue, 10 Sep 2024 16:14:05 +0200 Subject: [PATCH 5/9] Update the .NET Aspire tests (#1170) * Skip unit tests when Docker is not running in Linux container mode using DockerIsRunningInLinuxContainerModeFact * IgnoreOnContinuousIntegrationFact --- test/WireMock.Net.Aspire.Tests/DockerUtils.cs | 5 +-- ...DockerIsRunningInLinuxContainerModeFact.cs | 16 ++++++++ .../IntegrationTests.cs | 17 ++------- .../IgnoreOnContinuousIntegrationFact.cs | 16 ++++---- .../WireMock.Net.Tests/WireMockServerTests.cs | 38 +++++++++---------- 5 files changed, 45 insertions(+), 47 deletions(-) create mode 100644 test/WireMock.Net.Aspire.Tests/Facts/DockerIsRunningInLinuxContainerModeFact.cs diff --git a/test/WireMock.Net.Aspire.Tests/DockerUtils.cs b/test/WireMock.Net.Aspire.Tests/DockerUtils.cs index fa7b6378..2528dbcd 100644 --- a/test/WireMock.Net.Aspire.Tests/DockerUtils.cs +++ b/test/WireMock.Net.Aspire.Tests/DockerUtils.cs @@ -8,10 +8,7 @@ namespace WireMock.Net.Aspire.Tests; [ExcludeFromCodeCoverage] internal static class DockerUtils { - public static bool IsDockerRunningLinuxContainerMode() - { - return IsDockerRunning() && IsLinuxContainerMode(); - } + public static Lazy IsDockerRunningLinuxContainerMode => new(() => IsDockerRunning() && IsLinuxContainerMode()); private static bool IsDockerRunning() { diff --git a/test/WireMock.Net.Aspire.Tests/Facts/DockerIsRunningInLinuxContainerModeFact.cs b/test/WireMock.Net.Aspire.Tests/Facts/DockerIsRunningInLinuxContainerModeFact.cs new file mode 100644 index 00000000..7be0668d --- /dev/null +++ b/test/WireMock.Net.Aspire.Tests/Facts/DockerIsRunningInLinuxContainerModeFact.cs @@ -0,0 +1,16 @@ +// Copyright © WireMock.Net + +namespace WireMock.Net.Aspire.Tests.Facts; + +public sealed class DockerIsRunningInLinuxContainerModeFact : FactAttribute +{ + private const string SkipReason = "Docker is not running in Linux container mode. Skipping test."; + + public DockerIsRunningInLinuxContainerModeFact() + { + if (!DockerUtils.IsDockerRunningLinuxContainerMode.Value) + { + Skip = SkipReason; + } + } +} \ No newline at end of file diff --git a/test/WireMock.Net.Aspire.Tests/IntegrationTests.cs b/test/WireMock.Net.Aspire.Tests/IntegrationTests.cs index 8f78430b..e51c2d9b 100644 --- a/test/WireMock.Net.Aspire.Tests/IntegrationTests.cs +++ b/test/WireMock.Net.Aspire.Tests/IntegrationTests.cs @@ -3,6 +3,7 @@ using System.Net.Http.Json; using FluentAssertions; using Projects; +using WireMock.Net.Aspire.Tests.Facts; using Xunit.Abstractions; namespace WireMock.Net.Aspire.Tests; @@ -11,15 +12,9 @@ public class IntegrationTests(ITestOutputHelper output) { private record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary); - [Fact] + [DockerIsRunningInLinuxContainerModeFact] public async Task StartAppHostWithWireMockAndCreateHttpClientToCallTheMockedWeatherForecastEndpoint() { - if (!DockerUtils.IsDockerRunningLinuxContainerMode()) - { - output.WriteLine("Docker is not running in Linux container mode. Skipping test."); - return; - } - // Arrange var appHostBuilder = await DistributedApplicationTestingBuilder.CreateAsync(); await using var app = await appHostBuilder.BuildAsync(); @@ -44,15 +39,9 @@ public async Task StartAppHostWithWireMockAndCreateHttpClientToCallTheMockedWeat weatherForecasts2.Should().HaveCount(5); } - [Fact] + [DockerIsRunningInLinuxContainerModeFact] public async Task StartAppHostWithWireMockAndCreateWireMockAdminClientToCallTheAdminEndpoint() { - if (!DockerUtils.IsDockerRunningLinuxContainerMode()) - { - output.WriteLine("Docker is not running in Linux container mode. Skipping test."); - return; - } - // Arrange var appHostBuilder = await DistributedApplicationTestingBuilder.CreateAsync(); await using var app = await appHostBuilder.BuildAsync(); diff --git a/test/WireMock.Net.Tests/Facts/IgnoreOnContinuousIntegrationFact.cs b/test/WireMock.Net.Tests/Facts/IgnoreOnContinuousIntegrationFact.cs index d1254d94..f8f70818 100644 --- a/test/WireMock.Net.Tests/Facts/IgnoreOnContinuousIntegrationFact.cs +++ b/test/WireMock.Net.Tests/Facts/IgnoreOnContinuousIntegrationFact.cs @@ -7,16 +7,16 @@ namespace WireMock.Net.Tests.Facts; public sealed class IgnoreOnContinuousIntegrationFact : FactAttribute { - private static readonly string _skipReason = "Ignore when run via CI/CD"; - private static readonly bool _isContinuousIntegrationAzure = bool.TryParse(Environment.GetEnvironmentVariable("TF_BUILD"), out var isTF) && isTF; - private static readonly bool _isContinuousIntegrationGithub = bool.TryParse(Environment.GetEnvironmentVariable("GITHUB_ACTIONS"), out var isGH) && isGH; - private static bool IsContinuousIntegration() => _isContinuousIntegrationAzure || _isContinuousIntegrationGithub; - + private const string SkipReason = "Ignore when run via CI/CD"; + private static readonly bool IsContinuousIntegrationAzure = bool.TryParse(Environment.GetEnvironmentVariable("TF_BUILD"), out var isTF) && isTF; + private static readonly bool IsContinuousIntegrationGithub = bool.TryParse(Environment.GetEnvironmentVariable("GITHUB_ACTIONS"), out var isGH) && isGH; + private static readonly bool IsContinuousIntegration = IsContinuousIntegrationAzure || IsContinuousIntegrationGithub; + public IgnoreOnContinuousIntegrationFact() { - if (IsContinuousIntegration()) + if (IsContinuousIntegration) { - Skip = _skipReason; + Skip = SkipReason; } } -} +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/WireMockServerTests.cs b/test/WireMock.Net.Tests/WireMockServerTests.cs index dfe24c63..909ff660 100644 --- a/test/WireMock.Net.Tests/WireMockServerTests.cs +++ b/test/WireMock.Net.Tests/WireMockServerTests.cs @@ -40,7 +40,7 @@ public WireMockServerTests(ITestOutputHelper testOutputHelper) { _testOutputHelper = testOutputHelper; } - + [Fact] public void WireMockServer_Start() { @@ -209,7 +209,7 @@ private static string[] GetIPAddressesByFamily(AddressFamily addressFamily) .Select(addr => addr.Address.ToString()) .ToArray(); } - + [IgnoreOnContinuousIntegrationFact] public async Task WireMockServer_WithUrl0000_Should_Listen_On_All_IPs_IPv4() { @@ -218,22 +218,20 @@ public async Task WireMockServer_WithUrl0000_Should_Listen_On_All_IPs_IPv4() var IPv4 = GetIPAddressesByFamily(System.Net.Sockets.AddressFamily.InterNetwork); var settings = new WireMockServerSettings { - Urls = new string[] { "http://0.0.0.0:" + port }, + Urls = ["http://0.0.0.0:" + port], }; - var server = WireMockServer.Start(settings); - + using var server = WireMockServer.Start(settings); + server.Given(Request.Create().WithPath("/*")).RespondWith(Response.Create().WithBody("x")); - - foreach (var addr in IPv4) + + foreach (var address in IPv4) { // Act - var response = await new HttpClient().GetStringAsync("http://" + addr + ":" + server.Ports[0] + "/foo").ConfigureAwait(false); - + var response = await new HttpClient().GetStringAsync("http://" + address + ":" + server.Ports[0] + "/foo").ConfigureAwait(false); + // Assert response.Should().Be("x"); - } - - server.Stop(); + } } [IgnoreOnContinuousIntegrationFact] @@ -244,25 +242,23 @@ public async Task WireMockServer_WithUrl0000_Should_Listen_On_All_IPs_IPv6() var IPv6 = GetIPAddressesByFamily(System.Net.Sockets.AddressFamily.InterNetworkV6); var settings = new WireMockServerSettings { - Urls = new string[] { "http://0.0.0.0:" + port }, + Urls = ["http://0.0.0.0:" + port], }; - var server = WireMockServer.Start(settings); - + using var server = WireMockServer.Start(settings); + server.Given(Request.Create().WithPath("/*")).RespondWith(Response.Create().WithBody("x")); - foreach (var addr in IPv6) + foreach (var address in IPv6) { // Act - var response = await new HttpClient().GetStringAsync("http://[" + addr + "]:" + server.Ports[0] + "/foo").ConfigureAwait(false); - + var response = await new HttpClient().GetStringAsync("http://[" + address + "]:" + server.Ports[0] + "/foo").ConfigureAwait(false); + // Assert response.Should().Be("x"); } - - server.Stop(); } #endif - + [Fact] public async Task WireMockServer_Should_respond_a_redirect_without_body() { From dd80fd7822d1797017c399c3ea46426e1ecdfac4 Mon Sep 17 00:00:00 2001 From: Ruxo <639905+ruxo@users.noreply.github.com> Date: Fri, 20 Sep 2024 18:19:32 +0700 Subject: [PATCH 6/9] Attempt to fix JSON parsing of text/plain content type (#1172) * UseContentType * Fix unit tests * Add a unit test and an integration test for the fix. * Simplify body type checking with GetBodyType extension. * Split IBodyDataExtension, and use imperative style instead of functional style * Remove excessive null forgiving operators * Adjust braces --------- Co-authored-by: Ruxo Zheng --- .../Models/IBodyDataExtension.cs | 20 ++++ .../Http/HttpRequestMessageHelper.cs | 13 ++- .../Owin/Mappers/OwinResponseMapper.cs | 30 +++-- .../Http/HttpRequestMessageHelperTests.cs | 22 +++- .../ResponseWithProxyIntegrationTests.cs | 106 ++++++++++++++++++ 5 files changed, 174 insertions(+), 17 deletions(-) create mode 100644 src/WireMock.Net.Abstractions/Models/IBodyDataExtension.cs create mode 100644 test/WireMock.Net.Tests/ResponseBuilders/ResponseWithProxyIntegrationTests.cs diff --git a/src/WireMock.Net.Abstractions/Models/IBodyDataExtension.cs b/src/WireMock.Net.Abstractions/Models/IBodyDataExtension.cs new file mode 100644 index 00000000..7f90d056 --- /dev/null +++ b/src/WireMock.Net.Abstractions/Models/IBodyDataExtension.cs @@ -0,0 +1,20 @@ +using WireMock.Types; + +// ReSharper disable once CheckNamespace +namespace WireMock.Util; + +public static class IBodyDataExtension +{ + public static BodyType GetBodyType(this IBodyData bodyData) + { + if (bodyData.DetectedBodyTypeFromContentType is not null and not BodyType.None) + { + return bodyData.DetectedBodyTypeFromContentType.Value; + } + if (bodyData.DetectedBodyType is not null and not BodyType.None) + { + return bodyData.DetectedBodyType.Value; + } + return BodyType.None; + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Http/HttpRequestMessageHelper.cs b/src/WireMock.Net/Http/HttpRequestMessageHelper.cs index 23619bef..a43a6528 100644 --- a/src/WireMock.Net/Http/HttpRequestMessageHelper.cs +++ b/src/WireMock.Net/Http/HttpRequestMessageHelper.cs @@ -9,6 +9,7 @@ using Stef.Validation; using WireMock.Constants; using WireMock.Types; +using WireMock.Util; namespace WireMock.Http; @@ -33,12 +34,14 @@ internal static HttpRequestMessage Create(IRequestMessage requestMessage, string MediaTypeHeaderValue.TryParse(value, out contentType); } - httpRequestMessage.Content = requestMessage.BodyData?.DetectedBodyType switch + var bodyData = requestMessage.BodyData; + httpRequestMessage.Content = bodyData?.GetBodyType() switch { - BodyType.Bytes => ByteArrayContentHelper.Create(requestMessage.BodyData.BodyAsBytes!, contentType), - BodyType.Json => StringContentHelper.Create(JsonConvert.SerializeObject(requestMessage.BodyData.BodyAsJson), contentType), - BodyType.String => StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType), - BodyType.FormUrlEncoded => StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType), + BodyType.Bytes => ByteArrayContentHelper.Create(bodyData!.BodyAsBytes!, contentType), + BodyType.Json => StringContentHelper.Create(JsonConvert.SerializeObject(bodyData!.BodyAsJson), contentType), + BodyType.String => StringContentHelper.Create(bodyData!.BodyAsString!, contentType), + BodyType.FormUrlEncoded => StringContentHelper.Create(bodyData!.BodyAsString!, contentType), + _ => httpRequestMessage.Content }; diff --git a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs index 694ab2a1..417b1047 100644 --- a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs +++ b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs @@ -19,6 +19,7 @@ #if !USE_ASPNETCORE using IResponse = Microsoft.Owin.IOwinResponse; +#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously #else using Microsoft.AspNetCore.Http; using IResponse = Microsoft.AspNetCore.Http.HttpResponse; @@ -136,30 +137,37 @@ private bool IsFault(IResponseMessage responseMessage) return responseMessage.FaultPercentage == null || _randomizerDouble.Generate() <= responseMessage.FaultPercentage; } - private async Task GetNormalBodyAsync(IResponseMessage responseMessage) - { - switch (responseMessage.BodyData?.DetectedBodyType) + private async Task GetNormalBodyAsync(IResponseMessage responseMessage) { + var bodyData = responseMessage.BodyData; + switch (bodyData?.GetBodyType()) { case BodyType.String: case BodyType.FormUrlEncoded: - return (responseMessage.BodyData.Encoding ?? _utf8NoBom).GetBytes(responseMessage.BodyData.BodyAsString!); + return (bodyData!.Encoding ?? _utf8NoBom).GetBytes(bodyData.BodyAsString!); case BodyType.Json: - var formatting = responseMessage.BodyData.BodyAsJsonIndented == true ? Formatting.Indented : Formatting.None; - var jsonBody = JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson, new JsonSerializerSettings { Formatting = formatting, NullValueHandling = NullValueHandling.Ignore }); - return (responseMessage.BodyData.Encoding ?? _utf8NoBom).GetBytes(jsonBody); + var formatting = bodyData!.BodyAsJsonIndented == true ? Formatting.Indented : Formatting.None; + var jsonBody = JsonConvert.SerializeObject(bodyData.BodyAsJson, new JsonSerializerSettings { Formatting = formatting, NullValueHandling = NullValueHandling.Ignore }); + return (bodyData.Encoding ?? _utf8NoBom).GetBytes(jsonBody); #if PROTOBUF case BodyType.ProtoBuf: - var protoDefinition = responseMessage.BodyData.ProtoDefinition?.Invoke().Text; - return await ProtoBufUtils.GetProtoBufMessageWithHeaderAsync(protoDefinition, responseMessage.BodyData.ProtoBufMessageType, responseMessage.BodyData.BodyAsJson).ConfigureAwait(false); + var protoDefinition = bodyData!.ProtoDefinition?.Invoke().Text; + return await ProtoBufUtils.GetProtoBufMessageWithHeaderAsync(protoDefinition, bodyData!.ProtoBufMessageType, bodyData!.BodyAsJson).ConfigureAwait(false); #endif case BodyType.Bytes: - return responseMessage.BodyData.BodyAsBytes; + return bodyData!.BodyAsBytes; case BodyType.File: - return _options.FileSystemHandler?.ReadResponseBodyAsFile(responseMessage.BodyData.BodyAsFile!); + return _options.FileSystemHandler?.ReadResponseBodyAsFile(bodyData!.BodyAsFile!); + + case BodyType.MultiPart: + _options.Logger.Warn("MultiPart body type is not handled!"); + break; + + case BodyType.None: + break; } return null; diff --git a/test/WireMock.Net.Tests/Http/HttpRequestMessageHelperTests.cs b/test/WireMock.Net.Tests/Http/HttpRequestMessageHelperTests.cs index b356e40f..edd22b2b 100644 --- a/test/WireMock.Net.Tests/Http/HttpRequestMessageHelperTests.cs +++ b/test/WireMock.Net.Tests/Http/HttpRequestMessageHelperTests.cs @@ -49,6 +49,26 @@ public async Task HttpRequestMessageHelper_Create_Bytes() Check.That(await message.Content.ReadAsByteArrayAsync().ConfigureAwait(false)).ContainsExactly(Encoding.UTF8.GetBytes("hi")); } + [Fact] + public async Task HttpRequestMessageHelper_Create_TextPlain() + { + // Assign + var body = new BodyData + { + BodyAsString = "0123", // or 83 in decimal + BodyAsJson = 83, + DetectedBodyType = BodyType.Json, + DetectedBodyTypeFromContentType = BodyType.String + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", ClientIp, body); + + // Act + var message = HttpRequestMessageHelper.Create(request, "http://url"); + + // Assert + Check.That(await message.Content!.ReadAsStringAsync().ConfigureAwait(false)).Equals("0123"); + } + [Fact] public async Task HttpRequestMessageHelper_Create_Json() { @@ -64,7 +84,7 @@ public async Task HttpRequestMessageHelper_Create_Json() var message = HttpRequestMessageHelper.Create(request, "http://url"); // Assert - Check.That(await message.Content.ReadAsStringAsync().ConfigureAwait(false)).Equals("{\"x\":42}"); + Check.That(await message.Content!.ReadAsStringAsync().ConfigureAwait(false)).Equals("{\"x\":42}"); } [Fact] diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithProxyIntegrationTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithProxyIntegrationTests.cs new file mode 100644 index 00000000..eebac805 --- /dev/null +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithProxyIntegrationTests.cs @@ -0,0 +1,106 @@ +#if NET8_0_OR_GREATER + +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using WireMock.Net.Xunit; +using WireMock.RequestBuilders; +using WireMock.ResponseBuilders; +using WireMock.Server; +using WireMock.Settings; +using Xunit; +using Xunit.Abstractions; + +namespace WireMock.Net.Tests.ResponseBuilders; + +public sealed class ResponseWithProxyIntegrationTests(ITestOutputHelper output) +{ + [Fact] + public async Task Response_UsingTextPlain() + { + // Given + using var server = await TestServer.New().Run(); + var port = server.GetPort(); + output.WriteLine($"Server running on port {port}"); + + var settings = new WireMockServerSettings { + Port = 0, + Logger = new TestOutputHelperWireMockLogger(output) + }; + using var mockServer = WireMockServer.Start(settings); + mockServer.Given(Request.Create().WithPath("/zipcode").UsingPatch()) + .RespondWith(Response.Create().WithProxy($"http://localhost:{port}")); + + using var client = new HttpClient { BaseAddress = new Uri(mockServer.Urls[0]) }; + using var content = new ByteArrayContent(Encoding.UTF8.GetBytes("0123")); + content.Headers.ContentType = new MediaTypeHeaderValue("text/plain"); + + // When + var response = await client.PatchAsync("/zipcode", content); + + // Then + response.StatusCode.Should().Be(HttpStatusCode.OK); + response.Content.Headers.GetValues("Content-Type").Should().BeEquivalentTo("text/plain; charset=utf-8"); + var result = await response.Content.ReadAsStringAsync(); + result.Should().Be("0123"); + } + + sealed class Disposable(Action dispose) : IDisposable + { + public void Dispose() => dispose(); + } + + sealed class TestServer(WebApplication app) : IDisposable + { + Disposable disposable = new(() => { }); + + public static TestServer New() { + var builder = WebApplication.CreateBuilder(); + builder.WebHost.ConfigureKestrel(opts => opts.ListenAnyIP(0)); + + var app = builder.Build(); + + app.MapPatch("/zipcode", async (HttpRequest req) => { + var memory = new MemoryStream(); + await req.Body.CopyToAsync(memory); + var content = Encoding.UTF8.GetString(memory.ToArray()); + return content; + }); + return new(app); + } + + public int GetPort() + => app.Services.GetRequiredService().Features.Get()!.Addresses + .Select(x => new Uri(x).Port) + .First(); + + public async ValueTask Run() { + var started = new TaskCompletionSource(); + var host = app.Services.GetRequiredService(); + host.ApplicationStarted.Register(() => started.SetResult()); + _ = Task.Run(() => app.RunAsync()); + await started.Task; + disposable = new(() => host.StopApplication()); + return this; + } + + public void Dispose() { + disposable.Dispose(); + } + } +} + +#endif \ No newline at end of file From 2cbbef01ae31f74a8db4d3d6330adfc7390f3a4d Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 20 Sep 2024 13:52:45 +0200 Subject: [PATCH 7/9] Refactor some code (IBodyDataExtensions) --- ...ataExtension.cs => IBodyDataExtensions.cs} | 9 +++++-- .../Owin/Mappers/OwinResponseMapper.cs | 18 +++++-------- .../ResponseWithProxyIntegrationTests.cs | 27 +++++++++++-------- 3 files changed, 30 insertions(+), 24 deletions(-) rename src/WireMock.Net.Abstractions/Models/{IBodyDataExtension.cs => IBodyDataExtensions.cs} (78%) diff --git a/src/WireMock.Net.Abstractions/Models/IBodyDataExtension.cs b/src/WireMock.Net.Abstractions/Models/IBodyDataExtensions.cs similarity index 78% rename from src/WireMock.Net.Abstractions/Models/IBodyDataExtension.cs rename to src/WireMock.Net.Abstractions/Models/IBodyDataExtensions.cs index 7f90d056..eabfce47 100644 --- a/src/WireMock.Net.Abstractions/Models/IBodyDataExtension.cs +++ b/src/WireMock.Net.Abstractions/Models/IBodyDataExtensions.cs @@ -1,9 +1,12 @@ -using WireMock.Types; +// Copyright © WireMock.Net + +using WireMock.Types; // ReSharper disable once CheckNamespace namespace WireMock.Util; -public static class IBodyDataExtension +// ReSharper disable once InconsistentNaming +public static class IBodyDataExtensions { public static BodyType GetBodyType(this IBodyData bodyData) { @@ -11,10 +14,12 @@ public static BodyType GetBodyType(this IBodyData bodyData) { return bodyData.DetectedBodyTypeFromContentType.Value; } + if (bodyData.DetectedBodyType is not null and not BodyType.None) { return bodyData.DetectedBodyType.Value; } + return BodyType.None; } } \ No newline at end of file diff --git a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs index 417b1047..03ee5c25 100644 --- a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs +++ b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs @@ -19,7 +19,6 @@ #if !USE_ASPNETCORE using IResponse = Microsoft.Owin.IOwinResponse; -#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously #else using Microsoft.AspNetCore.Http; using IResponse = Microsoft.AspNetCore.Http.HttpResponse; @@ -143,24 +142,24 @@ private bool IsFault(IResponseMessage responseMessage) { case BodyType.String: case BodyType.FormUrlEncoded: - return (bodyData!.Encoding ?? _utf8NoBom).GetBytes(bodyData.BodyAsString!); + return (bodyData.Encoding ?? _utf8NoBom).GetBytes(bodyData.BodyAsString!); case BodyType.Json: - var formatting = bodyData!.BodyAsJsonIndented == true ? Formatting.Indented : Formatting.None; + var formatting = bodyData.BodyAsJsonIndented == true ? Formatting.Indented : Formatting.None; var jsonBody = JsonConvert.SerializeObject(bodyData.BodyAsJson, new JsonSerializerSettings { Formatting = formatting, NullValueHandling = NullValueHandling.Ignore }); return (bodyData.Encoding ?? _utf8NoBom).GetBytes(jsonBody); #if PROTOBUF case BodyType.ProtoBuf: - var protoDefinition = bodyData!.ProtoDefinition?.Invoke().Text; - return await ProtoBufUtils.GetProtoBufMessageWithHeaderAsync(protoDefinition, bodyData!.ProtoBufMessageType, bodyData!.BodyAsJson).ConfigureAwait(false); + var protoDefinition = bodyData.ProtoDefinition?.Invoke().Text; + return await ProtoBufUtils.GetProtoBufMessageWithHeaderAsync(protoDefinition, bodyData.ProtoBufMessageType, bodyData.BodyAsJson).ConfigureAwait(false); #endif case BodyType.Bytes: - return bodyData!.BodyAsBytes; + return bodyData.BodyAsBytes; case BodyType.File: - return _options.FileSystemHandler?.ReadResponseBodyAsFile(bodyData!.BodyAsFile!); + return _options.FileSystemHandler?.ReadResponseBodyAsFile(bodyData.BodyAsFile!); case BodyType.MultiPart: _options.Logger.Warn("MultiPart body type is not handled!"); @@ -179,10 +178,7 @@ private static void SetResponseHeaders(IResponseMessage responseMessage, byte[]? AppendResponseHeader( response, HttpKnownHeaderNames.Date, - new[] - { - DateTime.UtcNow.ToString(CultureInfo.InvariantCulture.DateTimeFormat.RFC1123Pattern, CultureInfo.InvariantCulture) - } + [ DateTime.UtcNow.ToString(CultureInfo.InvariantCulture.DateTimeFormat.RFC1123Pattern, CultureInfo.InvariantCulture) ] ); // Set other headers diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithProxyIntegrationTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithProxyIntegrationTests.cs index eebac805..c46d1da4 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithProxyIntegrationTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithProxyIntegrationTests.cs @@ -1,5 +1,6 @@ -#if NET8_0_OR_GREATER +// Copyright © WireMock.Net +#if NET8_0_OR_GREATER using System; using System.IO; using System.Linq; @@ -36,7 +37,8 @@ public async Task Response_UsingTextPlain() var port = server.GetPort(); output.WriteLine($"Server running on port {port}"); - var settings = new WireMockServerSettings { + var settings = new WireMockServerSettings + { Port = 0, Logger = new TestOutputHelperWireMockLogger(output) }; @@ -45,7 +47,7 @@ public async Task Response_UsingTextPlain() .RespondWith(Response.Create().WithProxy($"http://localhost:{port}")); using var client = new HttpClient { BaseAddress = new Uri(mockServer.Urls[0]) }; - using var content = new ByteArrayContent(Encoding.UTF8.GetBytes("0123")); + using var content = new ByteArrayContent("0123"u8.ToArray()); content.Headers.ContentType = new MediaTypeHeaderValue("text/plain"); // When @@ -65,15 +67,17 @@ sealed class Disposable(Action dispose) : IDisposable sealed class TestServer(WebApplication app) : IDisposable { - Disposable disposable = new(() => { }); + private Disposable _disposable = new(() => { }); - public static TestServer New() { + public static TestServer New() + { var builder = WebApplication.CreateBuilder(); builder.WebHost.ConfigureKestrel(opts => opts.ListenAnyIP(0)); var app = builder.Build(); - app.MapPatch("/zipcode", async (HttpRequest req) => { + app.MapPatch("/zipcode", async (HttpRequest req) => + { var memory = new MemoryStream(); await req.Body.CopyToAsync(memory); var content = Encoding.UTF8.GetString(memory.ToArray()); @@ -87,20 +91,21 @@ public int GetPort() .Select(x => new Uri(x).Port) .First(); - public async ValueTask Run() { + public async ValueTask Run() + { var started = new TaskCompletionSource(); var host = app.Services.GetRequiredService(); host.ApplicationStarted.Register(() => started.SetResult()); _ = Task.Run(() => app.RunAsync()); await started.Task; - disposable = new(() => host.StopApplication()); + _disposable = new(() => host.StopApplication()); return this; } - public void Dispose() { - disposable.Dispose(); + public void Dispose() + { + _disposable.Dispose(); } } } - #endif \ No newline at end of file From c845f73dd0e66d13a0e104fd2161f58652551b6d Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 20 Sep 2024 15:20:25 +0200 Subject: [PATCH 8/9] Unpin Testcontainers version and upgrade to version 3.10.0 (#1177) --- Directory.Build.props | 4 ++-- .../WireMock.Net.Testcontainers.csproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index b653450e..fcd7d4ce 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -44,12 +44,12 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/WireMock.Net.Testcontainers/WireMock.Net.Testcontainers.csproj b/src/WireMock.Net.Testcontainers/WireMock.Net.Testcontainers.csproj index a23b5095..ca55a717 100644 --- a/src/WireMock.Net.Testcontainers/WireMock.Net.Testcontainers.csproj +++ b/src/WireMock.Net.Testcontainers/WireMock.Net.Testcontainers.csproj @@ -28,7 +28,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + From 836976ca19ccbb2b105ffaf3f848809029e7ed0f Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 20 Sep 2024 15:20:38 +0200 Subject: [PATCH 9/9] Upgrade CS-Script to version 4.8.17 (#1178) --- .../WireMock.Net.Matchers.CSharpCode.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WireMock.Net.Matchers.CSharpCode/WireMock.Net.Matchers.CSharpCode.csproj b/src/WireMock.Net.Matchers.CSharpCode/WireMock.Net.Matchers.CSharpCode.csproj index 4cd59a08..2f412e6b 100644 --- a/src/WireMock.Net.Matchers.CSharpCode/WireMock.Net.Matchers.CSharpCode.csproj +++ b/src/WireMock.Net.Matchers.CSharpCode/WireMock.Net.Matchers.CSharpCode.csproj @@ -43,7 +43,7 @@ - + \ No newline at end of file