mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-01-11 21:10:32 +01:00
Use latest ProtoBufJsonConverter to support WellKnownTypes (#1161)
* Use latest ProtoBufJsonConverter to support WellKnownTypes * Fix * 02 * WireMockServer_WithBodyAsProtoBuf_WithWellKnownTypes * . * extra test * 0.4.0-preview-06 * 7 * <PackageReference Include="ProtoBufJsonConverter" Version="0.4.0-preview-08" /> * Update README.md * <PackageReference Include="ProtoBufJsonConverter" Version="0.4.0-preview-09" /> * <PackageReference Include="ProtoBufJsonConverter" Version="0.4.0" /> * Update README.md
This commit is contained in:
@@ -89,7 +89,7 @@ public class MappingModel
|
||||
|
||||
/// <summary>
|
||||
/// Data Object which can be used when WithTransformer is used.
|
||||
/// e.g. lookup an path in this object using
|
||||
/// e.g. lookup a path in this object using
|
||||
/// <example>
|
||||
/// lookup data "1"
|
||||
/// </example>
|
||||
@@ -105,4 +105,9 @@ public class MappingModel
|
||||
/// The Grpc ProtoDefinition which is used for this mapping (request and response). [Optional]
|
||||
/// </summary>
|
||||
public string? ProtoDefinition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Grpc ProtoDefinitions which are used for this mapping (request and response). [Optional]
|
||||
/// </summary>
|
||||
public string[]? ProtoDefinitions { get; set; }
|
||||
}
|
||||
@@ -137,6 +137,11 @@ public class ResponseModel
|
||||
/// </summary>
|
||||
public string? ProtoDefinition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the proto definitions.
|
||||
/// </summary>
|
||||
public string[]? ProtoDefinitions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".
|
||||
/// </summary>
|
||||
|
||||
@@ -121,7 +121,7 @@ public class SettingsModel
|
||||
/// <summary>
|
||||
/// A list of Grpc ProtoDefinitions which can be used.
|
||||
/// </summary>
|
||||
public Dictionary<string, string>? ProtoDefinitions { get; set; }
|
||||
public Dictionary<string, string[]>? ProtoDefinitions { get; set; }
|
||||
|
||||
#if NETSTANDARD1_3_OR_GREATER || NET461
|
||||
/// <summary>
|
||||
|
||||
@@ -79,7 +79,7 @@ public interface IBodyData
|
||||
/// <summary>
|
||||
/// Gets or sets the proto definition.
|
||||
/// </summary>
|
||||
public Func<IdOrText>? ProtoDefinition { get; set; }
|
||||
public Func<IdOrTexts>? ProtoDefinition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
namespace WireMock.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A structure defining an (optional) Id and a Text.
|
||||
/// </summary>
|
||||
public readonly struct IdOrText
|
||||
{
|
||||
/// <summary>
|
||||
/// The Id [optional].
|
||||
/// </summary>
|
||||
public string? Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The Text.
|
||||
/// </summary>
|
||||
public string Text { get; }
|
||||
|
||||
/// <summary>
|
||||
/// When Id is defined, return the Id, else the Text.
|
||||
/// </summary>
|
||||
public string Value => Id ?? Text;
|
||||
|
||||
/// <summary>
|
||||
/// Create a IdOrText
|
||||
/// </summary>
|
||||
/// <param name="id">The Id [optional]</param>
|
||||
/// <param name="text">The Text.</param>
|
||||
public IdOrText(string? id, string text)
|
||||
{
|
||||
Id = id;
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
59
src/WireMock.Net.Abstractions/Models/IdOrTexts.cs
Normal file
59
src/WireMock.Net.Abstractions/Models/IdOrTexts.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace WireMock.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A structure defining an (optional) Id and a Text.
|
||||
/// </summary>
|
||||
public readonly struct IdOrTexts
|
||||
{
|
||||
/// <summary>
|
||||
/// The Id [optional].
|
||||
/// </summary>
|
||||
public string? Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The Text.
|
||||
/// </summary>
|
||||
public IReadOnlyList<string> Texts { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a IdOrText
|
||||
/// </summary>
|
||||
/// <param name="id">The Id [optional]</param>
|
||||
/// <param name="text">The Text.</param>
|
||||
public IdOrTexts(string? id, string text) : this(id, [text])
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a IdOrText
|
||||
/// </summary>
|
||||
/// <param name="id">The Id [optional]</param>
|
||||
/// <param name="texts">The Texts.</param>
|
||||
public IdOrTexts(string? id, IReadOnlyList<string> texts)
|
||||
{
|
||||
Id = id;
|
||||
Texts = texts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When Id is defined, return process the Id, else process the Texts.
|
||||
/// </summary>
|
||||
/// <param name="id">Callback to process the id.</param>
|
||||
/// <param name="texts">Callback to process the texts.</param>
|
||||
public void Value(Action<string> id, Action<IReadOnlyList<string>> texts)
|
||||
{
|
||||
if (Id != null)
|
||||
{
|
||||
id(Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
texts(Texts);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,16 @@ public static class AnyOfExtensions
|
||||
return value.IsFirst ? value.First : value.Second.Pattern;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the patterns.
|
||||
/// </summary>
|
||||
/// <param name="values">AnyOf types</param>
|
||||
/// <returns>string values</returns>
|
||||
public static string[] GetPatterns(this AnyOf<string, StringPattern>[] values)
|
||||
{
|
||||
return values.Select(GetPattern).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string-patterns to AnyOf patterns.
|
||||
/// </summary>
|
||||
|
||||
@@ -141,7 +141,7 @@ public interface IMapping
|
||||
/// <summary>
|
||||
/// The Grpc ProtoDefinition which is used for this mapping (request and response). [Optional]
|
||||
/// </summary>
|
||||
IdOrText? ProtoDefinition { get; }
|
||||
IdOrTexts? ProtoDefinition { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ProvideResponseAsync
|
||||
@@ -175,26 +175,7 @@ public interface IMapping
|
||||
/// <summary>
|
||||
/// Define a Grpc ProtoDefinition which is used for this mapping (request and response).
|
||||
/// </summary>
|
||||
/// <param name="protoDefinition">The proto definition as text.</param>
|
||||
/// <param name="protoDefinition">The proto definitions as id or text.</param>
|
||||
/// <returns>The <see cref="IMapping"/>.</returns>
|
||||
IMapping WithProtoDefinition(IdOrText protoDefinition);
|
||||
}
|
||||
|
||||
/*
|
||||
executionConditionState">State in which the current mapping can occur. [Optional]
|
||||
nextState">The next state which will occur after the current mapping execution. [Optional]
|
||||
stateTimes">Only when the current state is executed this number, the next state which will occur. [Optional]
|
||||
webhooks">The Webhooks. [Optional]
|
||||
useWebhooksFireAndForget">Use Fire and Forget for the defined webhook(s). [Optional]
|
||||
timeSettings">The TimeSettings. [Optional]
|
||||
data">The data object. [Optional]
|
||||
|
||||
|
||||
string? executionConditionState,
|
||||
string? nextState,
|
||||
int? stateTimes,
|
||||
IWebhook[]? webhooks,
|
||||
bool? useWebhooksFireAndForget,
|
||||
ITimeSettings? timeSettings,
|
||||
object? data,
|
||||
*/
|
||||
IMapping WithProtoDefinition(IdOrTexts protoDefinition);
|
||||
}
|
||||
@@ -82,7 +82,7 @@ public class Mapping : IMapping
|
||||
public double? Probability { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IdOrText? ProtoDefinition { get; private set; }
|
||||
public IdOrTexts? ProtoDefinition { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Mapping"/> class.
|
||||
@@ -189,7 +189,7 @@ public class Mapping : IMapping
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IMapping WithProtoDefinition(IdOrText protoDefinition)
|
||||
public IMapping WithProtoDefinition(IdOrTexts protoDefinition)
|
||||
{
|
||||
ProtoDefinition = protoDefinition;
|
||||
return this;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#if PROTOBUF
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ProtoBufJsonConverter;
|
||||
@@ -25,9 +26,9 @@ public class ProtoBufMatcher : IProtoBufMatcher
|
||||
public MatchBehaviour MatchBehaviour { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The Func to define The proto definition as text.
|
||||
/// The Func to define the proto definition as id or texts.
|
||||
/// </summary>
|
||||
public Func<IdOrText> ProtoDefinition { get; }
|
||||
public Func<IdOrTexts> ProtoDefinition { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".
|
||||
@@ -44,12 +45,12 @@ public class ProtoBufMatcher : IProtoBufMatcher
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProtoBufMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="protoDefinition">The proto definition.</param>
|
||||
/// <param name="protoDefinition">The proto definition as id or text.</param>
|
||||
/// <param name="messageType">The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".</param>
|
||||
/// <param name="matchBehaviour">The match behaviour. (default = "AcceptOnMatch")</param>
|
||||
/// <param name="matcher">The optional jsonMatcher to use to match the ProtoBuf as (json) object.</param>
|
||||
public ProtoBufMatcher(
|
||||
Func<IdOrText> protoDefinition,
|
||||
Func<IdOrTexts> protoDefinition,
|
||||
string messageType,
|
||||
MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch,
|
||||
IObjectMatcher? matcher = null
|
||||
@@ -102,7 +103,11 @@ public class ProtoBufMatcher : IProtoBufMatcher
|
||||
return null;
|
||||
}
|
||||
|
||||
var request = new ConvertToObjectRequest(ProtoDefinition().Text, MessageType, input);
|
||||
var protoDefinitions = ProtoDefinition().Texts;
|
||||
|
||||
var resolver = new WireMockProtoFileResolver(protoDefinitions);
|
||||
var request = new ConvertToObjectRequest(protoDefinitions[0], MessageType, input)
|
||||
.WithProtoFileResolver(resolver);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -19,10 +19,10 @@ public class RequestMessageProtoBufMatcher : IRequestMatcher
|
||||
/// Initializes a new instance of the <see cref="RequestMessageProtoBufMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="matchBehaviour">The match behaviour. (default = "AcceptOnMatch")</param>
|
||||
/// <param name="protoDefinition">The Func to define The proto definition as text.</param>
|
||||
/// <param name="protoDefinition">The Func to define the proto definitions as id or text.</param>
|
||||
/// <param name="messageType">The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".</param>
|
||||
/// <param name="matcher">The optional matcher to use to match the ProtoBuf as (json) object.</param>
|
||||
public RequestMessageProtoBufMatcher(MatchBehaviour matchBehaviour, Func<IdOrText> protoDefinition, string messageType, IObjectMatcher? matcher = null)
|
||||
public RequestMessageProtoBufMatcher(MatchBehaviour matchBehaviour, Func<IdOrTexts> protoDefinition, string messageType, IObjectMatcher? matcher = null)
|
||||
{
|
||||
#if PROTOBUF
|
||||
Matcher = new ProtoBufMatcher(protoDefinition, messageType, matchBehaviour, matcher);
|
||||
|
||||
@@ -52,7 +52,7 @@ public class BodyData : IBodyData
|
||||
|
||||
#region ProtoBuf
|
||||
/// <inheritdoc />
|
||||
public Func<IdOrText>? ProtoDefinition { get; set; }
|
||||
public Func<IdOrTexts>? ProtoDefinition { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string? ProtoBufMessageType { get; set; }
|
||||
|
||||
@@ -151,8 +151,8 @@ namespace WireMock.Owin.Mappers
|
||||
|
||||
#if PROTOBUF
|
||||
case BodyType.ProtoBuf:
|
||||
var protoDefinition = bodyData.ProtoDefinition?.Invoke().Text;
|
||||
return await ProtoBufUtils.GetProtoBufMessageWithHeaderAsync(protoDefinition, bodyData.ProtoBufMessageType, bodyData.BodyAsJson).ConfigureAwait(false);
|
||||
var protoDefinitions = bodyData.ProtoDefinition?.Invoke().Texts;
|
||||
return await ProtoBufUtils.GetProtoBufMessageWithHeaderAsync(protoDefinitions, responseMessage.BodyData.ProtoBufMessageType, responseMessage.BodyData.BodyAsJson).ConfigureAwait(false);
|
||||
#endif
|
||||
|
||||
case BodyType.Bytes:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Collections.Generic;
|
||||
using WireMock.Matchers;
|
||||
|
||||
namespace WireMock.RequestBuilders;
|
||||
@@ -10,7 +11,7 @@ namespace WireMock.RequestBuilders;
|
||||
public interface IProtoBufRequestBuilder : IGraphQLRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// WithGrpcProto
|
||||
/// WithBodyAsProtoBuf
|
||||
/// </summary>
|
||||
/// <param name="protoDefinition">The proto definition as text.</param>
|
||||
/// <param name="messageType">The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".</param>
|
||||
@@ -19,7 +20,7 @@ public interface IProtoBufRequestBuilder : IGraphQLRequestBuilder
|
||||
IRequestBuilder WithBodyAsProtoBuf(string protoDefinition, string messageType, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
||||
|
||||
/// <summary>
|
||||
/// WithGrpcProto
|
||||
/// WithBodyAsProtoBuf
|
||||
/// </summary>
|
||||
/// <param name="protoDefinition">The proto definition as text.</param>
|
||||
/// <param name="messageType">The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".</param>
|
||||
@@ -29,7 +30,26 @@ public interface IProtoBufRequestBuilder : IGraphQLRequestBuilder
|
||||
IRequestBuilder WithBodyAsProtoBuf(string protoDefinition, string messageType, IObjectMatcher matcher, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
||||
|
||||
/// <summary>
|
||||
/// WithGrpcProto
|
||||
/// WithBodyAsProtoBuf
|
||||
/// </summary>
|
||||
/// <param name="protoDefinitions">The proto definitions as text.</param>
|
||||
/// <param name="messageType">The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".</param>
|
||||
/// <param name="matchBehaviour">The match behaviour. (default = "AcceptOnMatch")</param>
|
||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||
IRequestBuilder WithBodyAsProtoBuf(IReadOnlyList<string> protoDefinitions, string messageType, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
||||
|
||||
/// <summary>
|
||||
/// WithBodyAsProtoBuf
|
||||
/// </summary>
|
||||
/// <param name="protoDefinitions">The proto definitions as text.</param>
|
||||
/// <param name="messageType">The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".</param>
|
||||
/// <param name="matcher">The matcher to use to match the ProtoBuf as (json) object.</param>
|
||||
/// <param name="matchBehaviour">The match behaviour. (default = "AcceptOnMatch")</param>
|
||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||
IRequestBuilder WithBodyAsProtoBuf(IReadOnlyList<string> protoDefinitions, string messageType, IObjectMatcher matcher, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
||||
|
||||
/// <summary>
|
||||
/// WithBodyAsProtoBuf
|
||||
/// </summary>
|
||||
/// <param name="messageType">The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".</param>
|
||||
/// <param name="matchBehaviour">The match behaviour. (default = "AcceptOnMatch")</param>
|
||||
@@ -37,7 +57,7 @@ public interface IProtoBufRequestBuilder : IGraphQLRequestBuilder
|
||||
IRequestBuilder WithBodyAsProtoBuf(string messageType, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
||||
|
||||
/// <summary>
|
||||
/// WithGrpcProto
|
||||
/// WithBodyAsProtoBuf
|
||||
/// </summary>
|
||||
/// <param name="messageType">The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".</param>
|
||||
/// <param name="matcher">The matcher to use to match the ProtoBuf as (json) object.</param>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Models;
|
||||
|
||||
namespace WireMock.RequestBuilders;
|
||||
|
||||
@@ -10,13 +13,25 @@ public partial class Request
|
||||
/// <inheritdoc />
|
||||
public IRequestBuilder WithBodyAsProtoBuf(string protoDefinition, string messageType, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||
{
|
||||
return Add(new RequestMessageProtoBufMatcher(matchBehaviour, () => new (null, protoDefinition), messageType));
|
||||
return WithBodyAsProtoBuf([ protoDefinition ], messageType, matchBehaviour);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IRequestBuilder WithBodyAsProtoBuf(string protoDefinition, string messageType, IObjectMatcher matcher, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||
{
|
||||
return Add(new RequestMessageProtoBufMatcher(matchBehaviour, () => new(null, protoDefinition), messageType, matcher));
|
||||
return WithBodyAsProtoBuf([protoDefinition], messageType, matcher, matchBehaviour);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IRequestBuilder WithBodyAsProtoBuf(IReadOnlyList<string> protoDefinitions, string messageType, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||
{
|
||||
return Add(new RequestMessageProtoBufMatcher(matchBehaviour, () => new IdOrTexts(null, protoDefinitions), messageType));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IRequestBuilder WithBodyAsProtoBuf(IReadOnlyList<string> protoDefinitions, string messageType, IObjectMatcher matcher, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||
{
|
||||
return Add(new RequestMessageProtoBufMatcher(matchBehaviour, () => new IdOrTexts(null, protoDefinitions), messageType, matcher));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using JsonConverter.Abstractions;
|
||||
@@ -109,7 +110,7 @@ public interface IBodyResponseBuilder : IFaultResponseBuilder
|
||||
IResponseBuilder WithBody(object body, Encoding? encoding, IJsonConverter jsonConverter, JsonConverterOptions? options = null);
|
||||
|
||||
/// <summary>
|
||||
/// WithBody : Create a ProtoBuf byte[] response based on a proto definition, message type and the value.
|
||||
/// WithBodyAsProtoBuf : Create a ProtoBuf byte[] response based on a proto definition, message type and the value.
|
||||
/// </summary>
|
||||
/// <param name="protoDefinition">The proto definition as text.</param>
|
||||
/// <param name="messageType">The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".</param>
|
||||
@@ -126,7 +127,24 @@ public interface IBodyResponseBuilder : IFaultResponseBuilder
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// WithBody : Create a ProtoBuf byte[] response based on a proto definition, message type and the value.
|
||||
/// WithBodyAsProtoBuf : Create a ProtoBuf byte[] response based on proto definitions, message type and the value.
|
||||
/// </summary>
|
||||
/// <param name="protoDefinitions">The proto definition as text.</param>
|
||||
/// <param name="messageType">The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".</param>
|
||||
/// <param name="value">The object to convert to protobuf byte[].</param>
|
||||
/// <param name="jsonConverter">The <see cref="IJsonConverter"/> [optional]. Default value is NewtonsoftJsonConverter.</param>
|
||||
/// <param name="options">The <see cref="JsonConverterOptions"/> [optional].</param>
|
||||
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
|
||||
IResponseBuilder WithBodyAsProtoBuf(
|
||||
IReadOnlyList<string> protoDefinitions,
|
||||
string messageType,
|
||||
object value,
|
||||
IJsonConverter? jsonConverter = null,
|
||||
JsonConverterOptions? options = null
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// WithBodyAsProtoBuf : Create a ProtoBuf byte[] response based on a proto definition, message type and the value.
|
||||
/// </summary>
|
||||
/// <param name="messageType">The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".</param>
|
||||
/// <param name="value">The object to convert to protobuf byte[].</param>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using JsonConverter.Abstractions;
|
||||
using Stef.Validation;
|
||||
using WireMock.Exceptions;
|
||||
using WireMock.Models;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
|
||||
@@ -223,7 +225,19 @@ public partial class Response
|
||||
JsonConverterOptions? options = null
|
||||
)
|
||||
{
|
||||
Guard.NotNullOrWhiteSpace(protoDefinition);
|
||||
return WithBodyAsProtoBuf([protoDefinition], messageType, value, jsonConverter, options);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IResponseBuilder WithBodyAsProtoBuf(
|
||||
IReadOnlyList<string> protoDefinitions,
|
||||
string messageType,
|
||||
object value,
|
||||
IJsonConverter? jsonConverter = null,
|
||||
JsonConverterOptions? options = null
|
||||
)
|
||||
{
|
||||
Guard.NotNullOrEmpty(protoDefinitions);
|
||||
Guard.NotNullOrWhiteSpace(messageType);
|
||||
Guard.NotNull(value);
|
||||
|
||||
@@ -235,7 +249,7 @@ public partial class Response
|
||||
{
|
||||
DetectedBodyType = BodyType.ProtoBuf,
|
||||
BodyAsJson = value,
|
||||
ProtoDefinition = () => new (null, protoDefinition),
|
||||
ProtoDefinition = () => new IdOrTexts(null, protoDefinitions),
|
||||
ProtoBufMessageType = messageType
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -273,7 +273,6 @@ internal class MappingConverter(MatcherMapper mapper)
|
||||
WhenStateIs = mapping.ExecutionConditionState,
|
||||
SetStateTo = mapping.NextState,
|
||||
Data = mapping.Data,
|
||||
ProtoDefinition = mapping.ProtoDefinition?.Value,
|
||||
Probability = mapping.Probability,
|
||||
Request = new RequestModel
|
||||
{
|
||||
@@ -304,6 +303,20 @@ internal class MappingConverter(MatcherMapper mapper)
|
||||
Response = new ResponseModel()
|
||||
};
|
||||
|
||||
mapping.ProtoDefinition?.Value(
|
||||
id => mappingModel.ProtoDefinition = id,
|
||||
texts =>
|
||||
{
|
||||
if (texts.Count == 1)
|
||||
{
|
||||
mappingModel.ProtoDefinition = texts[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
mappingModel.ProtoDefinitions = texts.ToArray();
|
||||
}
|
||||
});
|
||||
|
||||
if (methodMatcher != null)
|
||||
{
|
||||
mappingModel.Request.Methods = methodMatcher.Methods;
|
||||
@@ -491,10 +504,22 @@ internal class MappingConverter(MatcherMapper mapper)
|
||||
break;
|
||||
|
||||
case BodyType.ProtoBuf:
|
||||
// If the ProtoDefinition is not defined at the MappingModel, get the ProtoDefinition from the ResponseMessage.
|
||||
if (mappingModel.ProtoDefinition == null)
|
||||
// If the ProtoDefinition(s) is/are not defined at the MappingModel, get the ProtoDefinition(s) from the ResponseMessage.
|
||||
if (mappingModel.ProtoDefinition == null && mappingModel.ProtoDefinitions == null)
|
||||
{
|
||||
mappingModel.Response.ProtoDefinition = response.ResponseMessage.BodyData.ProtoDefinition?.Invoke().Value;
|
||||
response.ResponseMessage.BodyData.ProtoDefinition?.Invoke().Value(
|
||||
id => mappingModel.Response.ProtoDefinition = id,
|
||||
texts =>
|
||||
{
|
||||
if (texts.Count == 1)
|
||||
{
|
||||
mappingModel.Response.ProtoDefinition = texts[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
mappingModel.Response.ProtoDefinitions = texts.ToArray();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mappingModel.Response.ProtoBufMessageType = response.ResponseMessage.BodyData.ProtoBufMessageType;
|
||||
|
||||
@@ -79,7 +79,7 @@ internal class MatcherMapper
|
||||
|
||||
#if PROTOBUF
|
||||
case nameof(ProtoBufMatcher):
|
||||
return CreateProtoBufMatcher(matchBehaviour, stringPatterns[0].GetPattern(), matcherModel);
|
||||
return CreateProtoBufMatcher(matchBehaviour, stringPatterns.GetPatterns(), matcherModel);
|
||||
#endif
|
||||
case nameof(RegexMatcher):
|
||||
return new RegexMatcher(matchBehaviour, stringPatterns, ignoreCase, useRegexExtended, matchOperator);
|
||||
@@ -211,7 +211,18 @@ internal class MatcherMapper
|
||||
|
||||
#if PROTOBUF
|
||||
case ProtoBufMatcher protoBufMatcher:
|
||||
model.Pattern = protoBufMatcher.ProtoDefinition().Value;
|
||||
protoBufMatcher.ProtoDefinition().Value(id => model.Pattern = id, texts =>
|
||||
{
|
||||
if (texts.Count == 1)
|
||||
{
|
||||
model.Pattern = texts[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
model.Patterns = texts.Cast<object>().ToArray();
|
||||
}
|
||||
});
|
||||
|
||||
model.ProtoBufMessageType = protoBufMatcher.MessageType;
|
||||
model.ContentMatcher = Map(protoBufMatcher.Matcher);
|
||||
break;
|
||||
@@ -278,22 +289,30 @@ internal class MatcherMapper
|
||||
#endif
|
||||
|
||||
#if PROTOBUF
|
||||
private ProtoBufMatcher CreateProtoBufMatcher(MatchBehaviour? matchBehaviour, string protoDefinitionOrId, MatcherModel matcher)
|
||||
private ProtoBufMatcher CreateProtoBufMatcher(MatchBehaviour? matchBehaviour, IReadOnlyList<string> protoDefinitions, MatcherModel matcher)
|
||||
{
|
||||
var objectMatcher = Map(matcher.ContentMatcher) as IObjectMatcher;
|
||||
|
||||
IdOrText protoDefinition;
|
||||
if (_settings.ProtoDefinitions?.TryGetValue(protoDefinitionOrId, out var protoDefinitionFromSettings) == true)
|
||||
IdOrTexts protoDefinitionAsIdOrTexts;
|
||||
if (protoDefinitions.Count == 1)
|
||||
{
|
||||
protoDefinition = new(protoDefinitionOrId, protoDefinitionFromSettings);
|
||||
var idOrText = protoDefinitions[0];
|
||||
if (_settings.ProtoDefinitions?.TryGetValue(idOrText, out var protoDefinitionFromSettings) == true)
|
||||
{
|
||||
protoDefinitionAsIdOrTexts = new(idOrText, protoDefinitionFromSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
protoDefinitionAsIdOrTexts = new(null, protoDefinitions);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
protoDefinition = new(null, protoDefinitionOrId);
|
||||
protoDefinitionAsIdOrTexts = new(null, protoDefinitions);
|
||||
}
|
||||
|
||||
return new ProtoBufMatcher(
|
||||
() => protoDefinition,
|
||||
() => protoDefinitionAsIdOrTexts,
|
||||
matcher!.ProtoBufMessageType!,
|
||||
matchBehaviour ?? MatchBehaviour.AcceptOnMatch,
|
||||
objectMatcher
|
||||
|
||||
@@ -242,7 +242,7 @@ public interface IRespondWithAProvider
|
||||
/// </summary>
|
||||
/// <param name="protoDefinitionOrId">The proto definition as text or as id.</param>
|
||||
/// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
|
||||
IRespondWithAProvider WithProtoDefinition(string protoDefinitionOrId);
|
||||
IRespondWithAProvider WithProtoDefinition(params string[] protoDefinitionOrId);
|
||||
|
||||
/// <summary>
|
||||
/// Define a GraphQL Schema which is used for the request and the response.
|
||||
|
||||
@@ -37,7 +37,7 @@ internal class RespondWithAProvider : IRespondWithAProvider
|
||||
private int _timesInSameState = 1;
|
||||
private bool? _useWebhookFireAndForget;
|
||||
private double? _probability;
|
||||
private IdOrText? _protoDefinition;
|
||||
private IdOrTexts? _protoDefinition;
|
||||
private GraphQLSchemaDetails? _graphQLSchemaDetails;
|
||||
|
||||
public Guid Guid { get; private set; }
|
||||
@@ -351,18 +351,27 @@ internal class RespondWithAProvider : IRespondWithAProvider
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IRespondWithAProvider WithProtoDefinition(string protoDefinitionOrId)
|
||||
public IRespondWithAProvider WithProtoDefinition(params string[] protoDefinitionOrId)
|
||||
{
|
||||
Guard.NotNullOrWhiteSpace(protoDefinitionOrId);
|
||||
Guard.NotNull(protoDefinitionOrId);
|
||||
|
||||
if (_settings.ProtoDefinitions?.TryGetValue(protoDefinitionOrId, out var protoDefinition) == true)
|
||||
if (protoDefinitionOrId.Length == 1)
|
||||
{
|
||||
_protoDefinition = new (protoDefinitionOrId, protoDefinition);
|
||||
var idOrText = protoDefinitionOrId[0];
|
||||
if (_settings.ProtoDefinitions?.TryGetValue(idOrText, out var protoDefinitions) == true)
|
||||
{
|
||||
_protoDefinition = new(idOrText, protoDefinitions);
|
||||
}
|
||||
else
|
||||
{
|
||||
_protoDefinition = new(null, protoDefinitionOrId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_protoDefinition = new(null, protoDefinitionOrId);
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -595,12 +595,12 @@ public partial class WireMockServer : IWireMockServer
|
||||
/// <param name="protoDefinition">The ProtoDefinition as text.</param>
|
||||
/// <returns><see cref="WireMockServer"/></returns>
|
||||
[PublicAPI]
|
||||
public WireMockServer AddProtoDefinition(string id, string protoDefinition)
|
||||
public WireMockServer AddProtoDefinition(string id, params string[] protoDefinition)
|
||||
{
|
||||
Guard.NotNullOrWhiteSpace(id);
|
||||
Guard.NotNullOrWhiteSpace(protoDefinition);
|
||||
Guard.NotNullOrEmpty(protoDefinition);
|
||||
|
||||
_settings.ProtoDefinitions ??= new Dictionary<string, string>();
|
||||
_settings.ProtoDefinitions ??= new Dictionary<string, string[]>();
|
||||
|
||||
_settings.ProtoDefinitions[id] = protoDefinition;
|
||||
|
||||
|
||||
@@ -298,7 +298,7 @@ public class WireMockServerSettings
|
||||
public IDictionary<string, Func<MatcherModel, IMatcher>>? CustomMatcherMappings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="JsonSerializerSettings"/> used when the a JSON response is generated.
|
||||
/// The <see cref="JsonSerializerSettings"/> used when the JSON response is generated.
|
||||
/// </summary>
|
||||
[PublicAPI, JsonIgnore]
|
||||
public JsonSerializerSettings? JsonSerializerSettings { get; set; }
|
||||
@@ -315,7 +315,7 @@ public class WireMockServerSettings
|
||||
/// A list of Grpc ProtoDefinitions which can be used.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public Dictionary<string, string>? ProtoDefinitions { get; set; }
|
||||
public Dictionary<string, string[]>? ProtoDefinitions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of GraphQL Schemas which can be used.
|
||||
|
||||
@@ -61,7 +61,7 @@ public static class WireMockServerSettingsParser
|
||||
HandleRequestsSynchronously = parser.GetBoolValue(nameof(WireMockServerSettings.HandleRequestsSynchronously)),
|
||||
HostingScheme = parser.GetEnumValue<HostingScheme>(nameof(WireMockServerSettings.HostingScheme)),
|
||||
MaxRequestLogCount = parser.GetIntValue(nameof(WireMockServerSettings.MaxRequestLogCount)),
|
||||
ProtoDefinitions = parser.GetObjectValueFromJson<Dictionary<string, string>>(nameof(settings.ProtoDefinitions)),
|
||||
ProtoDefinitions = parser.GetObjectValueFromJson<Dictionary<string, string[]>>(nameof(settings.ProtoDefinitions)),
|
||||
QueryParameterMultipleValueSupport = parser.GetEnumValue<QueryParameterMultipleValueSupport>(nameof(WireMockServerSettings.QueryParameterMultipleValueSupport)),
|
||||
ReadStaticMappings = parser.GetBoolValue(nameof(WireMockServerSettings.ReadStaticMappings)),
|
||||
RequestLogExpirationDuration = parser.GetIntValue(nameof(WireMockServerSettings.RequestLogExpirationDuration)),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#if PROTOBUF
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using JsonConverter.Abstractions;
|
||||
@@ -13,31 +13,25 @@ namespace WireMock.Util;
|
||||
internal static class ProtoBufUtils
|
||||
{
|
||||
internal static async Task<byte[]> GetProtoBufMessageWithHeaderAsync(
|
||||
string? protoDefinition,
|
||||
IReadOnlyList<string>? protoDefinitions,
|
||||
string? messageType,
|
||||
object? value,
|
||||
IJsonConverter? jsonConverter = null,
|
||||
JsonConverterOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(protoDefinition) || string.IsNullOrWhiteSpace(messageType) || value is null)
|
||||
if (protoDefinitions == null || string.IsNullOrWhiteSpace(messageType) || value is null)
|
||||
{
|
||||
return Array.Empty<byte>();
|
||||
return [];
|
||||
}
|
||||
|
||||
var request = new ConvertToProtoBufRequest(protoDefinition, messageType, value, true);
|
||||
var resolver = new WireMockProtoFileResolver(protoDefinitions);
|
||||
var request = new ConvertToProtoBufRequest(protoDefinitions[0], messageType, value, true)
|
||||
.WithProtoFileResolver(resolver);
|
||||
|
||||
if (jsonConverter != null)
|
||||
{
|
||||
request = request.WithJsonConverter(jsonConverter);
|
||||
if (options != null)
|
||||
{
|
||||
request = request.WithJsonConverterOptions(options);
|
||||
}
|
||||
}
|
||||
|
||||
return await SingletonFactory<Converter>.GetInstance().ConvertAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return await SingletonFactory<Converter>
|
||||
.GetInstance()
|
||||
.ConvertAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
46
src/WireMock.Net/Util/WireMockProtoFileResolver.cs
Normal file
46
src/WireMock.Net/Util/WireMockProtoFileResolver.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#if PROTOBUF
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ProtoBufJsonConverter;
|
||||
using Stef.Validation;
|
||||
|
||||
namespace WireMock.Util;
|
||||
|
||||
internal class WireMockProtoFileResolver : IProtoFileResolver
|
||||
{
|
||||
private readonly Dictionary<string, string> _files = new();
|
||||
|
||||
public WireMockProtoFileResolver(IReadOnlyCollection<string> protoDefinitions)
|
||||
{
|
||||
if (Guard.NotNullOrEmpty(protoDefinitions).Count() > 1)
|
||||
{
|
||||
foreach (var extraProtoDefinition in protoDefinitions.Skip(1))
|
||||
{
|
||||
var firstNonEmptyLine = extraProtoDefinition.Split(['\r', '\n']).FirstOrDefault(l => !string.IsNullOrEmpty(l));
|
||||
if (firstNonEmptyLine != null)
|
||||
{
|
||||
_files.Add(firstNonEmptyLine.TrimStart(['\r', '\n', '/', ' ']), extraProtoDefinition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Exists(string path)
|
||||
{
|
||||
return _files.ContainsKey(path);
|
||||
}
|
||||
|
||||
public TextReader OpenText(string path)
|
||||
{
|
||||
if (_files.TryGetValue(path, out var extraProtoDefinition))
|
||||
{
|
||||
return new StringReader(extraProtoDefinition);
|
||||
}
|
||||
|
||||
throw new FileNotFoundException($"The ProtoDefinition '{path}' was not found.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -150,7 +150,7 @@
|
||||
<PackageReference Include="GraphQL" Version="7.5.0" />
|
||||
<PackageReference Include="GraphQL.NewtonsoftJson" Version="7.5.0" />
|
||||
<PackageReference Include="MimeKitLite" Version="4.1.0.1" />
|
||||
<PackageReference Include="ProtoBufJsonConverter" Version="0.3.0" />
|
||||
<PackageReference Include="ProtoBufJsonConverter" Version="0.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
|
||||
|
||||
@@ -35,6 +35,69 @@ message HelloRequest {
|
||||
message HelloReply {
|
||||
string message = 1;
|
||||
}
|
||||
";
|
||||
|
||||
private const string ProtoDefinitionWithWellKnownTypes = @"
|
||||
syntax = ""proto3"";
|
||||
|
||||
package communication.api.v1;
|
||||
|
||||
import ""google/protobuf/empty.proto"";
|
||||
import ""google/protobuf/timestamp.proto"";
|
||||
import ""google/protobuf/duration.proto"";
|
||||
|
||||
service Greeter {
|
||||
rpc SayNothing (google.protobuf.Empty) returns (google.protobuf.Empty);
|
||||
}
|
||||
|
||||
message MyMessageTimestamp {
|
||||
google.protobuf.Timestamp ts = 1;
|
||||
}
|
||||
|
||||
message MyMessageDuration {
|
||||
google.protobuf.Duration du = 1;
|
||||
}
|
||||
";
|
||||
|
||||
private const string ProtoDefinitionMain = @"
|
||||
syntax = ""proto3"";
|
||||
|
||||
package greet;
|
||||
|
||||
import ""other.proto"";
|
||||
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);
|
||||
}
|
||||
|
||||
message HelloRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message HelloReply {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
message Person {
|
||||
string name = 1;
|
||||
int32 id = 2;
|
||||
string email = 3;
|
||||
}
|
||||
";
|
||||
|
||||
private const string ProtoDefinitionOther = @"// other.proto
|
||||
syntax = ""proto3"";
|
||||
|
||||
package greet;
|
||||
|
||||
message Other {
|
||||
string name = 1;
|
||||
}
|
||||
";
|
||||
|
||||
[Theory]
|
||||
@@ -80,6 +143,129 @@ message HelloReply {
|
||||
server.Stop();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WireMockServer_WithBodyAsProtoBuf_WithWellKnownTypes()
|
||||
{
|
||||
// Arrange
|
||||
var bytes = Convert.FromBase64String("CgRzdGVm");
|
||||
|
||||
using var server = WireMockServer.Start();
|
||||
|
||||
server
|
||||
.Given(Request.Create()
|
||||
.UsingPost()
|
||||
.WithPath("/grpc/Greeter/SayNothing")
|
||||
.WithBody(new NotNullOrEmptyMatcher())
|
||||
)
|
||||
.RespondWith(Response.Create()
|
||||
.WithBodyAsProtoBuf(ProtoDefinitionWithWellKnownTypes, "google.protobuf.Empty",
|
||||
new { }
|
||||
)
|
||||
.WithTrailingHeader("grpc-status", "0")
|
||||
.WithTransformer()
|
||||
);
|
||||
|
||||
// Act
|
||||
var protoBuf = new ByteArrayContent(bytes);
|
||||
protoBuf.Headers.ContentType = new MediaTypeHeaderValue("application/grpc-web");
|
||||
|
||||
var client = server.CreateClient();
|
||||
var response = await client.PostAsync("/grpc/Greeter/SayNothing", protoBuf);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var responseBytes = await response.Content.ReadAsByteArrayAsync();
|
||||
|
||||
Convert.ToBase64String(responseBytes).Should().Be("");
|
||||
|
||||
server.Stop();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WireMockServer_WithBodyAsProtoBuf_ServerProtoDefinition_WithWellKnownTypes()
|
||||
{
|
||||
// Arrange
|
||||
var bytes = Convert.FromBase64String("CgRzdGVm");
|
||||
|
||||
using var server = WireMockServer.Start();
|
||||
|
||||
var id = $"proto-{Guid.NewGuid()}";
|
||||
|
||||
server
|
||||
.AddProtoDefinition(id, ProtoDefinitionWithWellKnownTypes)
|
||||
.Given(Request.Create()
|
||||
.UsingPost()
|
||||
.WithPath("/grpc/Greeter/SayNothing")
|
||||
.WithBody(new NotNullOrEmptyMatcher())
|
||||
)
|
||||
.WithProtoDefinition(id)
|
||||
.RespondWith(Response.Create()
|
||||
.WithBodyAsProtoBuf("google.protobuf.Empty",
|
||||
new { }
|
||||
)
|
||||
.WithTrailingHeader("grpc-status", "0")
|
||||
.WithTransformer()
|
||||
);
|
||||
|
||||
// Act
|
||||
var protoBuf = new ByteArrayContent(bytes);
|
||||
protoBuf.Headers.ContentType = new MediaTypeHeaderValue("application/grpc-web");
|
||||
|
||||
var client = server.CreateClient();
|
||||
var response = await client.PostAsync("/grpc/Greeter/SayNothing", protoBuf);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var responseBytes = await response.Content.ReadAsByteArrayAsync();
|
||||
|
||||
Convert.ToBase64String(responseBytes).Should().Be("");
|
||||
|
||||
server.Stop();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WireMockServer_WithBodyAsProtoBuf_MultipleFiles()
|
||||
{
|
||||
// Arrange
|
||||
var bytes = Convert.FromBase64String("CgRzdGVm");
|
||||
var jsonMatcher = new JsonMatcher(new { name = "stef" });
|
||||
|
||||
using var server = WireMockServer.Start();
|
||||
|
||||
var protoFiles = new [] { ProtoDefinitionMain, ProtoDefinitionOther };
|
||||
|
||||
server
|
||||
.Given(Request.Create()
|
||||
.UsingPost()
|
||||
.WithPath("/grpc/greet.Greeter/SayOther")
|
||||
.WithBodyAsProtoBuf(protoFiles, "greet.Other", jsonMatcher)
|
||||
)
|
||||
.RespondWith(Response.Create()
|
||||
.WithBodyAsProtoBuf(protoFiles, "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/SayOther", 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()
|
||||
{
|
||||
|
||||
@@ -14,7 +14,8 @@ namespace WireMock.Net.Tests.Matchers;
|
||||
public class ProtoBufMatcherTests
|
||||
{
|
||||
private const string MessageType = "greet.HelloRequest";
|
||||
private readonly IdOrText _protoDefinition = new(null, @"
|
||||
|
||||
private static IdOrTexts ProtoDefinition => new(null, @"
|
||||
syntax = ""proto3"";
|
||||
|
||||
package greet;
|
||||
@@ -30,7 +31,7 @@ message HelloRequest {
|
||||
message HelloReply {
|
||||
string message = 1;
|
||||
}
|
||||
");
|
||||
" + "\r\n// Dummy " + Guid.NewGuid());
|
||||
|
||||
[Fact]
|
||||
public async Task ProtoBufMatcher_For_ValidProtoBuf_And_ValidMethod_DecodeAsync()
|
||||
@@ -39,7 +40,7 @@ message HelloReply {
|
||||
var bytes = Convert.FromBase64String("CgRzdGVm");
|
||||
|
||||
// Act
|
||||
var matcher = new ProtoBufMatcher(() => _protoDefinition, MessageType);
|
||||
var matcher = new ProtoBufMatcher(() => ProtoDefinition, MessageType);
|
||||
var result = await matcher.DecodeAsync(bytes).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
@@ -53,7 +54,7 @@ message HelloReply {
|
||||
var bytes = Convert.FromBase64String("CgRzdGVm");
|
||||
|
||||
// Act
|
||||
var matcher = new ProtoBufMatcher(() => _protoDefinition, MessageType);
|
||||
var matcher = new ProtoBufMatcher(() => ProtoDefinition, MessageType);
|
||||
var result = await matcher.IsMatchAsync(bytes).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
@@ -69,7 +70,7 @@ message HelloReply {
|
||||
var bytes = Convert.FromBase64String("CgRzdGVm");
|
||||
|
||||
// Act
|
||||
var matcher = new ProtoBufMatcher(() => _protoDefinition, MessageType, matcher: jsonMatcher);
|
||||
var matcher = new ProtoBufMatcher(() => ProtoDefinition, MessageType, matcher: jsonMatcher);
|
||||
var result = await matcher.IsMatchAsync(bytes);
|
||||
|
||||
// Assert
|
||||
@@ -84,7 +85,7 @@ message HelloReply {
|
||||
var bytes = new byte[] { 1, 2, 3 };
|
||||
|
||||
// Act
|
||||
var matcher = new ProtoBufMatcher(() => _protoDefinition, MessageType);
|
||||
var matcher = new ProtoBufMatcher(() => ProtoDefinition, MessageType);
|
||||
var result = await matcher.IsMatchAsync(bytes);
|
||||
|
||||
// Assert
|
||||
@@ -99,7 +100,7 @@ message HelloReply {
|
||||
var bytes = Convert.FromBase64String("CgRzdGVm");
|
||||
|
||||
// Act
|
||||
var matcher = new ProtoBufMatcher(() => _protoDefinition, "greet.Greeter.X");
|
||||
var matcher = new ProtoBufMatcher(() => ProtoDefinition, "greet.Greeter.X");
|
||||
var result = await matcher.IsMatchAsync(bytes);
|
||||
|
||||
// Assert
|
||||
|
||||
@@ -42,7 +42,7 @@ message HelloReply {
|
||||
matchers.Should().HaveCount(1);
|
||||
|
||||
var protoBufMatcher = (ProtoBufMatcher)((RequestMessageProtoBufMatcher)matchers[0]).Matcher!;
|
||||
protoBufMatcher.ProtoDefinition().Text.Should().Be(TestProtoDefinition);
|
||||
protoBufMatcher.ProtoDefinition().Texts.Should().Contain(TestProtoDefinition);
|
||||
protoBufMatcher.MessageType.Should().Be(MessageType);
|
||||
protoBufMatcher.Matcher.Should().BeNull();
|
||||
}
|
||||
@@ -59,7 +59,7 @@ message HelloReply {
|
||||
matchers.Should().HaveCount(1);
|
||||
|
||||
var protoBufMatcher = (ProtoBufMatcher)((RequestMessageProtoBufMatcher)matchers[0]).Matcher!;
|
||||
protoBufMatcher.ProtoDefinition().Text.Should().Be(TestProtoDefinition);
|
||||
protoBufMatcher.ProtoDefinition().Texts.Should().Contain(TestProtoDefinition);
|
||||
protoBufMatcher.MessageType.Should().Be(MessageType);
|
||||
protoBufMatcher.Matcher.Should().BeOfType<JsonMatcher>();
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
Guid: Guid_1,
|
||||
UpdatedAt: 2022-12-04 11:12:13,
|
||||
TimeSettings: {
|
||||
Start: 2023-01-14 15:16:17,
|
||||
End: 2023-01-14 15:17:57,
|
||||
Start: 2023-01-14 15:16:17 Utc,
|
||||
End: 2023-01-14 15:17:57 Utc,
|
||||
TTL: 100
|
||||
},
|
||||
Title: ,
|
||||
|
||||
@@ -226,7 +226,7 @@ message HelloReply {
|
||||
public Task ToMappingModel_WithTimeSettings_ReturnsCorrectTimeSettings()
|
||||
{
|
||||
// Assign
|
||||
var start = new DateTime(2023, 1, 14, 15, 16, 17);
|
||||
var start = new DateTime(2023, 1, 14, 15, 16, 17, DateTimeKind.Utc);
|
||||
var ttl = 100;
|
||||
var end = start.AddSeconds(ttl);
|
||||
var request = Request.Create();
|
||||
|
||||
@@ -102,7 +102,7 @@ public class MatcherMapperTests
|
||||
// Assign
|
||||
var matcherMock = new Mock<IStringMatcher>();
|
||||
matcherMock.Setup(m => m.Name).Returns("test");
|
||||
matcherMock.Setup(m => m.GetPatterns()).Returns(new AnyOf<string, StringPattern>[] { "p1", "p2" });
|
||||
matcherMock.Setup(m => m.GetPatterns()).Returns(["p1", "p2"]);
|
||||
|
||||
// Act
|
||||
var model = _sut.Map(matcherMock.Object)!;
|
||||
@@ -206,7 +206,7 @@ public class MatcherMapperTests
|
||||
public void MatcherMapper_Map_Matcher_ProtoBufMatcher()
|
||||
{
|
||||
// Arrange
|
||||
IdOrText protoDefinition = new(null, @"
|
||||
IdOrTexts protoDefinition = new(null, @"
|
||||
syntax = ""proto3"";
|
||||
|
||||
package greet;
|
||||
@@ -235,7 +235,7 @@ message HelloReply {
|
||||
|
||||
// Assert
|
||||
model.Name.Should().Be(nameof(ProtoBufMatcher));
|
||||
model.Pattern.Should().Be(protoDefinition.Text);
|
||||
model.Pattern.Should().Be(protoDefinition.Texts[0]);
|
||||
model.ProtoBufMessageType.Should().Be(messageType);
|
||||
model.ContentMatcher?.Name.Should().Be("JsonMatcher");
|
||||
model.ContentMatcher?.Pattern.Should().Be(jsonPattern);
|
||||
@@ -246,7 +246,7 @@ message HelloReply {
|
||||
{
|
||||
// Arrange
|
||||
string id = "abc123";
|
||||
IdOrText protoDefinition = new(id, @"
|
||||
IdOrTexts protoDefinition = new(id, @"
|
||||
syntax = ""proto3"";
|
||||
|
||||
package greet;
|
||||
@@ -327,7 +327,7 @@ message HelloReply {
|
||||
var model = new MatcherModel
|
||||
{
|
||||
Name = "LinqMatcher",
|
||||
Patterns = new[] { "p1", "p2" }
|
||||
Patterns = ["p1", "p2"]
|
||||
};
|
||||
|
||||
// Act
|
||||
@@ -362,7 +362,7 @@ message HelloReply {
|
||||
{
|
||||
// Assign
|
||||
var pattern = "{ \"post1\": \"value1\", \"post2\": \"value2\" }";
|
||||
var patterns = new[] { pattern };
|
||||
object[] patterns = [pattern];
|
||||
var model = new MatcherModel
|
||||
{
|
||||
Name = "JsonMatcher",
|
||||
@@ -383,7 +383,7 @@ message HelloReply {
|
||||
// Assign
|
||||
var pattern1 = "{ \"AccountIds\": [ 1, 2, 3 ] }";
|
||||
var pattern2 = "{ \"post1\": \"value1\", \"post2\": \"value2\" }";
|
||||
var patterns = new[] { pattern1, pattern2 };
|
||||
object[] patterns = [pattern1, pattern2];
|
||||
var model = new MatcherModel
|
||||
{
|
||||
Name = "JsonMatcher",
|
||||
@@ -690,7 +690,7 @@ message HelloReply {
|
||||
var model = new MatcherModel
|
||||
{
|
||||
Name = "CSharpCodeMatcher",
|
||||
Patterns = new[] { "return it == \"x\";" }
|
||||
Patterns = ["return it == \"x\";"]
|
||||
};
|
||||
var sut = new MatcherMapper(new WireMockServerSettings { AllowCSharpCodeMatcher = true });
|
||||
|
||||
@@ -716,7 +716,7 @@ message HelloReply {
|
||||
var model = new MatcherModel
|
||||
{
|
||||
Name = "CSharpCodeMatcher",
|
||||
Patterns = new[] { "x" }
|
||||
Patterns = ["x"]
|
||||
};
|
||||
var sut = new MatcherMapper(new WireMockServerSettings { AllowCSharpCodeMatcher = false });
|
||||
|
||||
@@ -734,7 +734,7 @@ message HelloReply {
|
||||
var model = new MatcherModel
|
||||
{
|
||||
Name = "ExactMatcher",
|
||||
Patterns = new[] { "x" }
|
||||
Patterns = ["x"]
|
||||
};
|
||||
|
||||
// Act
|
||||
@@ -751,7 +751,7 @@ message HelloReply {
|
||||
var model = new MatcherModel
|
||||
{
|
||||
Name = "ExactMatcher",
|
||||
Patterns = new[] { "x", "y" }
|
||||
Patterns = ["x", "y"]
|
||||
};
|
||||
|
||||
// Act
|
||||
@@ -819,7 +819,7 @@ message HelloReply {
|
||||
var matcher = (ExactObjectMatcher)_sut.Map(model)!;
|
||||
|
||||
// Assert
|
||||
Check.That((byte[])matcher.Value).ContainsExactly(new byte[] { 115, 116, 101, 102 });
|
||||
Check.That((byte[])matcher.Value).ContainsExactly(115, 116, 101, 102);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -846,7 +846,7 @@ message HelloReply {
|
||||
var model = new MatcherModel
|
||||
{
|
||||
Name = "RegexMatcher",
|
||||
Patterns = new[] { "x", "y" },
|
||||
Patterns = ["x", "y"],
|
||||
IgnoreCase = true,
|
||||
MatchOperator = matchOperator.ToString()
|
||||
};
|
||||
@@ -871,7 +871,7 @@ message HelloReply {
|
||||
var model = new MatcherModel
|
||||
{
|
||||
Name = "WildcardMatcher",
|
||||
Patterns = new[] { "x", "y" },
|
||||
Patterns = ["x", "y"],
|
||||
IgnoreCase = true,
|
||||
MatchOperator = matchOperator.ToString()
|
||||
};
|
||||
@@ -1127,7 +1127,7 @@ message HelloReply {
|
||||
var matcher = (ProtoBufMatcher)_sut.Map(model)!;
|
||||
|
||||
// Assert
|
||||
matcher.ProtoDefinition().Text.Should().Be(protoDefinition);
|
||||
matcher.ProtoDefinition().Texts.Should().ContainSingle(protoDefinition);
|
||||
matcher.Name.Should().Be(nameof(ProtoBufMatcher));
|
||||
matcher.MessageType.Should().Be(messageType);
|
||||
matcher.Matcher?.Value.Should().Be(jsonMatcherPattern);
|
||||
|
||||
@@ -759,8 +759,8 @@ public class WireMockServerProxyTests
|
||||
var brokenJpegHeader = new byte[]
|
||||
{0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00};
|
||||
|
||||
bool HasCorrectHeader(byte[] bytes) => bytes.SequenceEqual(jpegHeader);
|
||||
bool HasBrokenHeader(byte[] bytes) => bytes.SequenceEqual(brokenJpegHeader);
|
||||
bool HasCorrectHeader(byte[]? bytes) => bytes?.SequenceEqual(jpegHeader) == true;
|
||||
bool HasBrokenHeader(byte[]? bytes) => bytes?.SequenceEqual(brokenJpegHeader) == true;
|
||||
|
||||
var serverForProxyForwarding = WireMockServer.Start();
|
||||
serverForProxyForwarding
|
||||
|
||||
Reference in New Issue
Block a user