Add Grpc ProtoBuf support (request-response) (#1047)

* ProtoBuf

* .

* x

* ---

* x

* fx

* ...

* sc

* ...

* .

* groen

* x

* fix tests

* ok!?

* fix tests

* fix tests

* !

* x

* 6

* .

* x

* ivaluematcher

* transformer

* .

* sc

* .

* mapping

* x

* tra

* com

* ...

* .

* .

* .

* AddProtoDefinition

* .

* set

* grpahj

* .

* .

* IdOrText

* ...

* async

* async2

* .

* t

* nuget

* <PackageReference Include="ProtoBufJsonConverter" Version="0.2.0-preview-04" />

* http version

* tests

* .WithHttpVersion("2")

* <PackageReference Include="ProtoBufJsonConverter" Version="0.2.0" />

* HttpVersionParser
This commit is contained in:
Stef Heyenrath
2024-02-16 17:16:51 +01:00
committed by GitHub
parent 801546fae7
commit 6ac95cf57d
129 changed files with 4585 additions and 1556 deletions

View File

@@ -0,0 +1,128 @@
#if !(NET452 || NET461 || NETCOREAPP3_1)
using System.Threading.Tasks;
using RestEase;
using VerifyXunit;
using WireMock.Client;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using Xunit;
namespace WireMock.Net.Tests.AdminApi;
public partial class WireMockAdminApiTests
{
private const string ProtoDefinition = @"
syntax = ""proto3"";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
";
[Fact]
public async Task IWireMockAdminApi_GetMappingsAsync_WithBodyAsProtoBuf_ShouldReturnCorrectMappingModels()
{
// Arrange
using var server = WireMockServer.StartWithAdminInterface();
var protoBufJsonMatcher = new JsonPartialWildcardMatcher(new { name = "*" });
server
.Given(Request.Create()
.UsingPost()
.WithPath("/grpc/greet.Greeter/SayHello")
.WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloRequest", protoBufJsonMatcher)
)
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc")
.WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloReply",
new
{
message = "hello {{request.BodyAsJson.name}}"
}
)
.WithTrailingHeader("grpc-status", "0")
.WithTransformer()
);
server
.Given(Request.Create()
.UsingPost()
.WithPath("/grpc2/greet.Greeter/SayHello")
.WithBodyAsProtoBuf("greet.HelloRequest", protoBufJsonMatcher)
)
.WithProtoDefinition(ProtoDefinition)
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc")
.WithBodyAsProtoBuf("greet.HelloReply",
new
{
message = "hello {{request.BodyAsJson.name}}"
}
)
.WithTrailingHeader("grpc-status", "0")
.WithTransformer()
);
server
.AddProtoDefinition("my-greeter", ProtoDefinition)
.Given(Request.Create()
.UsingPost()
.WithPath("/grpc3/greet.Greeter/SayHello")
.WithBodyAsProtoBuf("greet.HelloRequest", protoBufJsonMatcher)
)
.WithProtoDefinition("my-greeter")
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc")
.WithBodyAsProtoBuf("greet.HelloReply",
new
{
message = "hello {{request.BodyAsJson.name}}"
}
)
.WithTrailingHeader("grpc-status", "0")
.WithTransformer()
);
server
.AddProtoDefinition("my-greeter", ProtoDefinition)
.Given(Request.Create()
.UsingPost()
.WithPath("/grpc4/greet.Greeter/SayHello")
.WithBodyAsProtoBuf("greet.HelloRequest")
)
.WithProtoDefinition("my-greeter")
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc")
.WithBodyAsProtoBuf("greet.HelloReply",
new
{
message = "hello {{request.BodyAsJson.name}}"
}
)
.WithTrailingHeader("grpc-status", "0")
.WithTransformer()
);
// Act
var api = RestClient.For<IWireMockAdminApi>(server.Url);
var getMappingsResult = await api.GetMappingsAsync().ConfigureAwait(false);
await Verifier.Verify(getMappingsResult, VerifySettings);
server.Stop();
}
}
#endif

View File

@@ -0,0 +1,235 @@
[
{
Guid: Guid_1,
UpdatedAt: DateTime_1,
Request: {
Path: {
Matchers: [
{
Name: WildcardMatcher,
Pattern: /grpc/greet.Greeter/SayHello,
IgnoreCase: false
}
]
},
Methods: [
POST
],
Body: {
Matcher: {
Name: ProtoBufMatcher,
Pattern:
syntax = "proto3";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
,
ContentMatcher: {
Name: JsonPartialWildcardMatcher,
Pattern: {
name: *
},
IgnoreCase: false,
Regex: false
},
ProtoBufMessageType: greet.HelloRequest
}
}
},
Response: {
BodyAsJson: {
message: hello {{request.BodyAsJson.name}}
},
UseTransformer: true,
TransformerType: Handlebars,
TransformerReplaceNodeOptions: EvaluateAndTryToConvert,
Headers: {
Content-Type: application/grpc
},
TrailingHeaders: {
grpc-status: 0
},
ProtoDefinition:
syntax = "proto3";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
,
ProtoBufMessageType: greet.HelloReply
}
},
{
Guid: Guid_2,
UpdatedAt: DateTime_2,
Request: {
Path: {
Matchers: [
{
Name: WildcardMatcher,
Pattern: /grpc2/greet.Greeter/SayHello,
IgnoreCase: false
}
]
},
Methods: [
POST
],
Body: {
Matcher: {
Name: ProtoBufMatcher,
ContentMatcher: {
Name: JsonPartialWildcardMatcher,
Pattern: {
name: *
},
IgnoreCase: false,
Regex: false
},
ProtoBufMessageType: greet.HelloRequest
}
}
},
Response: {
BodyAsJson: {
message: hello {{request.BodyAsJson.name}}
},
UseTransformer: true,
TransformerType: Handlebars,
TransformerReplaceNodeOptions: EvaluateAndTryToConvert,
Headers: {
Content-Type: application/grpc
},
TrailingHeaders: {
grpc-status: 0
},
ProtoBufMessageType: greet.HelloReply
},
ProtoDefinition:
syntax = "proto3";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
},
{
Guid: Guid_3,
UpdatedAt: DateTime_3,
Request: {
Path: {
Matchers: [
{
Name: WildcardMatcher,
Pattern: /grpc3/greet.Greeter/SayHello,
IgnoreCase: false
}
]
},
Methods: [
POST
],
Body: {
Matcher: {
Name: ProtoBufMatcher,
ContentMatcher: {
Name: JsonPartialWildcardMatcher,
Pattern: {
name: *
},
IgnoreCase: false,
Regex: false
},
ProtoBufMessageType: greet.HelloRequest
}
}
},
Response: {
BodyAsJson: {
message: hello {{request.BodyAsJson.name}}
},
UseTransformer: true,
TransformerType: Handlebars,
TransformerReplaceNodeOptions: EvaluateAndTryToConvert,
Headers: {
Content-Type: application/grpc
},
TrailingHeaders: {
grpc-status: 0
},
ProtoBufMessageType: greet.HelloReply
},
ProtoDefinition: my-greeter
},
{
Guid: Guid_4,
UpdatedAt: DateTime_4,
Request: {
Path: {
Matchers: [
{
Name: WildcardMatcher,
Pattern: /grpc4/greet.Greeter/SayHello,
IgnoreCase: false
}
]
},
Methods: [
POST
],
Body: {
Matcher: {
Name: ProtoBufMatcher,
ProtoBufMessageType: greet.HelloRequest
}
}
},
Response: {
BodyAsJson: {
message: hello {{request.BodyAsJson.name}}
},
UseTransformer: true,
TransformerType: Handlebars,
TransformerReplaceNodeOptions: EvaluateAndTryToConvert,
Headers: {
Content-Type: application/grpc
},
TrailingHeaders: {
grpc-status: 0
},
ProtoBufMessageType: greet.HelloReply
},
ProtoDefinition: my-greeter
}
]

