Add UseDefinedRequestMatchers to ProxyAndRecordSettings (#821)

* .

* UseDefinedRequestMatchers

* ok

* .

* ClientIP

* t

* fix ut

* .

* cf

* cf2
This commit is contained in:
Stef Heyenrath
2022-09-30 11:25:11 +02:00
committed by GitHub
parent c0b18631a3
commit f7b04f3234
20 changed files with 486 additions and 131 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,31 +1,39 @@
using System.Collections.Generic;
namespace WireMock.Admin.Mappings
namespace WireMock.Admin.Mappings;
/// <summary>
/// Cookie Model
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class CookieModel
{
/// <summary>
/// Cookie Model
/// Gets or sets the name.
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class CookieModel
{
/// <summary>
/// Gets or sets the name.
/// </summary>
public string Name { get; set; } = null!;
public string Name { get; set; } = null!;
/// <summary>
/// Gets or sets the matchers.
/// </summary>
public IList<MatcherModel>? Matchers { get; set; }
/// <summary>
/// Gets or sets the matchers.
/// </summary>
public IList<MatcherModel>? Matchers { get; set; }
/// <summary>
/// Gets or sets the ignore case.
/// </summary>
public bool? IgnoreCase { get; set; }
/// <summary>
/// Gets or sets the ignore case.
/// </summary>
public bool? IgnoreCase { get; set; }
/// <summary>
/// Reject on match.
/// </summary>
public bool? RejectOnMatch { get; set; }
}
/// <summary>
/// Reject on match.
/// </summary>
public bool? RejectOnMatch { get; set; }
/// <summary>
/// The Operator to use when matchers are defined. [Optional]
/// - null = Same as "or".
/// - "or" = Only one pattern should match.
/// - "and" = All patterns should match.
/// - "average" = The average value from all patterns.
/// </summary>
public string? MatchOperator { get; set; }
}

View File

@@ -54,5 +54,14 @@ namespace WireMock.Admin.Settings
/// Prefer the Proxy Mapping over the saved Mapping (in case SaveMapping is set to <c>true</c>).
/// </summary>
// public bool PreferProxyMapping { get; set; }
/// <summary>
/// When SaveMapping is set to <c>true</c>, this setting can be used to control the behavior of the generated request matchers for the new mapping.
/// - <c>false</c>, the default matchers will be used.
/// - <c>true</c>, the defined mappings in the request wil be used for the new mapping.
///
/// Default value is false.
/// </summary>
public bool UseDefinedRequestMatchers { get; set; }
}
}

View File

