mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-01-11 21:10:32 +01:00
Add GraphQL Schema matching (#964)
* Add GrapQLMatcher * tests * x * . * . * RequestMessageGraphQLMatcher * . * more tests * tests * ... * ms * . * more tests * GraphQL.NET !!! * . * executionResult * nw * sonarcloud
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PATCH/@EntryIndexedValue">PATCH</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=POST/@EntryIndexedValue">POST</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PUT/@EntryIndexedValue">PUT</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=QL/@EntryIndexedValue">QL</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RSA/@EntryIndexedValue">RSA</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SSL/@EntryIndexedValue">SSL</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TE/@EntryIndexedValue">TE</s:String>
|
||||
|
||||
@@ -27,10 +27,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
|
||||
<!--<PackageReference Include="Handlebars.Net.Helpers" Version="2.*" />-->
|
||||
<PackageReference Include="log4net" Version="2.0.15" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -42,6 +42,36 @@ namespace WireMock.Net.ConsoleApplication
|
||||
|
||||
public static class MainApp
|
||||
{
|
||||
private const string TestSchema = @"
|
||||
input MessageInput {
|
||||
content: String
|
||||
author: String
|
||||
}
|
||||
|
||||
type Message {
|
||||
id: ID!
|
||||
content: String
|
||||
author: String
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createMessage(input: MessageInput): Message
|
||||
updateMessage(id: ID!, input: MessageInput): Message
|
||||
}
|
||||
|
||||
type Query {
|
||||
greeting:String
|
||||
students:[Student]
|
||||
studentById(id:ID!):Student
|
||||
}
|
||||
|
||||
type Student {
|
||||
id:ID!
|
||||
firstName:String
|
||||
lastName:String
|
||||
fullName:String
|
||||
}";
|
||||
|
||||
public static void Run()
|
||||
{
|
||||
var mappingBuilder = new MappingBuilder();
|
||||
@@ -137,6 +167,16 @@ namespace WireMock.Net.ConsoleApplication
|
||||
|
||||
// server.AllowPartialMapping();
|
||||
|
||||
server
|
||||
.Given(Request.Create()
|
||||
.WithPath("/graphql")
|
||||
.UsingPost()
|
||||
.WithGraphQLSchema(TestSchema)
|
||||
)
|
||||
.RespondWith(Response.Create()
|
||||
.WithBody("GraphQL is ok")
|
||||
);
|
||||
|
||||
// 400 ms
|
||||
server
|
||||
.Given(Request.Create()
|
||||
|
||||
139
src/WireMock.Net/Matchers/GraphQLMatcher.cs
Normal file
139
src/WireMock.Net/Matchers/GraphQLMatcher.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
#if GRAPHQL
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AnyOfTypes;
|
||||
using GraphQL;
|
||||
using GraphQL.Types;
|
||||
using Newtonsoft.Json;
|
||||
using Stef.Validation;
|
||||
using WireMock.Models;
|
||||
|
||||
namespace WireMock.Matchers;
|
||||
|
||||
/// <summary>
|
||||
/// GrapQLMatcher Schema Matcher
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="IStringMatcher"/>
|
||||
public class GraphQLMatcher : IStringMatcher
|
||||
{
|
||||
private sealed class GraphQLRequest
|
||||
{
|
||||
public string? Query { get; set; }
|
||||
|
||||
public Dictionary<string, object?>? Variables { get; set; }
|
||||
}
|
||||
|
||||
private readonly AnyOf<string, StringPattern>[] _patterns;
|
||||
|
||||
private readonly ISchema _schema;
|
||||
|
||||
/// <inheritdoc />
|
||||
public MatchBehaviour MatchBehaviour { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ThrowException { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="schema">The schema.</param>
|
||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
|
||||
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
||||
public GraphQLMatcher(AnyOf<string, StringPattern, ISchema> schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, bool throwException = false, MatchOperator matchOperator = MatchOperator.Or)
|
||||
{
|
||||
Guard.NotNull(schema);
|
||||
MatchBehaviour = matchBehaviour;
|
||||
ThrowException = throwException;
|
||||
MatchOperator = matchOperator;
|
||||
|
||||
var patterns = new List<AnyOf<string, StringPattern>>();
|
||||
switch (schema.CurrentType)
|
||||
{
|
||||
case AnyOfType.First:
|
||||
patterns.Add(schema.First);
|
||||
_schema = BuildSchema(schema);
|
||||
break;
|
||||
|
||||
case AnyOfType.Second:
|
||||
patterns.Add(schema.Second);
|
||||
_schema = BuildSchema(schema.Second.Pattern);
|
||||
break;
|
||||
|
||||
case AnyOfType.Third:
|
||||
_schema = schema.Third;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
_patterns = patterns.ToArray();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public double IsMatch(string? input)
|
||||
{
|
||||
var match = MatchScores.Mismatch;
|
||||
|
||||
try
|
||||
{
|
||||
var graphQLRequest = JsonConvert.DeserializeObject<GraphQLRequest>(input!)!;
|
||||
|
||||
var executionResult = new DocumentExecuter().ExecuteAsync(_ =>
|
||||
{
|
||||
_.ThrowOnUnhandledException = true;
|
||||
|
||||
_.Schema = _schema;
|
||||
_.Query = graphQLRequest.Query;
|
||||
|
||||
if (graphQLRequest.Variables != null)
|
||||
{
|
||||
_.Variables = new Inputs(graphQLRequest.Variables);
|
||||
}
|
||||
}).GetAwaiter().GetResult();
|
||||
|
||||
if (executionResult.Errors == null || executionResult.Errors.Count == 0)
|
||||
{
|
||||
match = MatchScores.Perfect;
|
||||
}
|
||||
else
|
||||
{
|
||||
var exceptions = executionResult.Errors.OfType<Exception>().ToArray();
|
||||
if (exceptions.Length == 1)
|
||||
{
|
||||
throw exceptions[0];
|
||||
}
|
||||
|
||||
throw new AggregateException(exceptions);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (ThrowException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public AnyOf<string, StringPattern>[] GetPatterns()
|
||||
{
|
||||
return _patterns;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public MatchOperator MatchOperator { get; }
|
||||
|
||||
/// <inheritdoc cref="IMatcher.Name"/>
|
||||
public string Name => nameof(GraphQLMatcher);
|
||||
|
||||
private static ISchema BuildSchema(string schema)
|
||||
{
|
||||
return Schema.For(schema);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -69,7 +69,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
|
||||
MatchOperator = matchOperator;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
|
||||
/// <inheritdoc />
|
||||
public double IsMatch(string? input)
|
||||
{
|
||||
double match = MatchScores.Mismatch;
|
||||
@@ -95,7 +95,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
|
||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
|
||||
/// <inheritdoc />
|
||||
public double IsMatch(object? input)
|
||||
{
|
||||
double match = MatchScores.Mismatch;
|
||||
@@ -110,41 +110,15 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
|
||||
jArray = new JArray { JToken.FromObject(input) };
|
||||
}
|
||||
|
||||
//enumerable = jArray.ToDynamicClassArray();
|
||||
|
||||
//JObject value;
|
||||
//switch (input)
|
||||
//{
|
||||
// case JObject valueAsJObject:
|
||||
// value = valueAsJObject;
|
||||
// break;
|
||||
|
||||
// case { } valueAsObject:
|
||||
// value = JObject.FromObject(valueAsObject);
|
||||
// break;
|
||||
|
||||
// default:
|
||||
// return MatchScores.Mismatch;
|
||||
//}
|
||||
|
||||
// Convert a single object to a Queryable JObject-list with 1 entry.
|
||||
//var queryable1 = new[] { value }.AsQueryable();
|
||||
var queryable = jArray.ToDynamicClassArray().AsQueryable();
|
||||
|
||||
try
|
||||
{
|
||||
// Generate the DynamicLinq select statement.
|
||||
//string dynamicSelect = JsonUtils.GenerateDynamicLinqStatement(value);
|
||||
|
||||
// Execute DynamicLinq Select statement.
|
||||
//var queryable2 = queryable1.Select(dynamicSelect);
|
||||
|
||||
// Use the Any(...) method to check if the result matches.
|
||||
|
||||
var patternsAsStringArray = _patterns.Select(p => p.GetPattern()).ToArray();
|
||||
var scores = patternsAsStringArray.Select(p => queryable.Any(p)).ToArray();
|
||||
|
||||
match = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern.GetPattern())).ToArray(), MatchOperator);
|
||||
match = MatchScores.ToScore(scores, MatchOperator);
|
||||
|
||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||
}
|
||||
@@ -159,7 +133,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
|
||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
|
||||
/// <inheritdoc />
|
||||
public AnyOf<string, StringPattern>[] GetPatterns()
|
||||
{
|
||||
return _patterns;
|
||||
@@ -168,6 +142,6 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
|
||||
/// <inheritdoc />
|
||||
public MatchOperator MatchOperator { get; }
|
||||
|
||||
/// <inheritdoc cref="IMatcher.Name"/>
|
||||
/// <inheritdoc />
|
||||
public string Name => "LinqMatcher";
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using System.Linq;
|
||||
using Stef.Validation;
|
||||
using WireMock.Types;
|
||||
|
||||
namespace WireMock.Matchers.Request;
|
||||
|
||||
/// <summary>
|
||||
/// The request body GraphQL matcher.
|
||||
/// </summary>
|
||||
public class RequestMessageGraphQLMatcher : IRequestMatcher
|
||||
{
|
||||
/// <summary>
|
||||
/// The matchers.
|
||||
/// </summary>
|
||||
public IMatcher[]? Matchers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="MatchOperator"/>
|
||||
/// </summary>
|
||||
public MatchOperator MatchOperator { get; } = MatchOperator.Or;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageGraphQLMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||
/// <param name="schema">The schema.</param>
|
||||
public RequestMessageGraphQLMatcher(MatchBehaviour matchBehaviour, string schema) :
|
||||
this(CreateMatcherArray(matchBehaviour, schema))
|
||||
{
|
||||
}
|
||||
|
||||
#if GRAPHQL
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageGraphQLMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||
/// <param name="schema">The schema.</param>
|
||||
public RequestMessageGraphQLMatcher(MatchBehaviour matchBehaviour, GraphQL.Types.ISchema schema) :
|
||||
this(CreateMatcherArray(matchBehaviour, new AnyOfTypes.AnyOf<string, Models.StringPattern, GraphQL.Types.ISchema>(schema)))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageGraphQLMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="matchers">The matchers.</param>
|
||||
public RequestMessageGraphQLMatcher(params IMatcher[] matchers)
|
||||
{
|
||||
Matchers = Guard.NotNull(matchers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageGraphQLMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="matchers">The matchers.</param>
|
||||
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
|
||||
public RequestMessageGraphQLMatcher(MatchOperator matchOperator, params IMatcher[] matchers)
|
||||
{
|
||||
Matchers = Guard.NotNull(matchers);
|
||||
MatchOperator = matchOperator;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
var score = CalculateMatchScore(requestMessage);
|
||||
return requestMatchResult.AddScore(GetType(), score);
|
||||
}
|
||||
|
||||
private static double CalculateMatchScore(IRequestMessage requestMessage, IMatcher matcher)
|
||||
{
|
||||
// Check if the matcher is a IStringMatcher
|
||||
// If the body is a Json or a String, use the BodyAsString to match on.
|
||||
if (matcher is IStringMatcher stringMatcher && requestMessage.BodyData?.DetectedBodyType is BodyType.Json or BodyType.String or BodyType.FormUrlEncoded)
|
||||
{
|
||||
return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
|
||||
}
|
||||
|
||||
return MatchScores.Mismatch;
|
||||
}
|
||||
|
||||
private double CalculateMatchScore(IRequestMessage requestMessage)
|
||||
{
|
||||
if (Matchers == null)
|
||||
{
|
||||
return MatchScores.Mismatch;
|
||||
}
|
||||
|
||||
var matchersResult = Matchers.Select(matcher => CalculateMatchScore(requestMessage, matcher)).ToArray();
|
||||
return MatchScores.ToScore(matchersResult, MatchOperator);
|
||||
}
|
||||
|
||||
#if GRAPHQL
|
||||
private static IMatcher[] CreateMatcherArray(MatchBehaviour matchBehaviour, AnyOfTypes.AnyOf<string, Models.StringPattern, GraphQL.Types.ISchema> schema)
|
||||
{
|
||||
return new[] { new GraphQLMatcher(schema, matchBehaviour) }.Cast<IMatcher>().ToArray();
|
||||
}
|
||||
#else
|
||||
private static IMatcher[] CreateMatcherArray(MatchBehaviour matchBehaviour, object schema)
|
||||
{
|
||||
throw new System.NotSupportedException("The GrapQLMatcher can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -10,7 +10,7 @@ namespace WireMock.RequestBuilders;
|
||||
/// <summary>
|
||||
/// The BodyRequestBuilder interface.
|
||||
/// </summary>
|
||||
public interface IBodyRequestBuilder : IRequestMatcher
|
||||
public interface IBodyRequestBuilder : IGraphQLRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// WithBody: IMatcher
|
||||
@@ -103,4 +103,12 @@ public interface IBodyRequestBuilder : IRequestMatcher
|
||||
/// <param name="func">The form-urlencoded values.</param>
|
||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||
IRequestBuilder WithBody(Func<IDictionary<string, string>?, bool> func);
|
||||
|
||||
/// <summary>
|
||||
/// WithBodyAsGraphQLSchema: Body as GraphQL schema as a string.
|
||||
/// </summary>
|
||||
/// <param name="body">The GraphQL schema.</param>
|
||||
/// <param name="matchBehaviour">The match behaviour. (Default is <c>MatchBehaviour.AcceptOnMatch</c>).</param>
|
||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||
IRequestBuilder WithBodyAsGraphQLSchema(string body, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
||||
}
|
||||
28
src/WireMock.Net/RequestBuilders/IGraphQLRequestBuilder.cs
Normal file
28
src/WireMock.Net/RequestBuilders/IGraphQLRequestBuilder.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.RequestBuilders;
|
||||
|
||||
/// <summary>
|
||||
/// The GraphQLRequestBuilder interface.
|
||||
/// </summary>
|
||||
public interface IGraphQLRequestBuilder : IRequestMatcher
|
||||
{
|
||||
/// <summary>
|
||||
/// WithGraphQLSchema: The GraphQL schema as a string.
|
||||
/// </summary>
|
||||
/// <param name="schema">The GraphQL schema.</param>
|
||||
/// <param name="matchBehaviour">The match behaviour. (Default is <c>MatchBehaviour.AcceptOnMatch</c>).</param>
|
||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||
IRequestBuilder WithGraphQLSchema(string schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
||||
|
||||
#if GRAPHQL
|
||||
/// <summary>
|
||||
/// WithGraphQLSchema: The GraphQL schema as a ISchema.
|
||||
/// </summary>
|
||||
/// <param name="schema">The GraphQL schema.</param>
|
||||
/// <param name="matchBehaviour">The match behaviour. (Default is <c>MatchBehaviour.AcceptOnMatch</c>).</param>
|
||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||
IRequestBuilder WithGraphQLSchema(GraphQL.Types.ISchema schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
||||
#endif
|
||||
}
|
||||
@@ -109,4 +109,10 @@ public partial class Request
|
||||
_requestMatchers.Add(new RequestMessageBodyMatcher(Guard.NotNull(func)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IRequestBuilder WithBodyAsGraphQLSchema(string body, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||
{
|
||||
return WithGraphQLSchema(body, matchBehaviour);
|
||||
}
|
||||
}
|
||||
23
src/WireMock.Net/RequestBuilders/Request.WithGraphQL.cs
Normal file
23
src/WireMock.Net/RequestBuilders/Request.WithGraphQL.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.RequestBuilders;
|
||||
|
||||
public partial class Request
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IRequestBuilder WithGraphQLSchema(string schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageGraphQLMatcher(matchBehaviour, schema));
|
||||
return this;
|
||||
}
|
||||
|
||||
#if GRAPHQL
|
||||
/// <inheritdoc />
|
||||
public IRequestBuilder WithGraphQLSchema(GraphQL.Types.ISchema schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageGraphQLMatcher(matchBehaviour, schema));
|
||||
return this;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -46,7 +46,8 @@ internal class MappingConverter
|
||||
var cookieMatchers = request.GetRequestMessageMatchers<RequestMessageCookieMatcher>();
|
||||
var paramsMatchers = request.GetRequestMessageMatchers<RequestMessageParamMatcher>();
|
||||
var methodMatcher = request.GetRequestMessageMatcher<RequestMessageMethodMatcher>();
|
||||
var bodyMatcher = request.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
|
||||
var requestMessageBodyMatcher = request.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
|
||||
var requestMessageGraphQLMatcher = request.GetRequestMessageMatcher<RequestMessageGraphQLMatcher>();
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
@@ -105,13 +106,23 @@ internal class MappingConverter
|
||||
sb.AppendLine($" .WithCookie(\"{cookieMatcher.Name}\", {ToValueArguments(GetStringArray(cookieMatcher.Matchers!))}, true)");
|
||||
}
|
||||
|
||||
if (bodyMatcher is { Matchers: { } })
|
||||
#if GRAPHQL
|
||||
if (requestMessageGraphQLMatcher is { Matchers: { } })
|
||||
{
|
||||
if (bodyMatcher.Matchers.OfType<WildcardMatcher>().FirstOrDefault() is { } wildcardMatcher && wildcardMatcher.GetPatterns().Any())
|
||||
if (requestMessageGraphQLMatcher.Matchers.OfType<GraphQLMatcher>().FirstOrDefault() is { } graphQLMatcher && graphQLMatcher.GetPatterns().Any())
|
||||
{
|
||||
sb.AppendLine($" .WithGraphQLSchema({GetString(graphQLMatcher)})");
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (requestMessageBodyMatcher is { Matchers: { } })
|
||||
{
|
||||
if (requestMessageBodyMatcher.Matchers.OfType<WildcardMatcher>().FirstOrDefault() is { } wildcardMatcher && wildcardMatcher.GetPatterns().Any())
|
||||
{
|
||||
sb.AppendLine($" .WithBody({GetString(wildcardMatcher)})");
|
||||
}
|
||||
else if (bodyMatcher.Matchers.OfType<JsonPartialMatcher>().FirstOrDefault() is { Value: { } } jsonPartialMatcher)
|
||||
else if (requestMessageBodyMatcher.Matchers.OfType<JsonPartialMatcher>().FirstOrDefault() is { Value: { } } jsonPartialMatcher)
|
||||
{
|
||||
sb.AppendLine(@$" .WithBody(new JsonPartialMatcher(
|
||||
value: {ToCSharpStringLiteral(jsonPartialMatcher.Value.ToString())},
|
||||
@@ -120,7 +131,7 @@ internal class MappingConverter
|
||||
regex: {ToCSharpBooleanLiteral(jsonPartialMatcher.Regex)}
|
||||
))");
|
||||
}
|
||||
else if (bodyMatcher.Matchers.OfType<JsonPartialWildcardMatcher>().FirstOrDefault() is { Value: { } } jsonPartialWildcardMatcher)
|
||||
else if (requestMessageBodyMatcher.Matchers.OfType<JsonPartialWildcardMatcher>().FirstOrDefault() is { Value: { } } jsonPartialWildcardMatcher)
|
||||
{
|
||||
sb.AppendLine(@$" .WithBody(new JsonPartialWildcardMatcher(
|
||||
value: {ToCSharpStringLiteral(jsonPartialWildcardMatcher.Value.ToString())},
|
||||
@@ -216,6 +227,7 @@ internal class MappingConverter
|
||||
var paramsMatchers = request.GetRequestMessageMatchers<RequestMessageParamMatcher>();
|
||||
var methodMatcher = request.GetRequestMessageMatcher<RequestMessageMethodMatcher>();
|
||||
var bodyMatcher = request.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
|
||||
var graphQLMatcher = request.GetRequestMessageMatcher<RequestMessageGraphQLMatcher>();
|
||||
|
||||
var mappingModel = new MappingModel
|
||||
{
|
||||
@@ -301,7 +313,7 @@ internal class MappingConverter
|
||||
mappingModel.Response.Delay = (int?)(response.Delay == Timeout.InfiniteTimeSpan ? TimeSpan.MaxValue.TotalMilliseconds : response.Delay?.TotalMilliseconds);
|
||||
}
|
||||
|
||||
var nonNullableWebHooks = mapping.Webhooks?.Where(wh => wh != null).ToArray() ?? new IWebhook[0];
|
||||
var nonNullableWebHooks = mapping.Webhooks?.Where(wh => wh != null).ToArray() ?? EmptyArray<IWebhook>.Value;
|
||||
if (nonNullableWebHooks.Length == 1)
|
||||
{
|
||||
mappingModel.Webhook = WebhookMapper.Map(nonNullableWebHooks[0]);
|
||||
@@ -311,18 +323,20 @@ internal class MappingConverter
|
||||
mappingModel.Webhooks = mapping.Webhooks.Select(WebhookMapper.Map).ToArray();
|
||||
}
|
||||
|
||||
if (bodyMatcher?.Matchers != null)
|
||||
var graphQLOrBodyMatchers = graphQLMatcher?.Matchers ?? bodyMatcher?.Matchers;
|
||||
var matchOperator = graphQLMatcher?.MatchOperator ?? bodyMatcher?.MatchOperator;
|
||||
if (graphQLOrBodyMatchers != null && matchOperator != null)
|
||||
{
|
||||
mappingModel.Request.Body = new BodyModel();
|
||||
|
||||
if (bodyMatcher.Matchers.Length == 1)
|
||||
if (graphQLOrBodyMatchers.Length == 1)
|
||||
{
|
||||
mappingModel.Request.Body.Matcher = _mapper.Map(bodyMatcher.Matchers[0]);
|
||||
mappingModel.Request.Body.Matcher = _mapper.Map(graphQLOrBodyMatchers[0]);
|
||||
}
|
||||
else if (bodyMatcher.Matchers.Length > 1)
|
||||
else if (graphQLOrBodyMatchers.Length > 1)
|
||||
{
|
||||
mappingModel.Request.Body.Matchers = _mapper.Map(bodyMatcher.Matchers);
|
||||
mappingModel.Request.Body.MatchOperator = bodyMatcher.MatchOperator.ToString();
|
||||
mappingModel.Request.Body.Matchers = _mapper.Map(graphQLOrBodyMatchers);
|
||||
mappingModel.Request.Body.MatchOperator = matchOperator.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,10 @@ internal class MatcherMapper
|
||||
|
||||
case nameof(ExactObjectMatcher):
|
||||
return CreateExactObjectMatcher(matchBehaviour, stringPatterns[0], throwExceptionWhenMatcherFails);
|
||||
|
||||
#if GRAPHQL
|
||||
case nameof(GraphQLMatcher):
|
||||
return new GraphQLMatcher(stringPatterns[0].GetPattern(), matchBehaviour, throwExceptionWhenMatcherFails, matchOperator);
|
||||
#endif
|
||||
case nameof(RegexMatcher):
|
||||
return new RegexMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails, useRegexExtended, matchOperator);
|
||||
|
||||
|
||||
@@ -50,16 +50,19 @@
|
||||
<DefineConstants>$(DefineConstants);OPENAPIPARSER</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
|
||||
<DefineConstants>$(DefineConstants);GRAPHQL</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Util\FileSystemWatcherExtensions.cs" />
|
||||
<Compile Remove="Matchers\Request\IRequestMatcher.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" PrivateAssets="All" />
|
||||
<PackageReference Include="JsonConverter.Abstractions" Version="0.4.0" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="NJsonSchema.Extensions" Version="0.1.0" />
|
||||
<PackageReference Include="NSwag.Core" Version="13.16.1" />
|
||||
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
|
||||
@@ -154,6 +157,11 @@
|
||||
<PackageReference Include="Scriban.Signed" Version="5.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
|
||||
<PackageReference Include="GraphQL" Version="7.5.0" />
|
||||
<PackageReference Include="GraphQL.NewtonsoftJson" Version="7.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
|
||||
<PackageReference Include="Nullable" Version="1.3.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
142
test/WireMock.Net.Tests/Matchers/GraphQLMatcherTests.cs
Normal file
142
test/WireMock.Net.Tests/Matchers/GraphQLMatcherTests.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
#if GRAPHQL
|
||||
using System;
|
||||
using FluentAssertions;
|
||||
using GraphQLParser.Exceptions;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace WireMock.Net.Tests.Matchers;
|
||||
|
||||
public class GraphQLMatcherTests
|
||||
{
|
||||
private const string TestSchema = @"
|
||||
input MessageInput {
|
||||
content: String
|
||||
author: String
|
||||
}
|
||||
|
||||
type Message {
|
||||
id: ID!
|
||||
content: String
|
||||
author: String
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createMessage(input: MessageInput): Message
|
||||
updateMessage(id: ID!, input: MessageInput): Message
|
||||
}
|
||||
|
||||
type Query {
|
||||
greeting:String
|
||||
students:[Student]
|
||||
studentById(id:ID!):Student
|
||||
}
|
||||
|
||||
type Student {
|
||||
id:ID!
|
||||
firstName:String
|
||||
lastName:String
|
||||
fullName:String
|
||||
}";
|
||||
|
||||
[Fact]
|
||||
public void GraphQLMatcher_For_ValidSchema_And_CorrectQuery_IsMatch()
|
||||
{
|
||||
// Arrange
|
||||
var input = "{\"query\":\"{\\r\\n students {\\r\\n fullName\\r\\n id\\r\\n }\\r\\n}\"}";
|
||||
|
||||
// Act
|
||||
var matcher = new GraphQLMatcher(TestSchema);
|
||||
var result = matcher.IsMatch(input);
|
||||
|
||||
// Assert
|
||||
result.Should().Be(MatchScores.Perfect);
|
||||
|
||||
matcher.GetPatterns().Should().Contain(TestSchema);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GraphQLMatcher_For_ValidSchema_And_CorrectGraphQLQuery_IsMatch()
|
||||
{
|
||||
// Arrange
|
||||
var input = @"{
|
||||
""query"": ""query ($sid: ID!)\r\n{\r\n studentById(id: $sid) {\r\n fullName\r\n id\r\n }\r\n}"",
|
||||
""variables"": {
|
||||
""sid"": ""1""
|
||||
}
|
||||
}";
|
||||
// Act
|
||||
var matcher = new GraphQLMatcher(TestSchema);
|
||||
var result = matcher.IsMatch(input);
|
||||
|
||||
// Assert
|
||||
result.Should().Be(MatchScores.Perfect);
|
||||
|
||||
matcher.GetPatterns().Should().Contain(TestSchema);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GraphQLMatcher_For_ValidSchema_And_IncorrectQuery_IsMismatch()
|
||||
{
|
||||
// Arrange
|
||||
var input = @"
|
||||
{
|
||||
students {
|
||||
fullName
|
||||
id
|
||||
abc
|
||||
}
|
||||
}";
|
||||
// Act
|
||||
var matcher = new GraphQLMatcher(TestSchema);
|
||||
var result = matcher.IsMatch(input);
|
||||
|
||||
// Assert
|
||||
result.Should().Be(MatchScores.Mismatch);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GraphQLMatcher_For_ValidSchemaAsStringPattern_And_CorrectQuery_IsMatch()
|
||||
{
|
||||
// Arrange
|
||||
var input = "{\"query\":\"{\\r\\n students {\\r\\n fullName\\r\\n id\\r\\n }\\r\\n}\"}";
|
||||
var schema = new StringPattern
|
||||
{
|
||||
Pattern = TestSchema
|
||||
};
|
||||
|
||||
// Act
|
||||
var matcher = new GraphQLMatcher(schema);
|
||||
var result = matcher.IsMatch(input);
|
||||
|
||||
// Assert
|
||||
result.Should().Be(MatchScores.Perfect);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GraphQLMatcher_For_ValidSchema_And_IncorrectQueryWithError_WithThrowExceptionTrue_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
var input = "{\"query\":\"{\\r\\n studentsX {\\r\\n fullName\\r\\n X\\r\\n }\\r\\n}\"}";
|
||||
|
||||
// Act
|
||||
var matcher = new GraphQLMatcher(TestSchema, MatchBehaviour.AcceptOnMatch, true);
|
||||
Action action = () => matcher.IsMatch(input);
|
||||
|
||||
// Assert
|
||||
action.Should().Throw<Exception>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GraphQLMatcher_For_InvalidSchema_ThrowsGraphQLSyntaxErrorException()
|
||||
{
|
||||
// Act
|
||||
// ReSharper disable once ObjectCreationAsStatement
|
||||
Action action = () => _ = new GraphQLMatcher("in va lid");
|
||||
|
||||
// Assert
|
||||
action.Should().Throw<GraphQLSyntaxErrorException>();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
#if GRAPHQL
|
||||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using GraphQL.Types;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.RequestBuilders;
|
||||
using Xunit;
|
||||
|
||||
namespace WireMock.Net.Tests.RequestBuilders;
|
||||
|
||||
public class RequestBuilderWithGraphQLSchemaTests
|
||||
{
|
||||
private const string TestSchema = @"
|
||||
input MessageInput {
|
||||
content: String
|
||||
author: String
|
||||
}
|
||||
|
||||
type Message {
|
||||
id: ID!
|
||||
content: String
|
||||
author: String
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createMessage(input: MessageInput): Message
|
||||
updateMessage(id: ID!, input: MessageInput): Message
|
||||
}
|
||||
|
||||
type Query {
|
||||
greeting:String
|
||||
students:[Student]
|
||||
studentById(id:ID!):Student
|
||||
}
|
||||
|
||||
type Student {
|
||||
id:ID!
|
||||
firstName:String
|
||||
lastName:String
|
||||
fullName:String
|
||||
}";
|
||||
|
||||
[Fact]
|
||||
public void RequestBuilder_WithGraphQLSchema_SchemaAsString()
|
||||
{
|
||||
// Act
|
||||
var requestBuilder = (Request)Request.Create().WithGraphQLSchema(TestSchema);
|
||||
|
||||
// Assert
|
||||
var matchers = requestBuilder.GetPrivateFieldValue<IList<IRequestMatcher>>("_requestMatchers");
|
||||
matchers.Should().HaveCount(1);
|
||||
((RequestMessageGraphQLMatcher)matchers[0]).Matchers.Should().ContainItemsAssignableTo<GraphQLMatcher>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RequestBuilder_WithGraphQLSchema_SchemaAsISchema()
|
||||
{
|
||||
// Arrange
|
||||
var schema = Schema.For(TestSchema);
|
||||
|
||||
// Act
|
||||
var requestBuilder = (Request)Request.Create().WithGraphQLSchema(schema);
|
||||
|
||||
// Assert
|
||||
var matchers = requestBuilder.GetPrivateFieldValue<IList<IRequestMatcher>>("_requestMatchers");
|
||||
matchers.Should().HaveCount(1);
|
||||
((RequestMessageGraphQLMatcher)matchers[0]).Matchers.Should().ContainItemsAssignableTo<GraphQLMatcher>();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,194 @@
|
||||
#if GRAPHQL
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Models;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
using Xunit;
|
||||
|
||||
namespace WireMock.Net.Tests.RequestMatchers;
|
||||
|
||||
public class RequestMessageGraphQLMatcherTests
|
||||
{
|
||||
[Fact]
|
||||
public void RequestMessageGraphQLMatcher_GetMatchingScore_BodyAsString_IStringMatcher()
|
||||
{
|
||||
// Assign
|
||||
var body = new BodyData
|
||||
{
|
||||
BodyAsString = "b",
|
||||
DetectedBodyType = BodyType.String
|
||||
};
|
||||
var stringMatcherMock = new Mock<IStringMatcher>();
|
||||
stringMatcherMock.Setup(m => m.IsMatch(It.IsAny<string>())).Returns(1d);
|
||||
|
||||
var requestMessage = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.1", body);
|
||||
|
||||
var matcher = new RequestMessageGraphQLMatcher(stringMatcherMock.Object);
|
||||
|
||||
// Act
|
||||
var result = new RequestMatchResult();
|
||||
double score = matcher.GetMatchingScore(requestMessage, result);
|
||||
|
||||
// Assert
|
||||
score.Should().Be(MatchScores.Perfect);
|
||||
|
||||
// Verify
|
||||
stringMatcherMock.Verify(m => m.GetPatterns(), Times.Never);
|
||||
stringMatcherMock.Verify(m => m.IsMatch("b"), Times.Once);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1d, 1d, 1d)]
|
||||
[InlineData(0d, 1d, 1d)]
|
||||
[InlineData(1d, 0d, 1d)]
|
||||
[InlineData(0d, 0d, 0d)]
|
||||
public void RequestMessageGraphQLMatcher_GetMatchingScore_BodyAsString_IStringMatchers_Or(double one, double two, double expected)
|
||||
{
|
||||
// Assign
|
||||
var body = new BodyData
|
||||
{
|
||||
BodyAsString = "b",
|
||||
DetectedBodyType = BodyType.String
|
||||
};
|
||||
var stringMatcherMock1 = new Mock<IStringMatcher>();
|
||||
stringMatcherMock1.Setup(m => m.IsMatch(It.IsAny<string>())).Returns(one);
|
||||
|
||||
var stringMatcherMock2 = new Mock<IStringMatcher>();
|
||||
stringMatcherMock2.Setup(m => m.IsMatch(It.IsAny<string>())).Returns(two);
|
||||
|
||||
var matchers = new[] { stringMatcherMock1.Object, stringMatcherMock2.Object };
|
||||
|
||||
var requestMessage = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.1", body);
|
||||
|
||||
var matcher = new RequestMessageGraphQLMatcher(MatchOperator.Or, matchers.Cast<IMatcher>().ToArray());
|
||||
|
||||
// Act
|
||||
var result = new RequestMatchResult();
|
||||
double score = matcher.GetMatchingScore(requestMessage, result);
|
||||
|
||||
// Assert
|
||||
score.Should().Be(expected);
|
||||
|
||||
// Verify
|
||||
stringMatcherMock1.Verify(m => m.GetPatterns(), Times.Never);
|
||||
stringMatcherMock1.Verify(m => m.IsMatch("b"), Times.Once);
|
||||
|
||||
stringMatcherMock2.Verify(m => m.GetPatterns(), Times.Never);
|
||||
stringMatcherMock2.Verify(m => m.IsMatch("b"), Times.Once);
|
||||
stringMatcherMock2.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1d, 1d, 1d)]
|
||||
[InlineData(0d, 1d, 0d)]
|
||||
[InlineData(1d, 0d, 0d)]
|
||||
[InlineData(0d, 0d, 0d)]
|
||||
public void RequestMessageGraphQLMatcher_GetMatchingScore_BodyAsString_IStringMatchers_And(double one, double two, double expected)
|
||||
{
|
||||
// Assign
|
||||
var body = new BodyData
|
||||
{
|
||||
BodyAsString = "b",
|
||||
DetectedBodyType = BodyType.String
|
||||
};
|
||||
var stringMatcherMock1 = new Mock<IStringMatcher>();
|
||||
stringMatcherMock1.Setup(m => m.IsMatch(It.IsAny<string>())).Returns(one);
|
||||
|
||||
var stringMatcherMock2 = new Mock<IStringMatcher>();
|
||||
stringMatcherMock2.Setup(m => m.IsMatch(It.IsAny<string>())).Returns(two);
|
||||
|
||||
var matchers = new[] { stringMatcherMock1.Object, stringMatcherMock2.Object };
|
||||
|
||||
var requestMessage = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.1", body);
|
||||
|
||||
var matcher = new RequestMessageGraphQLMatcher(MatchOperator.And, matchers.Cast<IMatcher>().ToArray());
|
||||
|
||||
// Act
|
||||
var result = new RequestMatchResult();
|
||||
double score = matcher.GetMatchingScore(requestMessage, result);
|
||||
|
||||
// Assert
|
||||
score.Should().Be(expected);
|
||||
|
||||
// Verify
|
||||
stringMatcherMock1.Verify(m => m.GetPatterns(), Times.Never);
|
||||
stringMatcherMock1.Verify(m => m.IsMatch("b"), Times.Once);
|
||||
|
||||
stringMatcherMock2.Verify(m => m.GetPatterns(), Times.Never);
|
||||
stringMatcherMock2.Verify(m => m.IsMatch("b"), Times.Once);
|
||||
stringMatcherMock2.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1d, 1d, 1d)]
|
||||
[InlineData(0d, 1d, 0.5d)]
|
||||
[InlineData(1d, 0d, 0.5d)]
|
||||
[InlineData(0d, 0d, 0d)]
|
||||
public void RequestMessageGraphQLMatcher_GetMatchingScore_BodyAsString_IStringMatchers_Average(double one, double two, double expected)
|
||||
{
|
||||
// Assign
|
||||
var body = new BodyData
|
||||
{
|
||||
BodyAsString = "b",
|
||||
DetectedBodyType = BodyType.String
|
||||
};
|
||||
var stringMatcherMock1 = new Mock<IStringMatcher>();
|
||||
stringMatcherMock1.Setup(m => m.IsMatch(It.IsAny<string>())).Returns(one);
|
||||
|
||||
var stringMatcherMock2 = new Mock<IStringMatcher>();
|
||||
stringMatcherMock2.Setup(m => m.IsMatch(It.IsAny<string>())).Returns(two);
|
||||
|
||||
var matchers = new[] { stringMatcherMock1.Object, stringMatcherMock2.Object };
|
||||
|
||||
var requestMessage = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.1", body);
|
||||
|
||||
var matcher = new RequestMessageGraphQLMatcher(MatchOperator.Average, matchers.Cast<IMatcher>().ToArray());
|
||||
|
||||
// Act
|
||||
var result = new RequestMatchResult();
|
||||
double score = matcher.GetMatchingScore(requestMessage, result);
|
||||
|
||||
// Assert
|
||||
score.Should().Be(expected);
|
||||
|
||||
// Verify
|
||||
stringMatcherMock1.Verify(m => m.GetPatterns(), Times.Never);
|
||||
stringMatcherMock1.Verify(m => m.IsMatch("b"), Times.Once);
|
||||
|
||||
stringMatcherMock2.Verify(m => m.GetPatterns(), Times.Never);
|
||||
stringMatcherMock2.Verify(m => m.IsMatch("b"), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RequestMessageGraphQLMatcher_GetMatchingScore_BodyAsBytes_IStringMatcher_ReturnMisMatch()
|
||||
{
|
||||
// Assign
|
||||
var body = new BodyData
|
||||
{
|
||||
BodyAsBytes = new byte[] { 1 },
|
||||
DetectedBodyType = BodyType.Bytes
|
||||
};
|
||||
var stringMatcherMock = new Mock<IStringMatcher>();
|
||||
stringMatcherMock.Setup(m => m.IsMatch(It.IsAny<string>())).Returns(0.5d);
|
||||
|
||||
var requestMessage = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.1", body);
|
||||
|
||||
var matcher = new RequestMessageGraphQLMatcher(stringMatcherMock.Object);
|
||||
|
||||
// Act
|
||||
var result = new RequestMatchResult();
|
||||
double score = matcher.GetMatchingScore(requestMessage, result);
|
||||
|
||||
// Assert
|
||||
score.Should().Be(MatchScores.Mismatch);
|
||||
|
||||
// Verify
|
||||
stringMatcherMock.Verify(m => m.GetPatterns(), Times.Never);
|
||||
stringMatcherMock.Verify(m => m.IsMatch(It.IsAny<string>()), Times.Never);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
Guid: Guid_1,
|
||||
UpdatedAt: DateTime_1,
|
||||
Title: ,
|
||||
Description: ,
|
||||
Priority: 42,
|
||||
Request: {
|
||||
Body: {
|
||||
Matcher: {
|
||||
Name: GraphQLMatcher,
|
||||
Pattern:
|
||||
type Query {
|
||||
greeting:String
|
||||
students:[Student]
|
||||
studentById(id:ID!):Student
|
||||
}
|
||||
|
||||
type Student {
|
||||
id:ID!
|
||||
firstName:String
|
||||
lastName:String
|
||||
fullName:String
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Response: {},
|
||||
UseWebhooksFireAndForget: false
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
Guid: Guid_1,
|
||||
UpdatedAt: DateTime_1,
|
||||
Title: ,
|
||||
Description: ,
|
||||
Priority: 42,
|
||||
Request: {
|
||||
Path: {
|
||||
Matchers: [
|
||||
{
|
||||
Name: WildcardMatcher,
|
||||
Pattern: 1.2.3.4,
|
||||
IgnoreCase: false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
Response: {},
|
||||
UseWebhooksFireAndForget: false
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -260,7 +260,7 @@ public partial class MappingConverterTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task ToMappingModel_WithDelayAsMilliSeconds_ReturnsCorrectModel()
|
||||
public Task ToMappingModel_WithDelay_ReturnsCorrectModel()
|
||||
{
|
||||
// Assign
|
||||
var delay = 1000;
|
||||
@@ -343,5 +343,56 @@ public partial class MappingConverterTests
|
||||
// Verify
|
||||
return Verifier.Verify(model);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task ToMappingModel_Request_WithClientIP_ReturnsCorrectModel()
|
||||
{
|
||||
// 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);
|
||||
|
||||
// Act
|
||||
var model = _sut.ToMappingModel(mapping);
|
||||
|
||||
// Assert
|
||||
model.Should().NotBeNull();
|
||||
|
||||
// Verify
|
||||
return Verifier.Verify(model);
|
||||
}
|
||||
|
||||
#if GRAPHQL
|
||||
[Fact]
|
||||
public Task ToMappingModel_Request_WithBodyAsGraphQLSchema_ReturnsCorrectModel()
|
||||
{
|
||||
// Arrange
|
||||
var schema = @"
|
||||
type Query {
|
||||
greeting:String
|
||||
students:[Student]
|
||||
studentById(id:ID!):Student
|
||||
}
|
||||
|
||||
type Student {
|
||||
id:ID!
|
||||
firstName:String
|
||||
lastName:String
|
||||
fullName:String
|
||||
}";
|
||||
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);
|
||||
|
||||
// Act
|
||||
var model = _sut.ToMappingModel(mapping);
|
||||
|
||||
// Assert
|
||||
model.Should().NotBeNull();
|
||||
|
||||
// Verify
|
||||
return Verifier.Verify(model);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -24,6 +24,10 @@
|
||||
<DefineConstants>NETFRAMEWORK</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
|
||||
<DefineConstants>$(DefineConstants);GRAPHQL</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Util\JsonUtilsTests.cs" />
|
||||
</ItemGroup>
|
||||
@@ -65,7 +69,6 @@
|
||||
<PackageReference Include="Moq" Version="4.17.2" />
|
||||
<PackageReference Include="System.Threading" Version="4.3.0" />
|
||||
<PackageReference Include="RestEase" Version="1.5.7" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="NFluent" Version="2.8.0" />
|
||||
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
|
||||
<PackageReference Include="AnyOf" Version="0.3.0" />
|
||||
|
||||
Reference in New Issue
Block a user