View File

@@ -0,0 +1,205 @@
#if PROTOBUF
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using FluentAssertions;
using Greet;
using Grpc.Net.Client;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using Xunit;
// ReSharper disable once CheckNamespace
namespace WireMock.Net.Tests;
public partial class WireMockServerTests
{
private const string ProtoDefinition = @"
syntax = ""proto3"";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
";
[Theory]
[InlineData("CgRzdGVm")]
[InlineData("AAAAAAYKBHN0ZWY=")]
public async Task WireMockServer_WithBodyAsProtoBuf(string data)
{
// Arrange
var bytes = Convert.FromBase64String(data);
var jsonMatcher = new JsonMatcher(new { name = "stef" });
using var server = WireMockServer.Start();
server
.Given(Request.Create()
.UsingPost()
.WithPath("/grpc/greet.Greeter/SayHello")
.WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloRequest", jsonMatcher)
)
.RespondWith(Response.Create()
.WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloReply",
new
{
message = "hello"
}
)
.WithTrailingHeader("grpc-status", "0")
);
// Act
var protoBuf = new ByteArrayContent(bytes);
protoBuf.Headers.ContentType = new MediaTypeHeaderValue("application/grpc-web");
var client = server.CreateClient();
var response = await client.PostAsync("/grpc/greet.Greeter/SayHello", protoBuf);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
var responseBytes = await response.Content.ReadAsByteArrayAsync();
Convert.ToBase64String(responseBytes).Should().Be("AAAAAAcKBWhlbGxv");
server.Stop();
}
[Fact]
public async Task WireMockServer_WithBodyAsProtoBuf_InlineProtoDefinition_UsingGrpcGeneratedClient()
{
// Arrange
using var server = WireMockServer.Start(useHttp2: true);
var jsonMatcher = new JsonMatcher(new { name = "stef" });
server
.Given(Request.Create()
.UsingPost()
.WithPath("/greet.Greeter/SayHello")
.WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloRequest", jsonMatcher)
)
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc")
.WithTrailingHeader("grpc-status", "0")
.WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloReply",
new
{
message = "hello stef {{request.method}}"
}
)
.WithTransformer()
);
// Act
var channel = GrpcChannel.ForAddress(server.Url!);
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest { Name = "stef" });
// Assert
reply.Message.Should().Be("hello stef POST");
server.Stop();
}
[Fact]
public async Task WireMockServer_WithBodyAsProtoBuf_MappingProtoDefinition_UsingGrpcGeneratedClient()
{
// Arrange
using var server = WireMockServer.Start(useHttp2: true);
var jsonMatcher = new JsonMatcher(new { name = "stef" });
server
.Given(Request.Create()
.UsingPost()
.WithHttpVersion("2")
.WithPath("/greet.Greeter/SayHello")
.WithBodyAsProtoBuf("greet.HelloRequest", jsonMatcher)
)
.WithProtoDefinition(ProtoDefinition)
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc")
.WithTrailingHeader("grpc-status", "0")
.WithBodyAsProtoBuf("greet.HelloReply",
new
{
message = "hello {{request.BodyAsJson.name}} {{request.method}}"
}
)
.WithTransformer()
);
// Act
var channel = GrpcChannel.ForAddress(server.Url!);
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest { Name = "stef" });
// Assert
reply.Message.Should().Be("hello stef POST");
server.Stop();
}
[Fact]
public async Task WireMockServer_WithBodyAsProtoBuf_ServerProtoDefinition_UsingGrpcGeneratedClient()
{
// Arrange
var id = $"test-{Guid.NewGuid()}";
using var server = WireMockServer.Start(useHttp2: true);
var jsonMatcher = new JsonMatcher(new { name = "stef" });
server
.AddProtoDefinition(id, ProtoDefinition)
.Given(Request.Create()
.UsingPost()
.WithHttpVersion("2")
.WithPath("/greet.Greeter/SayHello")
.WithBodyAsProtoBuf("greet.HelloRequest", jsonMatcher)
)
.WithProtoDefinition(id)
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc")
.WithTrailingHeader("grpc-status", "0")
.WithBodyAsProtoBuf("greet.HelloReply",
new
{
message = "hello {{request.BodyAsJson.name}} {{request.method}}"
}
)
.WithTransformer()
);
// Act
var channel = GrpcChannel.ForAddress(server.Url!);
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest { Name = "stef" });
// Assert
reply.Message.Should().Be("hello stef POST");
server.Stop();
}
}
#endif

View File

@@ -0,0 +1,33 @@
// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package greet;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply);
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}

