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:
Степан
2026-05-03 10:27:19 +03:00
committed by GitHub
parent be9864461d
commit f8d3b51fbc
33 changed files with 451 additions and 8 deletions

View File

@@ -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