@@ -1,8 +1,7 @@
using Stef.Validation;
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Stef.Validation;
namespace WireMock.Matchers.Request;
@@ -13,12 +12,13 @@ namespace WireMock.Matchers.Request;
public class RequestMessageCookieMatcher : IRequestMatcher
{
private readonly MatchBehaviour _matchBehaviour;
private readonly bool _ignoreCase;
/// <summary>
/// The functions
/// </summary>
public Func<IDictionary<string, string>, bool>[] Funcs { get; }
public Func<IDictionary<string, string>, bool>[]? Funcs { get; }
/// <summary>
/// The name
@@ -28,7 +28,7 @@ public class RequestMessageCookieMatcher : IRequestMatcher
/// <value>
/// The matchers.
/// </value>
public IStringMatcher[] Matchers { get; }
public IStringMatcher[]? Matchers { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
@@ -37,15 +37,12 @@ public class RequestMessageCookieMatcher : IRequestMatcher
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="matchBehaviour">The match behaviour.</param>
public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, [NotNull] string name, [NotNull] string pattern, bool ignoreCase)
public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, string name, string pattern, bool ignoreCase)
{
Guard.NotNull(name, nameof(name));
Guard.NotNull(pattern, nameof(pattern));
_matchBehaviour = matchBehaviour;
_ignoreCase = ignoreCase;
Name = name;
Matchers = new IStringMatcher[] { new WildcardMatcher(matchBehaviour, pattern, ignoreCase) };
Name = Guard.NotNull(name);
Matchers = new IStringMatcher[] { new WildcardMatcher(matchBehaviour, Guard.NotNull(pattern), ignoreCase) };
}
/// <summary>
@@ -55,10 +52,10 @@ public class RequestMessageCookieMatcher : IRequestMatcher
/// <param name="name">The name.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, [NotNull] string name, bool ignoreCase, [NotNull] params string[] patterns) :
public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, string name, bool ignoreCase, params string[] patterns) :
this(matchBehaviour, name, ignoreCase, patterns.Select(pattern => new WildcardMatcher(matchBehaviour, pattern, ignoreCase)).Cast<IStringMatcher>().ToArray())
{
Guard.NotNull(patterns, nameof(patterns));
Guard.NotNull(patterns);
}
/// <summary>
@@ -68,14 +65,11 @@ public class RequestMessageCookieMatcher : IRequestMatcher
/// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, [NotNull] string name, bool ignoreCase, [NotNull] params IStringMatcher[] matchers)
public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, string name, bool ignoreCase, params IStringMatcher[] matchers)
{
Guard.NotNull(name, nameof(name));
Guard.NotNull(matchers, nameof(matchers));
_matchBehaviour = matchBehaviour;
Name = name;
Matchers = matchers;
Name = Guard.NotNull(name);
Matchers = Guard.NotNull(matchers);
_ignoreCase = ignoreCase;
}
@@ -83,11 +77,12 @@ public class RequestMessageCookieMatcher : IRequestMatcher
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
/// </summary>
/// <param name="funcs">The funcs.</param>
public RequestMessageCookieMatcher([NotNull] params Func<IDictionary<string, string>, bool>[] funcs)
public RequestMessageCookieMatcher(params Func<IDictionary<string, string>, bool>[] funcs)
{
Guard.NotNull(funcs, nameof(funcs));
Guard.NotNull(funcs);
Funcs = funcs;
Name = string.Empty; // Not used when Func, but set to a non-null valid value.
}
/// <inheritdoc />

View File

@@ -11,7 +11,10 @@ namespace WireMock.Matchers.Request;
/// </summary>
public class RequestMessageParamMatcher : IRequestMatcher
{
private readonly MatchBehaviour _matchBehaviour;
/// <summary>
/// MatchBehaviour
/// </summary>
public MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// The funcs
@@ -63,7 +66,7 @@ public class RequestMessageParamMatcher : IRequestMatcher
/// <param name="matchers">The matchers.</param>
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, string key, bool ignoreCase, IStringMatcher[]? matchers)
{
_matchBehaviour = matchBehaviour;
MatchBehaviour = matchBehaviour;
Key = Guard.NotNull(key);
IgnoreCase = ignoreCase;
Matchers = matchers;
@@ -81,7 +84,7 @@ public class RequestMessageParamMatcher : IRequestMatcher
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = MatchBehaviourHelper.Convert(_matchBehaviour, IsMatch(requestMessage));
double score = MatchBehaviourHelper.Convert(MatchBehaviour, IsMatch(requestMessage));
return requestMatchResult.AddScore(GetType(), score);
}

View File