View File

@@ -1,7 +1,6 @@
#if GRAPHQL
using System;
using System.Collections.Generic;
using CSScripting;
using FluentAssertions;
using GraphQLParser.Exceptions;
using WireMock.Exceptions;

View File

@@ -0,0 +1,108 @@
#if PROTOBUF
using System;
using System.Threading.Tasks;
using FluentAssertions;
using ProtoBuf;
using WireMock.Matchers;
using WireMock.Models;
using Xunit;
namespace WireMock.Net.Tests.Matchers;
public class ProtoBufMatcherTests
{
private const string MessageType = "greet.HelloRequest";
private readonly IdOrText _protoDefinition = new(null, @"
syntax = ""proto3"";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
");
[Fact]
public async Task ProtoBufMatcher_For_ValidProtoBuf_And_ValidMethod_DecodeAsync()
{
// Arrange
var bytes = Convert.FromBase64String("CgRzdGVm");
// Act
var matcher = new ProtoBufMatcher(() => _protoDefinition, MessageType);
var result = await matcher.DecodeAsync(bytes).ConfigureAwait(false);
// Assert
result.Should().BeEquivalentTo(new { name = "stef" });
}
[Fact]
public async Task ProtoBufMatcher_For_ValidProtoBuf_And_ValidMethod_NoJsonMatchers_IsMatchAsync()
{
// Arrange
var bytes = Convert.FromBase64String("CgRzdGVm");
// Act
var matcher = new ProtoBufMatcher(() => _protoDefinition, MessageType);
var result = await matcher.IsMatchAsync(bytes).ConfigureAwait(false);
// Assert
result.Score.Should().Be(MatchScores.Perfect);
result.Exception.Should().BeNull();
}
[Fact]
public async Task ProtoBufMatcher_For_ValidProtoBuf_And_ValidMethod_Using_JsonMatcher_IsMatchAsync()
{
// Arrange
var jsonMatcher = new JsonMatcher(new { name = "stef" });
var bytes = Convert.FromBase64String("CgRzdGVm");
// Act
var matcher = new ProtoBufMatcher(() => _protoDefinition, MessageType, matcher: jsonMatcher);
var result = await matcher.IsMatchAsync(bytes);
// Assert
result.Score.Should().Be(MatchScores.Perfect);
result.Exception.Should().BeNull();
}
[Fact]
public async Task ProtoBufMatcher_For_InvalidProtoBuf_IsNoMatch()
{
// Arrange
var bytes = new byte[] { 1, 2, 3 };
// Act
var matcher = new ProtoBufMatcher(() => _protoDefinition, MessageType);
var result = await matcher.IsMatchAsync(bytes);
// Assert
result.Score.Should().Be(MatchScores.Mismatch);
result.Exception.Should().BeOfType<ProtoException>();
}
[Fact]
public async Task ProtoBufMatcher_For_InvalidMethod_IsNoMatchAsync()
{
// Arrange
var bytes = Convert.FromBase64String("CgRzdGVm");
// Act
var matcher = new ProtoBufMatcher(() => _protoDefinition, "greet.Greeter.X");
var result = await matcher.IsMatchAsync(bytes);
// Assert
result.Score.Should().Be(MatchScores.Mismatch);
result.Exception.Should().BeOfType<ArgumentException>();
}
}
#endif

View File

@@ -28,7 +28,7 @@ namespace WireMock.Net.Tests.Owin
_responseMapperMock = new Mock<IOwinResponseMapper>();
_responseMapperMock.SetupAllProperties();
_responseMapperMock.Setup(m => m.MapAsync(It.IsAny<ResponseMessage>(), It.IsAny<IResponse>())).Returns(Task.FromResult(true));
_responseMapperMock.Setup(m => m.MapAsync(It.IsAny<ResponseMessage?>(), It.IsAny<IResponse>())).Returns(Task.FromResult(true));
_sut = new GlobalExceptionMiddleware(null, _optionsMock.Object, _responseMapperMock.Object);
}

View File

