mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-05-03 14:14:29 +02:00
Feature/early mismatch (#1451)
* feat(request matchers): Add support for early mismatch in mapping processing * test(request matchers): Add unit test for early mismatch functionality * test(grpc): Add test for grpc requests early mismatch and error logging (Issue #1442) * feat(request matchers): RequestMatcherType Add `RequestMatcherType` to request matchers for improved type identification Closes #1442 * refactor(request matchers): Request Replace `EarlyMatcherSelector` with `EarlyMatcherType` for improved clarity and consistency Closes #1442 * feat(request): conversion Add EarlyMatcherType support in request models and mapping conversion Closes #1442 * test(mapping): new tests add unit tests for EarlyMatcherType in mapping conversion and serialization Closes #1442 * refactor(request matchers): RequestMessageEarlyMatcher Replaced inline `EarlyMatcherType` logic with the new `RequestMessageEarlyMatcher` class to support cases when several matchers of the same type are present. For instance - Header, Cookie, Param Closes #1442 * test(request matchers): Early Mismatch add unit tests for early mismatch scenarios with several matchers of same type. Currently, headers and parameters Closes #1442 * refactor(mapping): RequestModel.EarlyMatcherType use fully qualified enum for EarlyMatcherType in serialization Closes #1442 * style(review): fixes - removed unused method - added missing curly brackets Closes #1442
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.Admin.Mappings;
|
||||
|
||||
/// <summary>
|
||||
@@ -61,9 +63,15 @@ public class RequestModel
|
||||
/// Gets or sets the Params.
|
||||
/// </summary>
|
||||
public IList<ParamModel>? Params { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the body.
|
||||
/// </summary>
|
||||
public BodyModel? Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Type of the request matcher to return an immediate mismatch during mapping processing.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public RequestMatcherType? EarlyMatcherType { get; set; }
|
||||
}
|
||||
@@ -7,6 +7,11 @@ namespace WireMock.Matchers.Request;
|
||||
/// </summary>
|
||||
public interface IRequestMatcher
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the request matcher's type.
|
||||
/// </summary>
|
||||
public RequestMatcherType Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified RequestMessage is match.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
namespace WireMock.Matchers.Request;
|
||||
|
||||
/// <summary>
|
||||
/// List of predefined request matcher types.
|
||||
/// </summary>
|
||||
public enum RequestMatcherType
|
||||
{
|
||||
/// <summary>
|
||||
/// RequestMessageBodyMatcher
|
||||
/// </summary>
|
||||
Body = 0,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessageBodyMatcher{T}
|
||||
/// </summary>
|
||||
BodyOfT = 1,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessageClientIPMatcher
|
||||
/// </summary>
|
||||
ClientIP = 2,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessageCookieMatcher
|
||||
/// </summary>
|
||||
Cookie = 3,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessageGraphQLMatcher
|
||||
/// </summary>
|
||||
GraphQL = 4,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessageHeaderMatcher
|
||||
/// </summary>
|
||||
Header = 5,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessageHttpVersionMatcher
|
||||
/// </summary>
|
||||
HttpVersion = 6,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessageMethodMatcher
|
||||
/// </summary>
|
||||
Method = 7,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessageMultiPartMatcher
|
||||
/// </summary>
|
||||
MultiPart = 8,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessageParamMatcher
|
||||
/// </summary>
|
||||
Param = 9,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessagePathMatcher
|
||||
/// </summary>
|
||||
Path = 10,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessageProtoBufMatcher
|
||||
/// </summary>
|
||||
ProtoBuf = 11,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessageScenarioAndStateMatcher
|
||||
/// </summary>
|
||||
ScenarioAndState = 12,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessageUrlMatcher
|
||||
/// </summary>
|
||||
Url = 13,
|
||||
|
||||
/// <summary>
|
||||
/// RequestMessageCompositeMatcher
|
||||
/// </summary>
|
||||
Composite = 14
|
||||
}
|
||||
@@ -142,6 +142,9 @@ public class RequestMessageBodyMatcher : IRequestMatcher
|
||||
MatchOperator = matchOperator;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.Body;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -31,6 +31,9 @@ public class RequestMessageBodyMatcher<T> : IRequestMatcher
|
||||
Func = Guard.NotNull(func);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.BodyOfT;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -74,6 +74,9 @@ public class RequestMessageClientIPMatcher : IRequestMatcher
|
||||
Funcs = Guard.NotNull(funcs);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.ClientIP;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -20,6 +20,11 @@ public abstract class RequestMessageCompositeMatcher : IRequestMatcher
|
||||
/// </value>
|
||||
private IEnumerable<IRequestMatcher> RequestMatchers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Selected type to choose the matcher from <see cref="RequestMatchers"/> which will immediately return a mismatch.
|
||||
/// </summary>
|
||||
internal RequestMatcherType? EarlyMatcherType { get; private protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageCompositeMatcher"/> class.
|
||||
/// </summary>
|
||||
@@ -31,6 +36,9 @@ public abstract class RequestMessageCompositeMatcher : IRequestMatcher
|
||||
_type = type;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.Composite;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
@@ -39,6 +47,13 @@ public abstract class RequestMessageCompositeMatcher : IRequestMatcher
|
||||
return MatchScores.Mismatch;
|
||||
}
|
||||
|
||||
var earlyMatcher = new RequestMessageEarlyMatcher(EarlyMatcherType, RequestMatchers);
|
||||
var earlyMatchResult = earlyMatcher.GetMatchingScore(requestMessage, requestMatchResult);
|
||||
if (!MatchScores.IsPerfect(earlyMatchResult))
|
||||
{
|
||||
return MatchScores.Mismatch;
|
||||
}
|
||||
|
||||
if (_type == CompositeMatcherType.And)
|
||||
{
|
||||
return RequestMatchers.Average(requestMatcher => requestMatcher.GetMatchingScore(requestMessage, requestMatchResult));
|
||||
|
||||
@@ -93,6 +93,9 @@ public class RequestMessageCookieMatcher : IRequestMatcher
|
||||
Name = string.Empty; // Not used when Func, but set to a non-null valid value.
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.Cookie;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
namespace WireMock.Matchers.Request;
|
||||
|
||||
/// <summary>
|
||||
/// Return the mismatch if the matching score of matchers is not perfect.
|
||||
/// </summary>
|
||||
internal sealed class RequestMessageEarlyMatcher(
|
||||
RequestMatcherType? earlyMatcherType,
|
||||
IEnumerable<IRequestMatcher> requestMatchers) : IRequestMatcher
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.Composite;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
if (earlyMatcherType is null)
|
||||
{
|
||||
return MatchScores.Perfect;
|
||||
}
|
||||
|
||||
var earlyMatchers = requestMatchers
|
||||
.Where(m => m.Type == earlyMatcherType)
|
||||
.ToList();
|
||||
|
||||
if (earlyMatchers.Count is 0)
|
||||
{
|
||||
return MatchScores.Perfect;
|
||||
}
|
||||
|
||||
var compositeMatcher = new RequestBuilders.Request(earlyMatchers);
|
||||
return compositeMatcher.GetMatchingScore(requestMessage, requestMatchResult);
|
||||
}
|
||||
}
|
||||
@@ -106,6 +106,9 @@ public class RequestMessageHeaderMatcher : IRequestMatcher
|
||||
Name = string.Empty; // Not used when Func, but set to a non-null valid value.
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.Header;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -65,6 +65,9 @@ public class RequestMessageHttpVersionMatcher : IRequestMatcher
|
||||
MatcherOnStringFunc = Guard.NotNull(func);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.HttpVersion;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -46,6 +46,9 @@ internal class RequestMessageMethodMatcher : IRequestMatcher
|
||||
MatchOperator = matchOperator;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.Method;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -55,6 +55,9 @@ public class RequestMessageMultiPartMatcher : IRequestMatcher
|
||||
MatchOperator = matchOperator;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.MultiPart;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -82,6 +82,9 @@ public class RequestMessageParamMatcher : IRequestMatcher
|
||||
Funcs = Guard.NotNull(funcs);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.Param;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -72,6 +72,9 @@ public class RequestMessagePathMatcher : IRequestMatcher
|
||||
Funcs = Guard.NotNull(funcs);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.Path;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -29,6 +29,9 @@ internal class RequestMessageScenarioAndStateMatcher : IRequestMatcher
|
||||
_executionConditionState = executionConditionState;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.ScenarioAndState;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -72,6 +72,9 @@ public class RequestMessageUrlMatcher : IRequestMatcher
|
||||
Funcs = Guard.NotNull(funcs);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.Url;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,7 @@ public partial class Request : RequestMessageCompositeMatcher, IRequestBuilder
|
||||
/// Initializes a new instance of the <see cref="Request"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requestMatchers">The request matchers.</param>
|
||||
private Request(IList<IRequestMatcher> requestMatchers) : base(requestMatchers)
|
||||
internal Request(IList<IRequestMatcher> requestMatchers) : base(requestMatchers)
|
||||
{
|
||||
_requestMatchers = Guard.NotNull(requestMatchers);
|
||||
}
|
||||
@@ -81,6 +81,13 @@ public partial class Request : RequestMessageCompositeMatcher, IRequestBuilder
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IRequestBuilder WithEarlyMismatch(RequestMatcherType? earlyMatcherType)
|
||||
{
|
||||
EarlyMatcherType = earlyMatcherType;
|
||||
return this;
|
||||
}
|
||||
|
||||
internal bool TryGetProtoBufMatcher([NotNullWhen(true)] out IProtoBufMatcher? protoBufMatcher)
|
||||
{
|
||||
protoBufMatcher = GetRequestMessageMatcher<RequestMessageProtoBufMatcher>()?.Matcher;
|
||||
|
||||
@@ -66,6 +66,12 @@ internal class MappingConverter(MatcherMapper mapper)
|
||||
|
||||
// Request
|
||||
sb.AppendLine(" .Given(Request.Create()");
|
||||
|
||||
if (request.EarlyMatcherType != null)
|
||||
{
|
||||
sb.AppendLine($" .WithEarlyMismatch({request.EarlyMatcherType.Value.GetFullyQualifiedEnumValue()})");
|
||||
}
|
||||
|
||||
sb.AppendLine($" .UsingMethod({To1Or2Or3Arguments(methodMatcher?.MatchBehaviour, methodMatcher?.MatchOperator, methodMatcher?.Methods, HttpRequestMethod.GET)})");
|
||||
|
||||
if (pathMatcher?.Matchers != null)
|
||||
@@ -300,7 +306,9 @@ internal class MappingConverter(MatcherMapper mapper)
|
||||
IgnoreCase = pm.IgnoreCase ? true : null,
|
||||
RejectOnMatch = pm.MatchBehaviour == MatchBehaviour.RejectOnMatch ? true : null,
|
||||
Matchers = _mapper.Map(pm.Matchers)
|
||||
}).ToList() : null
|
||||
}).ToList() : null,
|
||||
|
||||
EarlyMatcherType = request.EarlyMatcherType
|
||||
},
|
||||
Response = new ResponseModel()
|
||||
};
|
||||
|
||||
@@ -268,6 +268,8 @@ public partial class WireMockServer
|
||||
}
|
||||
}
|
||||
|
||||
requestBuilder = requestBuilder.WithEarlyMismatch(requestModel.EarlyMatcherType);
|
||||
|
||||
return requestBuilder;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,9 @@ public class RequestMessageGraphQLMatcher : IRequestMatcher
|
||||
MatchOperator = matchOperator;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.GraphQL;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -30,6 +30,9 @@ public class RequestMessageProtoBufMatcher : IRequestMatcher
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RequestMatcherType Type => RequestMatcherType.ProtoBuf;
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,8 @@ namespace WireMock.RequestBuilders;
|
||||
public interface IRequestBuilder : IClientIPRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a request matcher to the builder.
|
||||
/// Adds a request matcher to the builder.<br/>
|
||||
/// If the request matcher is already present, it will be replaced.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the request matcher.</typeparam>
|
||||
/// <param name="requestMatcher">The request matcher to add.</param>
|
||||
@@ -21,4 +22,11 @@ public interface IRequestBuilder : IClientIPRequestBuilder
|
||||
/// The link back to the Mapping.
|
||||
/// </summary>
|
||||
IMapping Mapping { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Chooses the <see cref="IRequestMatcher"/> which immediately returns a mismatch during mappings enumeration.
|
||||
/// </summary>
|
||||
/// <param name="earlyMatcherType">Selected type to choose the matcher from available list.</param>
|
||||
/// <returns>The current <see cref="IRequestBuilder"/> instance.</returns>
|
||||
IRequestBuilder WithEarlyMismatch(RequestMatcherType? earlyMatcherType);
|
||||
}
|
||||
@@ -8,8 +8,11 @@ using ExampleIntegrationTest.Lookup;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Greet;
|
||||
using Grpc.Net.Client;
|
||||
using Moq;
|
||||
using WireMock.Constants;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Net.Xunit;
|
||||
using WireMock.RequestBuilders;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.Server;
|
||||
@@ -78,7 +81,7 @@ import ""google/protobuf/empty.proto"";
|
||||
|
||||
service Greeter {
|
||||
rpc Nothing (google.protobuf.Empty) returns (google.protobuf.Empty);
|
||||
|
||||
|
||||
rpc SayHello (HelloRequest) returns (HelloReply);
|
||||
|
||||
rpc SayOther (Other) returns (HelloReply);
|
||||
@@ -731,6 +734,93 @@ message Other {
|
||||
Then_ReplyMessage_Should_BeCorrect(reply);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task WireMockServer_WithBodyAsProtoBuf_WithEarlyMismatch_ErrorLogs_Issue1442(
|
||||
bool withEarlyMismatch)
|
||||
{
|
||||
// Arrange
|
||||
var greeterId = $"test-greeter-{Guid.NewGuid()}";
|
||||
var policyId = $"test-policy-{Guid.NewGuid()}";
|
||||
var ct = TestContext.Current.CancellationToken;
|
||||
|
||||
var greeterProtoDefinition = ProtoDefinition;
|
||||
var policyProtoDefinition = File.ReadAllText("./Grpc/policy.proto");
|
||||
|
||||
var mockTestOutputHelper = new Mock<ITestOutputHelper>();
|
||||
using var server = WireMockServer.Start(new WireMockServerSettings
|
||||
{
|
||||
UseHttp2 = true,
|
||||
Logger = new TestOutputHelperWireMockLogger(mockTestOutputHelper.Object)
|
||||
});
|
||||
|
||||
server
|
||||
.AddProtoDefinition(greeterId, greeterProtoDefinition)
|
||||
.Given(Request.Create()
|
||||
.UsingPost()
|
||||
.WithHttpVersion("2")
|
||||
.WithPath("/greet.Greeter/SayHello")
|
||||
.WithEarlyMismatch(withEarlyMismatch
|
||||
? RequestMatcherType.Path
|
||||
: null)
|
||||
.WithBodyAsProtoBuf("greet.HelloRequest", new JsonMatcher(new { name = "stef" })))
|
||||
.WithProtoDefinition(greeterId)
|
||||
.RespondWith(Response.Create()
|
||||
.WithHeader("Content-Type", "application/grpc")
|
||||
.WithTrailingHeader("grpc-status", "0")
|
||||
.WithBodyAsProtoBuf("greet.HelloReply",
|
||||
new
|
||||
{
|
||||
message = "hello {{request.BodyAsJson.name}} {{request.method}}"
|
||||
})
|
||||
.WithTransformer());
|
||||
|
||||
server
|
||||
.AddProtoDefinition(policyId, policyProtoDefinition)
|
||||
.Given(Request.Create()
|
||||
.UsingPost()
|
||||
.WithHttpVersion("2")
|
||||
.WithPath("/Policy.PolicyService/GetVersion")
|
||||
.WithEarlyMismatch(withEarlyMismatch
|
||||
? RequestMatcherType.Path
|
||||
: null)
|
||||
.WithBodyAsProtoBuf("ExampleIntegrationTest.Lookup.GetVersionRequest", new NotNullOrEmptyMatcher()))
|
||||
.WithProtoDefinition(policyId)
|
||||
.RespondWith(Response.Create()
|
||||
.WithHeader("Content-Type", "application/grpc")
|
||||
.WithTrailingHeader("grpc-status", "0")
|
||||
.WithBodyAsProtoBuf("ExampleIntegrationTest.Lookup.GetVersionResponse",
|
||||
new GetVersionResponse
|
||||
{
|
||||
Version = "test",
|
||||
DateHired = new Timestamp
|
||||
{
|
||||
Seconds = 1722301323,
|
||||
Nanos = 12300
|
||||
},
|
||||
Client = new ExampleIntegrationTest.Lookup.Client
|
||||
{
|
||||
ClientName = ExampleIntegrationTest.Lookup.Client.Types.Clients.Test,
|
||||
CorrelationId = "correlation"
|
||||
}
|
||||
})
|
||||
.WithTransformer());
|
||||
|
||||
// Act
|
||||
var channel = GrpcChannel.ForAddress(server.Url!);
|
||||
var policyServiceClient = new PolicyService.PolicyServiceClient(channel);
|
||||
var greeterClient = new Greeter.GreeterClient(channel);
|
||||
|
||||
_ = await policyServiceClient.GetVersionAsync(new GetVersionRequest(), cancellationToken: ct);
|
||||
_ = await greeterClient.SayHelloAsync(new HelloRequest { Name = "stef" }, cancellationToken: ct);
|
||||
|
||||
mockTestOutputHelper.Verify(
|
||||
x => x.WriteLine(
|
||||
It.Is<string>(log => log.Contains("[Error]") && log.Contains("Exception"))),
|
||||
withEarlyMismatch ? Times.Never : Times.AtLeastOnce);
|
||||
}
|
||||
|
||||
private static WireMockServer Given_When_ServerStarted_And_RunningOnHttpAndGrpc()
|
||||
{
|
||||
var settings = new WireMockServerSettings
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using Moq;
|
||||
using WireMock.Constants;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Models;
|
||||
using WireMock.RequestBuilders;
|
||||
|
||||
namespace WireMock.Net.Tests.RequestMatchers;
|
||||
|
||||
@@ -10,8 +13,12 @@ public class RequestMessageCompositeMatcherTests
|
||||
{
|
||||
private class Helper : RequestMessageCompositeMatcher
|
||||
{
|
||||
public Helper(IEnumerable<IRequestMatcher> requestMatchers, CompositeMatcherType type = CompositeMatcherType.And) : base(requestMatchers, type)
|
||||
public Helper(
|
||||
IEnumerable<IRequestMatcher> requestMatchers,
|
||||
CompositeMatcherType type = CompositeMatcherType.And,
|
||||
RequestMatcherType? earlyMatcherType = null) : base(requestMatchers, type)
|
||||
{
|
||||
EarlyMatcherType = earlyMatcherType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,4 +84,74 @@ public class RequestMessageCompositeMatcherTests
|
||||
requestMatcher1Mock.Verify(rm => rm.GetMatchingScore(It.IsAny<RequestMessage>(), It.IsAny<RequestMatchResult>()), Times.Once);
|
||||
requestMatcher2Mock.Verify(rm => rm.GetMatchingScore(It.IsAny<RequestMessage>(), It.IsAny<RequestMatchResult>()), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RequestMessageCompositeMatcher_GetMatchingScore_EarlyMismatch()
|
||||
{
|
||||
// Assign
|
||||
var requestMatcher1Mock = new Mock<IRequestMatcher>();
|
||||
requestMatcher1Mock.Setup(rm => rm.GetMatchingScore(It.IsAny<RequestMessage>(), It.IsAny<RequestMatchResult>())).Returns(1.0d);
|
||||
var requestMatcher2Mock = new Mock<IRequestMatcher>();
|
||||
requestMatcher2Mock.Setup(rm => rm.GetMatchingScore(It.IsAny<RequestMessage>(), It.IsAny<RequestMatchResult>())).Returns(0.8d);
|
||||
var postMatcher = new RequestMessageMethodMatcher(HttpRequestMethod.POST);
|
||||
|
||||
var requestMessage = new RequestMessage(new UrlDetails("http://localhost"), HttpRequestMethod.GET, "127.0.0.1");
|
||||
var matcher = new Helper(
|
||||
[requestMatcher1Mock.Object, requestMatcher2Mock.Object, postMatcher],
|
||||
earlyMatcherType: RequestMatcherType.Method);
|
||||
|
||||
// Act
|
||||
var result = new RequestMatchResult();
|
||||
double score = matcher.GetMatchingScore(requestMessage, result);
|
||||
|
||||
// Assert
|
||||
score.Should().Be(0.0d);
|
||||
|
||||
// Verify
|
||||
requestMatcher1Mock.Verify(rm => rm.GetMatchingScore(It.IsAny<RequestMessage>(), It.IsAny<RequestMatchResult>()), Times.Never);
|
||||
requestMatcher2Mock.Verify(rm => rm.GetMatchingScore(It.IsAny<RequestMessage>(), It.IsAny<RequestMatchResult>()), Times.Never);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RequestMessageCompositeMatcher_GetMatchingScore_SeveralHeadersEarlyMismatch()
|
||||
{
|
||||
// Assign
|
||||
var headers = new Dictionary<string, string[]>
|
||||
{
|
||||
{ "teST", new[] { "x" } },
|
||||
{ "teST2", new[] { "z" } }
|
||||
};
|
||||
var requestMessage = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.1", null, headers);
|
||||
var request = Request.Create()
|
||||
.WithEarlyMismatch(RequestMatcherType.Header)
|
||||
.UsingAnyMethod()
|
||||
.WithHeader("teST", "x")
|
||||
.WithHeader("teST1", ["xx", "yy"])
|
||||
.WithHeader("teST2", ["y", "z"], matchOperator: MatchOperator.And);
|
||||
|
||||
// Act
|
||||
var score = request.GetMatchingScore(requestMessage, new RequestMatchResult());
|
||||
|
||||
// Assert
|
||||
score.Should().Be(0.0d);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RequestMessageCompositeMatcher_GetMatchingScore_SeveralParamEarlyMismatchSuccess()
|
||||
{
|
||||
// Assign
|
||||
var uriWithParams = new Uri("http://localhost?test1=1&test2=2");
|
||||
var requestMessage = new RequestMessage(new UrlDetails(uriWithParams), "GET", "127.0.0.1");
|
||||
var request = Request.Create()
|
||||
.WithEarlyMismatch(RequestMatcherType.Param)
|
||||
.UsingAnyMethod()
|
||||
.WithParam("test1", "1")
|
||||
.WithParam("test2", "2");
|
||||
|
||||
// Act
|
||||
var score = request.GetMatchingScore(requestMessage, new RequestMatchResult());
|
||||
|
||||
// Assert
|
||||
score.Should().Be(1.0d);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Net.Tests.VerifyExtensions;
|
||||
using WireMock.RequestBuilders;
|
||||
using WireMock.ResponseBuilders;
|
||||
@@ -101,6 +102,7 @@ public partial class MappingConverterTests
|
||||
var guid = new Guid("8e7b9ab7-e18e-4502-8bc9-11e6679811cc");
|
||||
var request = Request.Create()
|
||||
.UsingGet()
|
||||
.WithEarlyMismatch(RequestMatcherType.Method)
|
||||
.WithPath("/test_path")
|
||||
.WithParam("q", "42")
|
||||
.WithClientIP("112.123.100.99")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
builder
|
||||
.Given(Request.Create()
|
||||
.WithEarlyMismatch(WireMock.Matchers.Request.RequestMatcherType.Method)
|
||||
.UsingMethod("GET")
|
||||
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/test_path", false, WireMock.Matchers.MatchOperator.Or))
|
||||
.WithParam("q", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "42"))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var builder = new MappingBuilder();
|
||||
builder
|
||||
.Given(Request.Create()
|
||||
.WithEarlyMismatch(WireMock.Matchers.Request.RequestMatcherType.Method)
|
||||
.UsingMethod("GET")
|
||||
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/test_path", false, WireMock.Matchers.MatchOperator.Or))
|
||||
.WithParam("q", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "42"))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
server
|
||||
.Given(Request.Create()
|
||||
.WithEarlyMismatch(WireMock.Matchers.Request.RequestMatcherType.Method)
|
||||
.UsingMethod("GET")
|
||||
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/test_path", false, WireMock.Matchers.MatchOperator.Or))
|
||||
.WithParam("q", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "42"))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var server = WireMockServer.Start();
|
||||
server
|
||||
.Given(Request.Create()
|
||||
.WithEarlyMismatch(WireMock.Matchers.Request.RequestMatcherType.Method)
|
||||
.UsingMethod("GET")
|
||||
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/test_path", false, WireMock.Matchers.MatchOperator.Or))
|
||||
.WithParam("q", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "42"))
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
id:ID!
|
||||
firstName:String
|
||||
lastName:String
|
||||
fullName:String
|
||||
fullName:String
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
Guid: Guid_1,
|
||||
UpdatedAt: DateTime_1,
|
||||
Title: ,
|
||||
Description: ,
|
||||
Priority: 42,
|
||||
Request: {
|
||||
Path: {
|
||||
Matchers: [
|
||||
{
|
||||
Name: WildcardMatcher,
|
||||
Pattern: 1.2.3.4,
|
||||
IgnoreCase: false
|
||||
}
|
||||
]
|
||||
},
|
||||
Headers: [
|
||||
{
|
||||
Name: x1,
|
||||
Matchers: [
|
||||
{
|
||||
Name: WildcardMatcher,
|
||||
Pattern: y,
|
||||
IgnoreCase: true
|
||||
}
|
||||
],
|
||||
IgnoreCase: true
|
||||
}
|
||||
],
|
||||
EarlyMatcherType: ClientIP
|
||||
},
|
||||
Response: {},
|
||||
UseWebhooksFireAndForget: false
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Models;
|
||||
using WireMock.RequestBuilders;
|
||||
using WireMock.ResponseBuilders;
|
||||
@@ -538,7 +539,7 @@ message HelloReply {
|
||||
id:ID!
|
||||
firstName:String
|
||||
lastName:String
|
||||
fullName:String
|
||||
fullName:String
|
||||
}";
|
||||
var request = Request.Create().WithGraphQLSchema(schema);
|
||||
var response = Response.Create();
|
||||
@@ -640,4 +641,25 @@ message HelloReply {
|
||||
// Verify
|
||||
return Verify(model);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task ToMappingModel_Request_WithEarlyMismatch_ReturnsCorrectModel()
|
||||
{
|
||||
// Arrange
|
||||
var request = Request.Create().WithEarlyMismatch(RequestMatcherType.ClientIP)
|
||||
.WithHeader("x1", "y")
|
||||
.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();
|
||||
model.Request.EarlyMatcherType.Should().Be(RequestMatcherType.ClientIP);
|
||||
|
||||
// Verify
|
||||
return Verify(model);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user