@@ -161,7 +161,6 @@ namespace WireMock.Owin
_options.Logger.Error($"Providing a Response for Mapping '{result.Match?.Mapping?.Guid}' failed. HttpStatusCode set to 500. Exception: {ex}");
response = ResponseMessageBuilder.Create(ex.Message, 500);
}
finally
{
var log = new LogEntry

View File

@@ -1,16 +1,10 @@
using Stef.Validation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Stef.Validation;
using WireMock.Constants;
using WireMock.Http;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Serialization;
using WireMock.Settings;
using WireMock.Types;
using WireMock.Util;
namespace WireMock.Proxy;
@@ -18,13 +12,16 @@ namespace WireMock.Proxy;
internal class ProxyHelper
{
private readonly WireMockServerSettings _settings;
private readonly ProxyMappingConverter _proxyMappingConverter;
public ProxyHelper(WireMockServerSettings settings)
{
_settings = Guard.NotNull(settings);
_proxyMappingConverter = new ProxyMappingConverter(settings, new GuidUtils());
}
public async Task<(IResponseMessage Message, IMapping? Mapping)> SendAsync(
IMapping? mapping,
ProxyAndRecordSettings proxyAndRecordSettings,
HttpClient client,
IRequestMessage requestMessage,
@@ -49,78 +46,13 @@ internal class ProxyHelper
var responseMessage = await HttpResponseMessageHelper.CreateAsync(httpResponseMessage, requiredUri, originalUri, deserializeJson, decompressGzipAndDeflate).ConfigureAwait(false);
IMapping? mapping = null;
IMapping? newMapping = null;
if (HttpStatusRangeParser.IsMatch(proxyAndRecordSettings.SaveMappingForStatusCodePattern, responseMessage.StatusCode) &&
(proxyAndRecordSettings.SaveMapping || proxyAndRecordSettings.SaveMappingToFile))
{
mapping = ToMapping(proxyAndRecordSettings, requestMessage, responseMessage);
newMapping = _proxyMappingConverter.ToMapping(mapping, proxyAndRecordSettings, requestMessage, responseMessage);
}
return (responseMessage, mapping);
}
private IMapping ToMapping(ProxyAndRecordSettings proxyAndRecordSettings, IRequestMessage requestMessage, ResponseMessage responseMessage)
{
var excludedHeaders = proxyAndRecordSettings.ExcludedHeaders ?? new string[] { };
var excludedCookies = proxyAndRecordSettings.ExcludedCookies ?? new string[] { };
var request = Request.Create();
request.WithPath(requestMessage.Path);
request.UsingMethod(requestMessage.Method);
requestMessage.Query?.Loop((key, value) => request.WithParam(key, false, value.ToArray()));
requestMessage.Cookies?.Loop((key, value) =>
{
if (!excludedCookies.Contains(key, StringComparer.OrdinalIgnoreCase))
{
request.WithCookie(key, value);
}
});
var allExcludedHeaders = new List<string>(excludedHeaders) { "Cookie" };
requestMessage.Headers?.Loop((key, value) =>
{
if (!allExcludedHeaders.Contains(key, StringComparer.OrdinalIgnoreCase))
{
request.WithHeader(key, value.ToArray());
}
});
bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
switch (requestMessage.BodyData?.DetectedBodyType)
{
case BodyType.Json:
request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson!, true, throwExceptionWhenMatcherFails));
break;
case BodyType.String:
request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, throwExceptionWhenMatcherFails, MatchOperator.Or, requestMessage.BodyData.BodyAsString));
break;
case BodyType.Bytes:
request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes, throwExceptionWhenMatcherFails));
break;
}
var response = Response.Create(responseMessage);
return new Mapping
(
guid: Guid.NewGuid(),
title: $"Proxy Mapping for {requestMessage.Method} {requestMessage.Path}",
description: string.Empty,
path: null,
settings: _settings,
request,
response,
priority: WireMockConstants.ProxyPriority, // This was 0
scenario: null,
executionConditionState: null,
nextState: null,
stateTimes: null,
webhooks: null,
useWebhooksFireAndForget: null,
timeSettings: null
);
return (responseMessage, newMapping);
}
}

View File