@@ -202,7 +202,7 @@ namespace WireMock.Net.Tests.Owin.Mappers
public async Task OwinResponseMapper_MapAsync_BodyAsJson()
{
// Arrange
var json = new { t = "x", i = (string)null };
var json = new { t = "x", i = (string?)null };
var responseMessage = new ResponseMessage
{
Headers = new Dictionary<string, WireMockList<string>>(),

View File

@@ -70,7 +70,7 @@ public class WireMockMiddlewareTests
_responseMapperMock = new Mock<IOwinResponseMapper>();
_responseMapperMock.SetupAllProperties();
_responseMapperMock.Setup(m => m.MapAsync(It.IsAny<ResponseMessage>(), It.IsAny<IResponse>())).Returns(Task.FromResult(true));
_responseMapperMock.Setup(m => m.MapAsync(It.IsAny<ResponseMessage?>(), It.IsAny<IResponse>())).Returns(Task.FromResult(true));
_matcherMock = new Mock<IMappingMatcher>();
_matcherMock.SetupAllProperties();
@@ -216,7 +216,7 @@ public class WireMockMiddlewareTests
_mappingMock.SetupGet(m => m.Provider).Returns(responseBuilder);
_mappingMock.SetupGet(m => m.Settings).Returns(settings);
var newMappingFromProxy = new Mapping(NewGuid, UpdatedAt, string.Empty, string.Empty, null, settings, Request.Create(), Response.Create(), 0, null, null, null, null, null, false, null, null, null);
var newMappingFromProxy = new Mapping(NewGuid, UpdatedAt, string.Empty, string.Empty, null, settings, Request.Create(), Response.Create(), 0, null, null, null, null, null, false, null, null);
_mappingMock.Setup(m => m.ProvideResponseAsync(It.IsAny<RequestMessage>())).ReturnsAsync((new ResponseMessage(), newMappingFromProxy));
var requestBuilder = Request.Create().UsingAnyMethod();
@@ -270,7 +270,7 @@ public class WireMockMiddlewareTests
_mappingMock.SetupGet(m => m.Provider).Returns(responseBuilder);
_mappingMock.SetupGet(m => m.Settings).Returns(settings);
var newMappingFromProxy = new Mapping(NewGuid, UpdatedAt, "my-title", "my-description", null, settings, Request.Create(), Response.Create(), 0, null, null, null, null, null, false, null, data: null, probability: null);
var newMappingFromProxy = new Mapping(NewGuid, UpdatedAt, "my-title", "my-description", null, settings, Request.Create(), Response.Create(), 0, null, null, null, null, null, false, null, data: null);
_mappingMock.Setup(m => m.ProvideResponseAsync(It.IsAny<RequestMessage>())).ReturnsAsync((new ResponseMessage(), newMappingFromProxy));
var requestBuilder = Request.Create().UsingAnyMethod();

View File

@@ -0,0 +1,65 @@
#if PROTOBUF
using System.Collections.Generic;
using FluentAssertions;
using WireMock.Matchers;
using WireMock.Matchers.Request;
using WireMock.RequestBuilders;
using Xunit;
namespace WireMock.Net.Tests.RequestBuilders;
public class RequestBuilderWithProtoBufTests
{
private const string MessageType = "greet.HelloRequest";
private const string TestProtoDefinition = @"
syntax = ""proto3"";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
";
[Fact]
public void RequestBuilder_WithGrpcProto_Without_JsonMatcher()
{
// Act
var requestBuilder = (Request)Request.Create().WithBodyAsProtoBuf(TestProtoDefinition, MessageType);
// Assert
var matchers = requestBuilder.GetPrivateFieldValue<IList<IRequestMatcher>>("_requestMatchers");
matchers.Should().HaveCount(1);
var protoBufMatcher = (ProtoBufMatcher)((RequestMessageProtoBufMatcher)matchers[0]).Matcher!;
protoBufMatcher.ProtoDefinition().Text.Should().Be(TestProtoDefinition);
protoBufMatcher.MessageType.Should().Be(MessageType);
protoBufMatcher.Matcher.Should().BeNull();
}
[Fact]
public void RequestBuilder_WithGrpcProto_With_JsonMatcher()
{
// Act
var jsonMatcher = new JsonMatcher(new { name = "stef" });
var requestBuilder = (Request)Request.Create().WithBodyAsProtoBuf(TestProtoDefinition, MessageType, jsonMatcher);
// Assert
var matchers = requestBuilder.GetPrivateFieldValue<IList<IRequestMatcher>>("_requestMatchers");
matchers.Should().HaveCount(1);
var protoBufMatcher = (ProtoBufMatcher)((RequestMessageProtoBufMatcher)matchers[0]).Matcher!;
protoBufMatcher.ProtoDefinition().Text.Should().Be(TestProtoDefinition);
protoBufMatcher.MessageType.Should().Be(MessageType);
protoBufMatcher.Matcher.Should().BeOfType<JsonMatcher>();
}
}
#endif

View File

@@ -6,6 +6,7 @@
Url: http://localhost/,
AbsoluteUrl: http://localhost/,
Method: post,
HttpVersion: 1.1,
BodyAsBytes: AA==,
DetectedBodyType: Bytes
},

View File

@@ -5,7 +5,8 @@
AbsolutePath: /,
Url: http://localhost/,
AbsoluteUrl: http://localhost/,
Method: get
Method: get,
HttpVersion: 1.1
},
Response: {
BodyAsFile: test,

View File

@@ -6,6 +6,7 @@
Url: http://localhost/,
AbsoluteUrl: http://localhost/,
Method: post,
HttpVersion: 1.1,
BodyAsBytes: AA==,
DetectedBodyType: Bytes
},

View File

@@ -5,7 +5,8 @@
AbsolutePath: /,
Url: http://localhost/,
AbsoluteUrl: http://localhost/,
Method: get
Method: get,
HttpVersion: 1.1
},
Response: {
BodyAsFile: test,

View File

@@ -102,7 +102,7 @@ public partial class MappingConverterTests
return Verifier.Verify(code, VerifySettings);
}
private Mapping CreateMapping()
private IMapping CreateMapping()
{
var guid = new Guid("8e7b9ab7-e18e-4502-8bc9-11e6679811cc");
var request = Request.Create()
@@ -119,7 +119,8 @@ public partial class MappingConverterTests
.WithDelay(12345)
.WithTransformer();
return new Mapping(
return new Mapping
(
guid,
_updatedAt,
string.Empty,
@@ -136,9 +137,8 @@ public partial class MappingConverterTests
null,
false,
null,
data: null,
probability: 0.3
);
data: null
).WithProbability(0.3);
}
}
#endif

View File

@@ -0,0 +1,61 @@
{
Guid: Guid_1,
UpdatedAt: DateTime_1,
Title: ,
Description: ,
Priority: 41,
Request: {
Path: {
Matchers: [
{
Name: WildcardMatcher,
Pattern: /grpc/greet.Greeter/SayHello,
IgnoreCase: false
}
]
},
Methods: [
POST
],
Body: {
Matcher: {
Name: ProtoBufMatcher,
ContentMatcher: {
Name: JsonMatcher,
Pattern: {
name: stef
},
IgnoreCase: false
},
ProtoBufMessageType: greet.HelloRequest
}
}
},
Response: {
BodyAsJson: {
message: hello
},
TrailingHeaders: {
grpc-status: 0
},
ProtoBufMessageType: greet.HelloReply
},
UseWebhooksFireAndForget: false,
ProtoDefinition:
syntax = "proto3";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
}

View File

@@ -0,0 +1,53 @@
{
Guid: Guid_1,
UpdatedAt: DateTime_1,
Title: ,
Description: ,
Priority: 41,
Request: {
Path: {
Matchers: [
{
Name: WildcardMatcher,
Pattern: /grpc/greet.Greeter/SayHello,
IgnoreCase: false
}
]
},
Methods: [
POST
],
Body: {
Matcher: {
Name: ProtoBufMatcher,
Pattern:
syntax = "proto3";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
,
ContentMatcher: {
Name: JsonMatcher,
Pattern: {
name: stef
},
IgnoreCase: false
},
ProtoBufMessageType: greet.HelloRequest
}
}
},
Response: {},
UseWebhooksFireAndForget: false
}

View File

