From d39f7c771f8450aafcce0b8c644ad8fd4d305490 Mon Sep 17 00:00:00 2001 From: Dmytro Nikitin Date: Thu, 6 Aug 2026 19:28:40 +0200 Subject: [PATCH] Fix #1492: Serialize WithClientIP matcher to Request.ClientIP (#1493) --- .../Serialization/MappingConverter.cs | 2 +- .../Server/WireMockServer.ConvertMapping.cs | 3 +- ...ientIPToClientIPModel_NotPath.verified.txt | 29 +++++++++++++ ...hClientIP_ReturnsCorrectModel.verified.txt | 2 +- ...yMismatch_ReturnsCorrectModel.verified.txt | 2 +- ...elRoundTrip_AsClientIPMatcher.verified.txt | 29 +++++++++++++ .../Serialization/MappingConverterTests.cs | 42 +++++++++++++++++++ 7 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_Request_WithClientIP_And_Path_MapsClientIPToClientIPModel_NotPath.verified.txt create mode 100644 test/WireMock.Net.Tests/Serialization/MappingConverterTests.WithClientIP_And_Path_SurvivesMappingModelRoundTrip_AsClientIPMatcher.verified.txt diff --git a/src/WireMock.Net.Minimal/Serialization/MappingConverter.cs b/src/WireMock.Net.Minimal/Serialization/MappingConverter.cs index 2981aff7..c54ecb7b 100644 --- a/src/WireMock.Net.Minimal/Serialization/MappingConverter.cs +++ b/src/WireMock.Net.Minimal/Serialization/MappingConverter.cs @@ -342,7 +342,7 @@ internal class MappingConverter(MatcherMapper mapper) if (clientIPMatcher?.Matchers != null) { var clientIPMatchers = _mapper.Map(clientIPMatcher.Matchers); - mappingModel.Request.Path = new ClientIPModel + mappingModel.Request.ClientIP = new ClientIPModel { Matchers = clientIPMatchers, MatchOperator = clientIPMatchers?.Length > 1 ? clientIPMatcher.MatchOperator.ToString() : null diff --git a/src/WireMock.Net.Minimal/Server/WireMockServer.ConvertMapping.cs b/src/WireMock.Net.Minimal/Server/WireMockServer.ConvertMapping.cs index 02960a63..8a3d0433 100644 --- a/src/WireMock.Net.Minimal/Server/WireMockServer.ConvertMapping.cs +++ b/src/WireMock.Net.Minimal/Server/WireMockServer.ConvertMapping.cs @@ -155,7 +155,8 @@ public partial class WireMockServer var clientIPModel = _settings.DefaultJsonSerializer.ParseJsonToken(requestModel.ClientIP); if (clientIPModel.Matchers != null) { - requestBuilder = requestBuilder.WithPath(clientIPModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray()); + var matchOperator = StringUtils.ParseMatchOperator(clientIPModel.MatchOperator); + requestBuilder = requestBuilder.WithClientIP(matchOperator, clientIPModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray()); } } } diff --git a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_Request_WithClientIP_And_Path_MapsClientIPToClientIPModel_NotPath.verified.txt b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_Request_WithClientIP_And_Path_MapsClientIPToClientIPModel_NotPath.verified.txt new file mode 100644 index 00000000..362be07e --- /dev/null +++ b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_Request_WithClientIP_And_Path_MapsClientIPToClientIPModel_NotPath.verified.txt @@ -0,0 +1,29 @@ +{ + Guid: Guid_1, + UpdatedAt: DateTime_1, + Title: , + Description: , + Priority: 42, + Request: { + ClientIP: { + Matchers: [ + { + Name: WildcardMatcher, + Pattern: 1.2.3.4, + IgnoreCase: false + } + ] + }, + Path: { + Matchers: [ + { + Name: WildcardMatcher, + Pattern: /foo, + IgnoreCase: false + } + ] + } + }, + Response: {}, + UseWebhooksFireAndForget: false +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_Request_WithClientIP_ReturnsCorrectModel.verified.txt b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_Request_WithClientIP_ReturnsCorrectModel.verified.txt index f3b5f431..d4e4f0b5 100644 --- a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_Request_WithClientIP_ReturnsCorrectModel.verified.txt +++ b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_Request_WithClientIP_ReturnsCorrectModel.verified.txt @@ -5,7 +5,7 @@ Description: , Priority: 42, Request: { - Path: { + ClientIP: { Matchers: [ { Name: WildcardMatcher, diff --git a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_Request_WithEarlyMismatch_ReturnsCorrectModel.verified.txt b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_Request_WithEarlyMismatch_ReturnsCorrectModel.verified.txt index b15a7c89..cc010c08 100644 --- a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_Request_WithEarlyMismatch_ReturnsCorrectModel.verified.txt +++ b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_Request_WithEarlyMismatch_ReturnsCorrectModel.verified.txt @@ -5,7 +5,7 @@ Description: , Priority: 42, Request: { - Path: { + ClientIP: { Matchers: [ { Name: WildcardMatcher, diff --git a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.WithClientIP_And_Path_SurvivesMappingModelRoundTrip_AsClientIPMatcher.verified.txt b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.WithClientIP_And_Path_SurvivesMappingModelRoundTrip_AsClientIPMatcher.verified.txt new file mode 100644 index 00000000..27798909 --- /dev/null +++ b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.WithClientIP_And_Path_SurvivesMappingModelRoundTrip_AsClientIPMatcher.verified.txt @@ -0,0 +1,29 @@ +[ + { + Guid: Guid_1, + UpdatedAt: DateTime_1, + Request: { + ClientIP: { + Matchers: [ + { + Name: WildcardMatcher, + Pattern: 1.2.3.4, + IgnoreCase: false + } + ] + }, + Path: { + Matchers: [ + { + Name: WildcardMatcher, + Pattern: /foo, + IgnoreCase: false + } + ] + } + }, + Response: { + StatusCode: 200 + } + } +] \ No newline at end of file diff --git a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs index 0986a637..4242faff 100644 --- a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs +++ b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs @@ -6,6 +6,7 @@ using WireMock.Models; using WireMock.RequestBuilders; using WireMock.ResponseBuilders; using WireMock.Serialization; +using WireMock.Server; using WireMock.Settings; using WireMock.Types; using WireMock.Util; @@ -376,6 +377,47 @@ message HelloReply { return Verify(model); } + [Fact] + public Task ToMappingModel_Request_WithClientIP_And_Path_MapsClientIPToClientIPModel_NotPath() + { + // Arrange: a request that gates on BOTH ClientIP and Path. + var request = Request.Create().WithPath("/foo").WithClientIP("1.2.3.4"); + var response = Response.Create(); + var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, null); + + // Act + var model = _sut.ToMappingModel(mapping); + + // Assert + model.Should().NotBeNull(); + + // Verify + return Verify(model); + } + + [Fact] + public Task WithClientIP_And_Path_SurvivesMappingModelRoundTrip_AsClientIPMatcher() + { + // Arrange: a server with a mapping that gates on BOTH ClientIP and Path. + using var source = WireMockServer.Start(); + source + .Given(Request.Create().WithPath("/foo").WithClientIP("1.2.3.4")) + .RespondWith(Response.Create().WithSuccess()); + + var models = source.MappingModels.ToArray(); + models.Should().ContainSingle(); + + // Act + using var target = WireMockServer.Start(); + target.WithMapping(models); + + // Assert + var request = (Request)target.Mappings.Single(m => !m.IsAdminInterface).RequestMatcher; + + // Verify + return Verify(target.MappingModels); + } + [Fact] public Task ToMappingModel_Request_WithHeader_And_Cookie_ReturnsCorrectModel() {