@@ -20,7 +20,7 @@ namespace WireMock.RequestBuilders
/// <inheritdoc cref="IParamsRequestBuilder.WithParam(string, bool, MatchBehaviour)"/>
public IRequestBuilder WithParam(string key, bool ignoreCase, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
Guard.NotNull(key, nameof(key));
Guard.NotNull(key);
_requestMatchers.Add(new RequestMessageParamMatcher(matchBehaviour, key, ignoreCase));
return this;

View File

@@ -271,6 +271,7 @@ public partial class Response : IResponseBuilder
var proxyHelper = new ProxyHelper(settings);
return await proxyHelper.SendAsync(
mapping,
ProxyAndRecordSettings,
_httpClientForProxy,
requestMessage,

View File

@@ -20,7 +20,7 @@ internal class MappingConverter
public MappingConverter(MatcherMapper mapper)
{
_mapper = Guard.NotNull(mapper, nameof(mapper));
_mapper = Guard.NotNull(mapper);
}
public MappingModel ToMappingModel(IMapping mapping)

View File

@@ -0,0 +1,181 @@
using Stef.Validation;
using System;
using System.Collections.Generic;
using System.Linq;
using WireMock.Constants;
using WireMock.Matchers;
using WireMock.Matchers.Request;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Settings;
using WireMock.Types;
using WireMock.Util;
namespace WireMock.Serialization;
internal class ProxyMappingConverter
{
private readonly WireMockServerSettings _settings;
private readonly IGuidUtils _guidUtils;
public ProxyMappingConverter(WireMockServerSettings settings, IGuidUtils guidUtils)
{
_settings = Guard.NotNull(settings);
_guidUtils = Guard.NotNull(guidUtils);
}
public IMapping ToMapping(IMapping? mapping, ProxyAndRecordSettings proxyAndRecordSettings, IRequestMessage requestMessage, ResponseMessage responseMessage)
{
var request = (Request?)mapping?.RequestMatcher;
var clientIPMatcher = request?.GetRequestMessageMatcher<RequestMessageClientIPMatcher>();
var pathMatcher = request?.GetRequestMessageMatcher<RequestMessagePathMatcher>();
var headerMatchers = request?.GetRequestMessageMatchers<RequestMessageHeaderMatcher>();
var cookieMatchers = request?.GetRequestMessageMatchers<RequestMessageCookieMatcher>();
var paramMatchers = request?.GetRequestMessageMatchers<RequestMessageParamMatcher>();
var methodMatcher = request?.GetRequestMessageMatcher<RequestMessageMethodMatcher>();
var bodyMatcher = request?.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
var useDefinedRequestMatchers = proxyAndRecordSettings.UseDefinedRequestMatchers;
var excludedHeaders = new List<string>(proxyAndRecordSettings.ExcludedHeaders ?? new string[] { }) { "Cookie" };
var excludedCookies = proxyAndRecordSettings.ExcludedCookies ?? new string[] { };
var newRequest = Request.Create();
// ClientIP
if (useDefinedRequestMatchers && clientIPMatcher?.Matchers is not null)
{
newRequest.WithClientIP(clientIPMatcher.MatchOperator, clientIPMatcher.Matchers.ToArray());
}
// Path
if (useDefinedRequestMatchers && pathMatcher?.Matchers is not null)
{
newRequest.WithPath(pathMatcher.MatchOperator, pathMatcher.Matchers.ToArray());
}
else
{
newRequest.WithPath(requestMessage.Path);
}
// Method
if (useDefinedRequestMatchers && methodMatcher is not null)
{
newRequest.UsingMethod(methodMatcher.Methods);
}
else
{
newRequest.UsingMethod(requestMessage.Method);
}
// QueryParams
if (useDefinedRequestMatchers && paramMatchers is not null)
{
foreach (var paramMatcher in paramMatchers)
{
newRequest.WithParam(paramMatcher.Key, paramMatcher.MatchBehaviour, paramMatcher.Matchers!.ToArray());
}
}
else
{
requestMessage.Query?.Loop((key, value) => newRequest.WithParam(key, false, value.ToArray()));
}
// Cookies
if (useDefinedRequestMatchers && cookieMatchers is not null)
{
foreach (var cookieMatcher in cookieMatchers.Where(hm => hm.Matchers is not null))
{
if (!excludedCookies.Contains(cookieMatcher.Name, StringComparer.OrdinalIgnoreCase))
{
newRequest.WithCookie(cookieMatcher.Name, cookieMatcher.Matchers!);
}
}
}
else
{
requestMessage.Cookies?.Loop((key, value) =>
{
if (!excludedCookies.Contains(key, StringComparer.OrdinalIgnoreCase))
{
newRequest.WithCookie(key, value);
}
});
}
// Headers
if (useDefinedRequestMatchers && headerMatchers is not null)
{
foreach (var headerMatcher in headerMatchers.Where(hm => hm.Matchers is not null))
{
if (!excludedHeaders.Contains(headerMatcher.Name, StringComparer.OrdinalIgnoreCase))
{
newRequest.WithHeader(headerMatcher.Name, headerMatcher.Matchers!);
}
}
}
else
{
requestMessage.Headers?.Loop((key, value) =>
{
if (!excludedHeaders.Contains(key, StringComparer.OrdinalIgnoreCase))
{
newRequest.WithHeader(key, value.ToArray());
}
});
}
// Body
bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
if (useDefinedRequestMatchers && bodyMatcher?.Matchers is not null)
{
newRequest.WithBody(bodyMatcher.Matchers);
}
else
{
switch (requestMessage.BodyData?.DetectedBodyType)
{
case BodyType.Json:
newRequest.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson!, true, throwExceptionWhenMatcherFails));
break;
case BodyType.String:
newRequest.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, throwExceptionWhenMatcherFails, MatchOperator.Or, requestMessage.BodyData.BodyAsString));
break;
case BodyType.Bytes:
newRequest.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes, throwExceptionWhenMatcherFails));
break;
}
}
// Title
var title = useDefinedRequestMatchers && !string.IsNullOrEmpty(mapping?.Title) ?
mapping!.Title :
$"Proxy Mapping for {requestMessage.Method} {requestMessage.Path}";
// Description
var description = useDefinedRequestMatchers && !string.IsNullOrEmpty(mapping?.Description) ?
mapping!.Description :
$"Proxy Mapping for {requestMessage.Method} {requestMessage.Path}";
return new Mapping
(
guid: _guidUtils.NewGuid(),
title: title,
description: description,
path: null,
settings: _settings,
requestMatcher: newRequest,
provider: Response.Create(responseMessage),
priority: WireMockConstants.ProxyPriority, // This was 0
scenario: null,
executionConditionState: null,
nextState: null,
stateTimes: null,
webhooks: null,
useWebhooksFireAndForget: null,
timeSettings: null
);
}
}