@@ -0,0 +1,35 @@
{
Guid: Guid_1,
UpdatedAt: DateTime_1,
Title: ,
Description: ,
Priority: 43,
Request: {},
Response: {
BodyAsJson: {
message: hello
},
TrailingHeaders: {
grpc-status: 0
},
ProtoDefinition:
syntax = "proto3";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
,
ProtoBufMessageType: greet.HelloReply
},
UseWebhooksFireAndForget: false
}

View File

@@ -0,0 +1,14 @@
{
Guid: Guid_1,
UpdatedAt: DateTime_1,
Request: {},
Response: {
Headers: {
w[]: [
x,
y
]
}
},
UseWebhooksFireAndForget: false
}

View File

@@ -0,0 +1,14 @@
{
Guid: Guid_1,
UpdatedAt: DateTime_1,
Request: {},
Response: {
Headers: {
w[]: [
x,
y
]
}
},
UseWebhooksFireAndForget: false
}

View File

@@ -0,0 +1,15 @@
{
Guid: Guid_1,
UpdatedAt: DateTime_1,
Request: {},
Response: {
TrailingHeaders: {
x1: y,
x2: [
y,
z
]
}
},
UseWebhooksFireAndForget: false
}

View File

@@ -0,0 +1,14 @@
{
Guid: Guid_1,
UpdatedAt: DateTime_1,
Request: {},
Response: {
TrailingHeaders: {
w[]: [
x,
y
]
}
},
UseWebhooksFireAndForget: false
}

View File

@@ -22,6 +22,23 @@ public partial class MappingConverterTests
private readonly Guid _guid = new("c8eeaf99-d5c4-4341-8543-4597c3fd40d9");
private readonly DateTime _updatedAt = new(2022, 12, 4, 11, 12, 13);
private readonly WireMockServerSettings _settings = new();
private const string ProtoDefinition = @"
syntax = ""proto3"";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
";
private readonly MappingConverter _sut;
@@ -58,7 +75,7 @@ public partial class MappingConverterTests
}
}
};
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 0, null, null, null, null, webhooks, false, null, data: null, probability: null);
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 0, null, null, null, null, webhooks, false, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
@@ -131,7 +148,7 @@ public partial class MappingConverterTests
}
}
};
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 0, null, null, null, null, webhooks, true, null, data: null, probability: null);
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 0, null, null, null, null, webhooks, true, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
@@ -169,7 +186,7 @@ public partial class MappingConverterTests
var description = "my-description";
var request = Request.Create();
var response = Response.Create();
var mapping = new Mapping(_guid, _updatedAt, title, description, null, _settings, request, response, 0, null, null, null, null, null, false, null, data: null, probability: null);
var mapping = new Mapping(_guid, _updatedAt, title, description, null, _settings, request, response, 0, null, null, null, null, null, false, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
@@ -189,7 +206,7 @@ public partial class MappingConverterTests
// Assign
var request = Request.Create();
var response = Response.Create().WithBodyAsJson(new { x = "x" }).WithTransformer();
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, data: null, probability: null);
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
@@ -218,7 +235,7 @@ public partial class MappingConverterTests
End = end,
TTL = ttl
};
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, timeSettings, data: null, probability: null);
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, timeSettings, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
@@ -249,7 +266,7 @@ public partial class MappingConverterTests
{
var request = Request.Create();
var response = Response.Create().WithDelay(test.Delay);
var mapping = new Mapping(Guid.NewGuid(), _updatedAt, string.Empty, string.Empty, string.Empty, _settings, request, response, 42, null, null, null, null, null, false, null, data: null, probability: null);
var mapping = new Mapping(Guid.NewGuid(), _updatedAt, string.Empty, string.Empty, string.Empty, _settings, request, response, 42, null, null, null, null, null, false, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
@@ -267,7 +284,7 @@ public partial class MappingConverterTests
var delay = 1000;
var request = Request.Create();
var response = Response.Create().WithDelay(delay);
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, data: null, probability: null);
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
@@ -287,7 +304,7 @@ public partial class MappingConverterTests
int minimumDelay = 1000;
var request = Request.Create();
var response = Response.Create().WithRandomDelay(minimumDelay);
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, data: null, probability: null);
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
@@ -310,7 +327,7 @@ public partial class MappingConverterTests
int maximumDelay = 2000;
var request = Request.Create();
var response = Response.Create().WithRandomDelay(minimumDelay, maximumDelay);
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, data: null, probability: null);
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
@@ -332,7 +349,8 @@ public partial class MappingConverterTests
double probability = 0.4;
var request = Request.Create();
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, data: null, probability: probability);
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, data: null)
.WithProbability(probability);
// Act
var model = _sut.ToMappingModel(mapping);
@@ -351,7 +369,7 @@ public partial class MappingConverterTests
// Arrange
var request = Request.Create().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, null);
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);
@@ -364,7 +382,7 @@ public partial class MappingConverterTests
}
[Fact]
public Task ToMappingModel_WithHeader_And_Cookie_ReturnsCorrectModel()
public Task ToMappingModel_Request_WithHeader_And_Cookie_ReturnsCorrectModel()
{
// Assign
var request = Request.Create()
@@ -380,8 +398,10 @@ public partial class MappingConverterTests
.WithCookie("IgnoreCase_true", "cv-4")
.WithCookie("ExactMatcher", new ExactMatcher("c-exact"))
;
var response = Response.Create();
var mapping = new Mapping(_guid, _updatedAt, null, null, null, _settings, request, response, 0, null, null, null, null, null, false, null, data: null, probability: null);
var mapping = new Mapping(_guid, _updatedAt, null, null, null, _settings, request, response, 0, null, null, null, null, null, false, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
@@ -393,6 +413,98 @@ public partial class MappingConverterTests
return Verifier.Verify(model);
}
[Fact]
public Task ToMappingModel_Response_WithHeader_ReturnsCorrectModel()
{
// Assign
var request = Request.Create();
var response = Response.Create()
.WithHeader("x1", "y")
.WithHeader("x2", "y", "z")
.WithHeaders(new Dictionary<string, string> { { "d", "test" } })
.WithHeaders(new Dictionary<string, string[]> { { "d[]", new[] { "v1", "v2" } } })
.WithHeaders(new Dictionary<string, WireMockList<string>> { { "w", new WireMockList<string>("x") } })
.WithHeaders(new Dictionary<string, WireMockList<string>> { { "w[]", new WireMockList<string>("x", "y") } });
var mapping = new Mapping(_guid, _updatedAt, null, null, null, _settings, request, response, 0, null, null, null, null, null, false, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
// Assert
model.Should().NotBeNull();
// Verify
return Verifier.Verify(model);
}
[Fact]
public Task ToMappingModel_Response_WithHeaders_ReturnsCorrectModel()
{
// Assign
var request = Request.Create();
var response = Response.Create()
.WithHeaders(new Dictionary<string, WireMockList<string>> { { "w[]", new WireMockList<string>("x", "y") } });
var mapping = new Mapping(_guid, _updatedAt, null, null, null, _settings, request, response, 0, null, null, null, null, null, false, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
// Assert
model.Should().NotBeNull();
// Verify
return Verifier.Verify(model);
}
#if TRAILINGHEADERS
[Fact]
public Task ToMappingModel_Response_WithTrailingHeader_ReturnsCorrectModel()
{
// Assign
var request = Request.Create();
var response = Response.Create()
.WithTrailingHeader("x1", "y")
.WithTrailingHeader("x2", "y", "z");
var mapping = new Mapping(_guid, _updatedAt, null, null, null, _settings, request, response, 0, null, null, null, null, null, false, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
// Assert
model.Should().NotBeNull();
// Verify
return Verifier.Verify(model);
}
[Fact]
public Task ToMappingModel_Response_WithTrailingHeaders_ReturnsCorrectModel()
{
// Assign
var request = Request.Create();
var response = Response.Create()
.WithTrailingHeaders(new Dictionary<string, WireMockList<string>> { { "w[]", new WireMockList<string>("x", "y") } });
var mapping = new Mapping(_guid, _updatedAt, null, null, null, _settings, request, response, 0, null, null, null, null, null, false, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
// Assert
model.Should().NotBeNull();
// Verify
return Verifier.Verify(model);
}
#endif
[Fact]
public Task ToMappingModel_WithParam_ReturnsCorrectModel()
{
@@ -405,7 +517,7 @@ public partial class MappingConverterTests
.WithParam("ExactMatcher", new ExactMatcher("exact"))
;
var response = Response.Create();
var mapping = new Mapping(_guid, _updatedAt, null, null, null, _settings, request, response, 0, null, null, null, null, null, false, null, data: null, probability: null);
var mapping = new Mapping(_guid, _updatedAt, null, null, null, _settings, request, response, 0, null, null, null, null, null, false, null, data: null);
// Act
var model = _sut.ToMappingModel(mapping);
@@ -422,7 +534,7 @@ public partial class MappingConverterTests
public Task ToMappingModel_Request_WithBodyAsGraphQLSchema_ReturnsCorrectModel()
{
// Arrange
var schema = @"
const string schema = @"
type Query {
greeting:String
students:[Student]
@@ -437,7 +549,96 @@ public partial class MappingConverterTests
}";
var request = Request.Create().WithBodyAsGraphQLSchema(schema);
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, null);
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 Verifier.Verify(model);
}
#endif
#if PROTOBUF
[Fact]
public Task ToMappingModel_Request_WithBodyAsProtoBuf_ReturnsCorrectModel()
{
// Arrange
var jsonMatcher = new JsonMatcher(new { name = "stef" });
var request = Request.Create()
.UsingPost()
.WithPath("/grpc/greet.Greeter/SayHello")
.WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloRequest", jsonMatcher);
var response = Response.Create();
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 41, null, null, null, null, null, false, null, null);
// Act
var model = _sut.ToMappingModel(mapping);
// Assert
model.Should().NotBeNull();
// Verify
return Verifier.Verify(model);
}
[Fact]
public Task ToMappingModel_Response_WithBodyAsProtoBuf_ReturnsCorrectModel()
{
// Arrange
var protobufResponse = new
{
message = "hello"
};
var request = Request.Create();
var response = Response.Create()
.WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloReply", protobufResponse)
.WithTrailingHeader("grpc-status", "0");
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 43, null, null, null, null, null, false, null, null);
// Act
var model = _sut.ToMappingModel(mapping);
// Assert
model.Should().NotBeNull();
// Verify
return Verifier.Verify(model);
}
[Fact]
public Task ToMappingModel_Mapping_WithBodyAsProtoBuf_ReturnsCorrectModel()
{
// Arrange
var jsonMatcher = new JsonMatcher(new { name = "stef" });
var protobufResponse = new
{
message = "hello"
};
var request = Request.Create()
.UsingPost()
.WithPath("/grpc/greet.Greeter/SayHello")
.WithBodyAsProtoBuf("greet.HelloRequest", jsonMatcher);
var response = Response.Create()
.WithBodyAsProtoBuf("greet.HelloReply", protobufResponse)
.WithTrailingHeader("grpc-status", "0");
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 41, null, null, null, null, null, false, null, null)
.WithProtoDefinition(new (null, ProtoDefinition));
((Request)request).Mapping = mapping;
((Response)response).Mapping = mapping;
// Act
var model = _sut.ToMappingModel(mapping);

View File

@@ -27,7 +27,7 @@ public class MatcherMapperTests
}
[Fact]
public void MatcherMapper_Map_IMatcher_Null()
public void MatcherMapper_Map_Matcher_IMatcher_Null()
{
// Act
var model = _sut.Map((IMatcher?)null);
@@ -37,7 +37,7 @@ public class MatcherMapperTests
}
[Fact]
public void MatcherMapper_Map_IMatchers_Null()
public void MatcherMapper_Map_Matcher_IMatchers_Null()
{
// Act
var model = _sut.Map((IMatcher[]?)null);
@@ -47,7 +47,7 @@ public class MatcherMapperTests
}
[Fact]
public void MatcherMapper_Map_IMatchers()
public void MatcherMapper_Map_Matcher_IMatchers()
{
// Assign
var matcherMock1 = new Mock<IStringMatcher>();
@@ -62,7 +62,7 @@ public class MatcherMapperTests
#if MIMEKIT
[Fact]
public void MatcherMapper_Map_MimePartMatcher()
public void MatcherMapper_Map_Matcher_MimePartMatcher()
{
// Arrange
var bytes = Convert.FromBase64String("c3RlZg==");
@@ -95,7 +95,7 @@ public class MatcherMapperTests
#endif
[Fact]
public void MatcherMapper_Map_IStringMatcher()
public void MatcherMapper_Map_Matcher_IStringMatcher()
{
// Assign
var matcherMock = new Mock<IStringMatcher>();
@@ -115,7 +115,7 @@ public class MatcherMapperTests
}
[Fact]
public void MatcherMapper_Map_IStringMatcher_With_PatternAsFile()
public void MatcherMapper_Map_Matcher_IStringMatcher_With_PatternAsFile()
{
// Arrange
var pattern = new StringPattern { Pattern = "p", PatternAsFile = "pf" };
@@ -136,7 +136,7 @@ public class MatcherMapperTests
}
[Fact]
public void MatcherMapper_Map_IIgnoreCaseMatcher()
public void MatcherMapper_Map_Matcher_IIgnoreCaseMatcher()
{
// Assign
var matcherMock = new Mock<IIgnoreCaseMatcher>();
@@ -150,7 +150,7 @@ public class MatcherMapperTests
}
[Fact]
public void MatcherMapper_Map_XPathMatcher()
public void MatcherMapper_Map_Matcher_XPathMatcher()
{
// Assign
var xmlNamespaceMap = new[]
@@ -171,7 +171,7 @@ public class MatcherMapperTests
#if GRAPHQL
[Fact]
public void MatcherMapper_Map_GraphQLMatcher()
public void MatcherMapper_Map_Matcher_GraphQLMatcher()
{
// Assign
const string testSchema = @"
@@ -199,6 +199,87 @@ public class MatcherMapperTests
}
#endif
#if PROTOBUF
[Fact]
public void MatcherMapper_Map_Matcher_ProtoBufMatcher()
{
// Arrange
IdOrText protoDefinition = new(null, @"
syntax = ""proto3"";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
");
const string messageType = "greet.HelloRequest";
var jsonPattern = new { name = "stef" };
var jsonMatcher = new JsonMatcher(jsonPattern);
var matcher = new ProtoBufMatcher(() => protoDefinition, messageType, matcher: jsonMatcher);
// Act
var model = _sut.Map(matcher)!;
// Assert
model.Name.Should().Be(nameof(ProtoBufMatcher));
model.Pattern.Should().Be(protoDefinition.Text);
model.ProtoBufMessageType.Should().Be(messageType);
model.ContentMatcher?.Name.Should().Be("JsonMatcher");
model.ContentMatcher?.Pattern.Should().Be(jsonPattern);
}
[Fact]
public void MatcherMapper_Map_Matcher_ProtoBufMatcher_WithId()
{
// Arrange
string id = "abc123";
IdOrText protoDefinition = new(id, @"
syntax = ""proto3"";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
");
const string messageType = "greet.HelloRequest";
var jsonPattern = new { name = "stef" };
var jsonMatcher = new JsonMatcher(jsonPattern);
var matcher = new ProtoBufMatcher(() => protoDefinition, messageType, matcher: jsonMatcher);
// Act
var model = _sut.Map(matcher)!;
// Assert
model.Name.Should().Be(nameof(ProtoBufMatcher));
model.Pattern.Should().Be(id);
model.ProtoBufMessageType.Should().Be(messageType);
model.ContentMatcher?.Name.Should().Be("JsonMatcher");
model.ContentMatcher?.Pattern.Should().Be(jsonPattern);
}
#endif
[Fact]
public void MatcherMapper_Map_MatcherModel_Null()
{
@@ -736,7 +817,7 @@ public class MatcherMapperTests
var matcher = (ExactObjectMatcher)_sut.Map(model)!;
// Assert
Check.That(matcher.ValueAsBytes).ContainsExactly(new byte[] { 115, 116, 101, 102 });
Check.That((byte[])matcher.Value).ContainsExactly(new byte[] { 115, 116, 101, 102 });
}
[Fact]
@@ -1001,4 +1082,53 @@ public class MatcherMapperTests
matcher.CustomScalars.Should().BeEquivalentTo(customScalars);
}
#endif
#if PROTOBUF
[Fact]
public void MatcherMapper_Map_MatcherModel_ProtoBufMatcher()
{
// Arrange
const string protoDefinition = @"
syntax = ""proto3"";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
";
const string messageType = "greet.HelloRequest";
var jsonMatcherPattern = new { name = "stef" };
var model = new MatcherModel
{
Name = nameof(ProtoBufMatcher),
Pattern = protoDefinition,
ProtoBufMessageType = messageType,
ContentMatcher = new MatcherModel
{
Name = nameof(JsonMatcher),
Pattern = jsonMatcherPattern
}
};
// Act
var matcher = (ProtoBufMatcher)_sut.Map(model)!;
// Assert
matcher.ProtoDefinition().Text.Should().Be(protoDefinition);
matcher.Name.Should().Be(nameof(ProtoBufMatcher));
matcher.MessageType.Should().Be(messageType);
matcher.Matcher?.Value.Should().Be(jsonMatcherPattern);
}
#endif
}

View File

@@ -174,4 +174,22 @@ public class SimpleSettingsParserTests
Check.That(value3).IsEqualTo(100);
Check.That(value4).IsNull();
}
[Fact]
public void SimpleCommandLineParser_Parse_GetObjectValueFromJson()
{
// Assign
_parser.Parse(new[] { @"--json {""k1"":""v1"",""k2"":""v2""}" });
// Act
var value = _parser.GetObjectValueFromJson<Dictionary<string, string>>("json");
// Assert
var expected = new Dictionary<string, string>
{
{ "k1", "v1" },
{ "k2", "v2" }
};
value.Should().BeEquivalentTo(expected);
}
}

View File

@@ -0,0 +1,39 @@
using System.Diagnostics.CodeAnalysis;
using FluentAssertions;
using WireMock.Util;
using Xunit;
namespace WireMock.Net.Tests.Util;
[ExcludeFromCodeCoverage]
public class HttpVersionParserTests
{
[Theory]
[InlineData("HTTP/1.1", "1.1")]
[InlineData("HTTP/2", "2")]
[InlineData("http/1.0", "1.0")]
[InlineData("HTTP/3", "3")]
public void Parse_ValidHttpVersion_ReturnsCorrectVersion(string protocol, string expectedVersion)
{
// Act
var version = HttpVersionParser.Parse(protocol);
// Assert
version.Should().Be(expectedVersion, "the input string is a valid HTTP protocol version");
}
[Theory]
[InlineData("HTP/2")]
[InlineData("HTTP/2.2.2")]
[InlineData("HTTP/")]
[InlineData("http//1.1")]
[InlineData("")]
public void Parse_InvalidHttpVersion_ReturnsEmptyString(string protocol)
{
// Act
var version = HttpVersionParser.Parse(protocol);
// Assert
version.Should().BeEmpty("the input string is not a valid HTTP protocol version");
}
}

View File

@@ -1,5 +1,4 @@
using FluentAssertions;
using NFluent;
using WireMock.Util;
using Xunit;
@@ -11,14 +10,15 @@ public class PortUtilsTests
public void PortUtils_TryExtract_InvalidUrl_Returns_False()
{
// Assign
string url = "test";
var url = "test";
// Act
bool result = PortUtils.TryExtract(url, out bool isHttps, out string proto, out string host, out int port);
var result = PortUtils.TryExtract(url, out var isHttps, out var isGrpc, out var proto, out var host, out var port);
// Assert
result.Should().BeFalse();
isHttps.Should().BeFalse();
isGrpc.Should().BeFalse();
proto.Should().BeNull();
host.Should().BeNull();
port.Should().Be(default(int));
@@ -28,14 +28,15 @@ public class PortUtilsTests
public void PortUtils_TryExtract_UrlIsMissingPort_Returns_False()
{
// Assign
string url = "http://0.0.0.0";
var url = "http://0.0.0.0";
// Act
bool result = PortUtils.TryExtract(url, out bool isHttps, out string proto, out string host, out int port);
var result = PortUtils.TryExtract(url, out var isHttps, out var isGrpc, out var proto, out var host, out var port);
// Assert
result.Should().BeFalse();
isHttps.Should().BeFalse();
isGrpc.Should().BeFalse();
proto.Should().BeNull();
host.Should().BeNull();
port.Should().Be(default(int));
@@ -45,14 +46,15 @@ public class PortUtilsTests
public void PortUtils_TryExtract_Http_Returns_True()
{
// Assign
string url = "http://wiremock.net:1234";
var url = "http://wiremock.net:1234";
// Act
bool result = PortUtils.TryExtract(url, out bool isHttps, out string proto, out string host, out int port);
var result = PortUtils.TryExtract(url, out var isHttps, out var isGrpc, out var proto, out var host, out var port);
// Assert
result.Should().BeTrue();
isHttps.Should().BeFalse();
isGrpc.Should().BeFalse();
proto.Should().Be("http");
host.Should().Be("wiremock.net");
port.Should().Be(1234);
@@ -62,31 +64,51 @@ public class PortUtilsTests
public void PortUtils_TryExtract_Https_Returns_True()
{
// Assign
string url = "https://wiremock.net:5000";
var url = "https://wiremock.net:5000";
// Act
bool result = PortUtils.TryExtract(url, out bool isHttps, out string proto, out string host, out int port);
var result = PortUtils.TryExtract(url, out var isHttps, out var isGrpc, out var proto, out var host, out var port);
// Assert
result.Should().BeTrue();
isHttps.Should().BeTrue();
isGrpc.Should().BeFalse();
proto.Should().Be("https");
host.Should().Be("wiremock.net");
port.Should().Be(5000);
}
[Fact]
public void PortUtils_TryExtract_Grpc_Returns_True()
{
// Assign
var url = "grpc://wiremock.net:1234";
// Act
var result = PortUtils.TryExtract(url, out var isHttps, out var isGrpc, out var proto, out var host, out var port);
// Assert
result.Should().BeTrue();
isHttps.Should().BeFalse();
isGrpc.Should().BeTrue();
proto.Should().Be("grpc");
host.Should().Be("wiremock.net");
port.Should().Be(1234);
}
[Fact]
public void PortUtils_TryExtract_Https0_0_0_0_Returns_True()
{
// Assign
string url = "https://0.0.0.0:5000";
var url = "https://0.0.0.0:5000";
// Act
bool result = PortUtils.TryExtract(url, out bool isHttps, out string proto, out string host, out int port);
var result = PortUtils.TryExtract(url, out var isHttps, out var isGrpc, out var proto, out var host, out var port);
// Assert
result.Should().BeTrue();
isHttps.Should().BeTrue();
isGrpc.Should().BeFalse();
proto.Should().Be("https");
host.Should().Be("0.0.0.0");
port.Should().Be(5000);

View File

@@ -27,7 +27,11 @@
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
<DefineConstants>$(DefineConstants);GRAPHQL;MIMEKIT</DefineConstants>
<DefineConstants>$(DefineConstants);GRAPHQL;MIMEKIT;PROTOBUF</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' ">
<DefineConstants>$(DefineConstants);TRAILINGHEADERS</DefineConstants>
</PropertyGroup>
<ItemGroup>
@@ -102,7 +106,16 @@
<ItemGroup Condition="'$(TargetFramework)' != 'net452'">
<PackageReference Include="System.Net.Http.Json" Version="3.2.1" />
<PackageReference Include="JsonConverter.System.Text.Json" Version="0.4.0" />
<PackageReference Include="JsonConverter.System.Text.Json" Version="0.5.0" />
<PackageReference Include="Google.Protobuf" Version="3.25.1" />
<PackageReference Include="Grpc.Net.Client" Version="2.59.0" />
<PackageReference Include="Grpc.Tools" Version="2.60.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<Protobuf Include="Grpc\greet.proto" GrpcServices="Client" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' or '$(TargetFramework)' == 'net8.0'">
@@ -119,6 +132,9 @@
<None Update="cert.pem">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Grpc\greet.proto">
<GrpcServices>Client</GrpcServices>
</None>
<None Update="responsebody.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View File

@@ -108,11 +108,10 @@ public partial class WireMockServerTests
// Arrange
const string body = "example";
var path = $"/foo_{Guid.NewGuid()}";
var settings = new WireMockServerSettings
var server = WireMockServer.Start(settings =>
{
UseSSL = true
};
var server = WireMockServer.Start(settings);
settings.UseSSL = true;
});
server
.Given(Request.Create()