View File

@@ -236,6 +236,7 @@ public partial class WireMockServer
var proxyHelper = new ProxyHelper(settings);
var (responseMessage, mapping) = await proxyHelper.SendAsync(
null,
_settings.ProxyAndRecordSettings!,
_httpClientForProxy!,
requestMessage,

View File

@@ -198,7 +198,7 @@ public partial class WireMockServer
{
foreach (var cookieModel in requestModel.Cookies.Where(c => c.Matchers != null))
{
requestBuilder = requestBuilder.WithCookie(
requestBuilder = requestBuilder.WithCookie(
cookieModel.Name,
cookieModel.IgnoreCase == true,
cookieModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch,

View File

@@ -49,4 +49,13 @@ public class ProxyAndRecordSettings : HttpClientSettings
/// </summary>
//[PublicAPI]
//public bool PreferProxyMapping { get; set; }
/// <summary>
/// When SaveMapping is set to <c>true</c>, this setting can be used to control the behavior of the generated request matchers for the new mapping.
/// - <c>false</c>, the default matchers will be used.
/// - <c>true</c>, the defined mappings in the request wil be used for the new mapping.
///
/// Default value is false.
/// </summary>
public bool UseDefinedRequestMatchers { get; set; }
}

View File

@@ -92,6 +92,7 @@ public static class WireMockServerSettingsParser
SaveMapping = parser.GetBoolValue("SaveMapping"),
SaveMappingForStatusCodePattern = parser.GetStringValue("SaveMappingForStatusCodePattern", "*"),
SaveMappingToFile = parser.GetBoolValue("SaveMappingToFile"),
UseDefinedRequestMatchers = parser.GetBoolValue(nameof(ProxyAndRecordSettings.UseDefinedRequestMatchers)),
Url = proxyUrl!
};

View File

@@ -0,0 +1,16 @@
using System;
namespace WireMock.Util;
internal interface IGuidUtils
{
Guid NewGuid();
}
internal class GuidUtils : IGuidUtils
{
public Guid NewGuid()
{
return Guid.NewGuid();
}
}

View File

@@ -0,0 +1,70 @@
using System;
using Moq;
using Newtonsoft.Json;
using System.IO;
using FluentAssertions;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.Serialization;
using WireMock.Settings;
using WireMock.Util;
using Xunit;
namespace WireMock.Net.Tests.Serialization;
public class ProxyMappingConverterTests
{
private readonly WireMockServerSettings _settings = new();
private readonly MappingConverter _mappingConverter;
private readonly ProxyMappingConverter _sut;
public ProxyMappingConverterTests()
{
var guidUtilsMock = new Mock<IGuidUtils>();
guidUtilsMock.Setup(g => g.NewGuid()).Returns(Guid.Parse("ff55ac0a-fea9-4d7b-be74-5e483a2c1305"));
_mappingConverter = new MappingConverter(new MatcherMapper(_settings));
_sut = new ProxyMappingConverter(_settings, guidUtilsMock.Object);
}
[Fact]
public void ToMapping_UseDefinedRequestMatchers_True()
{
// Arrange
var proxyAndRecordSettings = new ProxyAndRecordSettings
{
UseDefinedRequestMatchers = true
};
var request = Request.Create()
.UsingPost()
.WithPath("x")
.WithParam("p1", "p1-v")
.WithParam("p2", "p2-v")
.WithHeader("Content-Type", new ContentTypeMatcher("text/plain"))
.WithCookie("c", "x")
.WithBody(new RegexMatcher("<RequestType>Auth</RequestType"));
var mappingMock = new Mock<IMapping>();
mappingMock.SetupGet(m => m.RequestMatcher).Returns(request);
mappingMock.SetupGet(m => m.Title).Returns("my title");
mappingMock.SetupGet(m => m.Description).Returns("my description");
var requestMessageMock = new Mock<IRequestMessage>();
var responseMessage = new ResponseMessage();
// Act
var proxyMapping = _sut.ToMapping(mappingMock.Object, proxyAndRecordSettings, requestMessageMock.Object, responseMessage);
// Assert
var model = _mappingConverter.ToMappingModel(proxyMapping);
var json = JsonConvert.SerializeObject(model, JsonSerializationConstants.JsonSerializerSettingsDefault);
var expected = File.ReadAllText(Path.Combine("../../../", "Serialization", "files", "proxy.json"));
json.Should().Be(expected);
}
}

View File

@@ -0,0 +1,72 @@
{
"Guid": "ff55ac0a-fea9-4d7b-be74-5e483a2c1305",
"Title": "my title",
"Description": "my description",
"Priority": -2000000,
"Request": {
"Path": {
"Matchers": [
{
"Name": "WildcardMatcher",
"Pattern": "x",
"IgnoreCase": false
}
]
},
"Methods": [
"POST"
],
"Headers": [
{
"Name": "Content-Type",
"Matchers": [
{
"Name": "ContentTypeMatcher",
"Pattern": "text/plain",
"IgnoreCase": false
}
]
}
],
"Cookies": [
{
"Name": "c",
"Matchers": [
{
"Name": "WildcardMatcher",
"Pattern": "x",
"IgnoreCase": true
}
]
}
],
"Params": [
{
"Name": "p1",
"Matchers": [
{
"Name": "ExactMatcher",
"Pattern": "p1-v"
}
]
},
{
"Name": "p2",
"Matchers": [
{
"Name": "ExactMatcher",
"Pattern": "p2-v"
}
]
}
],
"Body": {
"Matcher": {
"Name": "RegexMatcher",
"Pattern": "<RequestType>Auth</RequestType",
"IgnoreCase": false
}
}
},
"Response": {}
}

View File

@@ -85,6 +85,9 @@
<None Update="responsebody.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Serialization\files\proxy.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings.org\*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
@@ -105,6 +108,7 @@
<ItemGroup>
<Folder Include="Pact\files\" />
<Folder Include="Serialization\files\" />
</ItemGroup>
</Project>

View File

@@ -1,3 +1,6 @@
using FluentAssertions;
using Moq;
using NFluent;
using System;
using System.Linq;
using System.Net;
@@ -5,11 +8,9 @@ using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using FluentAssertions;
using Moq;
using NFluent;
using WireMock.Admin.Mappings;
using WireMock.Constants;
using WireMock.Handlers;
using WireMock.Matchers;
using WireMock.Matchers.Request;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
@@ -119,6 +120,61 @@ public class WireMockServerProxyTests
server.Mappings.Should().HaveCount(28);
}
[Fact]
public async Task WireMockServer_Proxy_With_SaveMappingToFile_Is_True_ShouldSaveMappingToFile()
{
// Assign
string path = $"/prx_{Guid.NewGuid()}";
var title = "IndexFile";
var description = "IndexFile_Test";
var stringBody = "<pretendXml>value</pretendXml>";
var serverForProxyForwarding = WireMockServer.Start();
var fileSystemHandlerMock = new Mock<IFileSystemHandler>();
fileSystemHandlerMock.Setup(f => f.GetMappingFolder()).Returns("m");
var settings = new WireMockServerSettings
{
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = serverForProxyForwarding.Urls[0],
SaveMapping = false,
SaveMappingToFile = true
},
FileSystemHandler = fileSystemHandlerMock.Object
};
var server = WireMockServer.Start(settings);
server.Given(Request.Create()
.WithPath("/*")
.WithBody(new RegexMatcher(stringBody)))
.WithTitle(title)
.WithDescription(description)
.AtPriority(WireMockConstants.ProxyPriority)
.RespondWith(Response.Create().WithProxy(new ProxyAndRecordSettings
{
Url = serverForProxyForwarding.Urls[0],
SaveMapping = false,
SaveMappingToFile = true,
UseDefinedRequestMatchers = true,
}));
// Act
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri($"{server.Urls[0]}{path}"),
Content = new StringContent(stringBody)
};
var httpClientHandler = new HttpClientHandler { AllowAutoRedirect = false };
await new HttpClient(httpClientHandler).SendAsync(requestMessage).ConfigureAwait(false);
// Assert
server.Mappings.Should().HaveCount(2);
// Verify
fileSystemHandlerMock.Verify(f => f.WriteMappingFile($"m{System.IO.Path.DirectorySeparatorChar}{title}.json", It.IsRegex(stringBody)), Times.Once);
}
[Fact]
public async Task WireMockServer_Proxy_With_SaveMapping_Is_False_And_SaveMappingToFile_Is_True_ShouldSaveMappingToFile()
{
@@ -735,8 +791,6 @@ public class WireMockServerProxyTests
content.Should().NotBeEmpty();
server.LogEntries.Should().HaveCount(1);
var status = ((StatusModel)server.LogEntries.First().ResponseMessage.BodyData.BodyAsJson).Status;
server.Stop();
}
}