Compare commits

..

7 Commits

Author SHA1 Message Date
Stef Heyenrath
29e149a7fa 1.5.40 2023-11-07 18:03:34 +01:00
Stef Heyenrath
7160dbdd19 FluentAssertions - WithBody and WithBodyAsJson and WithBodyAsBytes (#1014)
* WithBody

* .

* fix

* .

* .
2023-11-04 16:17:23 +01:00
Stef Heyenrath
2f29d80336 Add more tests for JmesPathMatchers and StringUtils.ParseMatchOperator (#1009)
* Add more tests for JmesPathMatchers and StringUtils.ParseMatchOperator

* .

* prio
2023-10-16 17:13:52 +02:00
Stef Heyenrath
f7cd4b100e GraphQL - add support for standard scalar types in the schema (#1011)
* GraphQL: register BuiltInTypes

* GraphQLMatcher_For_ValidSchema_And_CorrectGraphQL_Mutation_IsMatch
2023-10-16 16:13:53 +02:00
Stef Heyenrath
62fa4666b5 Add unit tests for HttpClient with WebProxy (#1010)
* Add test for SSL / Https

* Add unit tests for HttpClient with WebProxy

* cert.pem

* x

* skip

* example google

* revert

* host tests

* sonar
2023-10-14 17:55:29 +02:00
Stef Heyenrath
30372a9348 1.5.39 2023-10-09 18:30:19 +02:00
Stef Heyenrath
bc75db8c8c Fix RequestMessageParamMatcher : RejectOnMatch (#1006) 2023-10-09 18:28:22 +02:00
34 changed files with 958 additions and 159 deletions

View File

@@ -1,3 +1,13 @@
# 1.5.40 (07 November 2023)
- [#1009](https://github.com/WireMock-Net/WireMock.Net/pull/1009) - Add more tests for JmesPathMatchers and StringUtils.ParseMatchOperator [test] contributed by [StefH](https://github.com/StefH)
- [#1010](https://github.com/WireMock-Net/WireMock.Net/pull/1010) - Add unit tests for HttpClient with WebProxy [test] contributed by [StefH](https://github.com/StefH)
- [#1011](https://github.com/WireMock-Net/WireMock.Net/pull/1011) - GraphQL - add support for standard scalar types in the schema [feature] contributed by [StefH](https://github.com/StefH)
- [#1014](https://github.com/WireMock-Net/WireMock.Net/pull/1014) - FluentAssertions - WithBody and WithBodyAsJson and WithBodyAsBytes contributed by [StefH](https://github.com/StefH)
# 1.5.39 (09 October 2023)
- [#1006](https://github.com/WireMock-Net/WireMock.Net/pull/1006) - Fix RequestMessageParamMatcher : RejectOnMatch [bug] contributed by [StefH](https://github.com/StefH)
- [#997](https://github.com/WireMock-Net/WireMock.Net/issues/997) - JmesPathMatcher or and MatchOperator working in version 1.5.34 but not 1.5.35 [bug]
# 1.5.38 (02 October 2023)
- [#1005](https://github.com/WireMock-Net/WireMock.Net/pull/1005) - Support for xml namespaces in XPathMatcher [feature] contributed by [cal-schleupen](https://github.com/cal-schleupen)

View File

@@ -4,7 +4,7 @@
</PropertyGroup>
<PropertyGroup>
<VersionPrefix>1.5.38</VersionPrefix>
<VersionPrefix>1.5.40</VersionPrefix>
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>

View File

@@ -1,6 +1,6 @@
rem https://github.com/StefH/GitHubReleaseNotes
SET version=1.5.38
SET version=1.5.40
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc duplicate --version %version% --token %GH_TOKEN%

View File

@@ -1,4 +1,7 @@
# 1.5.38 (02 October 2023)
- #1005 Support for xml namespaces in XPathMatcher [feature]
# 1.5.40 (07 November 2023)
- #1009 Add more tests for JmesPathMatchers and StringUtils.ParseMatchOperator [test]
- #1010 Add unit tests for HttpClient with WebProxy [test]
- #1011 GraphQL - add support for standard scalar types in the schema [feature]
- #1014 FluentAssertions - WithBody and WithBodyAsJson and WithBodyAsBytes
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md

View File

@@ -1,4 +1,4 @@
using WireMock.Logging;
using WireMock.Logging;
using WireMock.Server;
using WireMock.Settings;
@@ -24,7 +24,6 @@ namespace WireMock.Net.Console.NETCoreApp3WithCertificate
// X509CertificateFilePath = "example.pfx",
// X509CertificatePassword = "wiremock"
}
});
System.Console.WriteLine("WireMockServer listening at {0}", string.Join(",", server.Urls));

View File

@@ -94,23 +94,23 @@ public interface IRequestMessage
IBodyData? BodyData { get; }
/// <summary>
/// The original body as string. Convenience getter for Handlebars.
/// The original body as string. Convenience getter for Handlebars and WireMockAssertions.
/// </summary>
string? Body { get; }
/// <summary>
/// The body (as JSON object). Convenience getter for Handlebars.
/// The body (as JSON object). Convenience getter for Handlebars and WireMockAssertions.
/// </summary>
object? BodyAsJson { get; }
/// <summary>
/// The body (as bytearray). Convenience getter for Handlebars.
/// The body (as bytearray). Convenience getter for Handlebars and WireMockAssertions.
/// </summary>
byte[]? BodyAsBytes { get; }
#if MIMEKIT
/// <summary>
/// The original body as MimeMessage. Convenience getter for Handlebars.
/// The original body as MimeMessage. Convenience getter for Handlebars and WireMockAssertions.
/// </summary>
object? BodyAsMimeMessage { get; }
#endif

View File

@@ -1,3 +1,4 @@
using Stef.Validation;
using WireMock.Server;
// ReSharper disable once CheckNamespace
@@ -10,7 +11,7 @@ namespace WireMock.FluentAssertions
public WireMockANumberOfCallsAssertions(IWireMockServer server, int callsCount)
{
_server = server;
_server = Guard.NotNull(server);
_callsCount = callsCount;
}

View File

@@ -0,0 +1,79 @@
#pragma warning disable CS1591
using System;
using WireMock.Constants;
// ReSharper disable once CheckNamespace
namespace WireMock.FluentAssertions;
public partial class WireMockAssertions
{
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingConnect(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.CONNECT, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingDelete(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.DELETE, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingGet(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.GET, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingHead(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.HEAD, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingOptions(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.OPTIONS, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPost(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.POST, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPatch(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.PATCH, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPut(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.PUT, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingTrace(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.TRACE, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingAnyMethod(string because = "", params object[] becauseArgs)
=> UsingMethod(Any, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingMethod(string method, string because = "", params object[] becauseArgs)
{
var any = method == Any;
Func<IRequestMessage, bool> predicate = request => (any && !string.IsNullOrEmpty(request.Method)) ||
string.Equals(request.Method, method, StringComparison.OrdinalIgnoreCase);
var (filter, condition) = BuildFilterAndCondition(predicate);
Execute.Assertion
.BecauseOf(because, becauseArgs)
.Given(() => _requestMessages)
.ForCondition(requests => _callsCount == 0 || requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called using method {0}{reason}, but no calls were made.",
method
)
.Then
.ForCondition(condition)
.FailWith(
"Expected {context:wiremockserver} to have been called using method {0}{reason}, but didn't find it among the methods {1}.",
_ => method,
requests => requests.Select(request => request.Method)
);
_requestMessages = filter(_requestMessages).ToList();
return new AndConstraint<WireMockAssertions>(this);
}
}

View File

@@ -0,0 +1,151 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using WireMock.Matchers;
// ReSharper disable once CheckNamespace
namespace WireMock.FluentAssertions;
public partial class WireMockAssertions
{
private const string MessageFormatNoCalls = "Expected {context:wiremockserver} to have been called using body {0}{reason}, but no calls were made.";
private const string MessageFormat = "Expected {context:wiremockserver} to have been called using body {0}{reason}, but didn't find it among the body {1}.";
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBody(string body, string because = "", params object[] becauseArgs)
{
return WithBody(new WildcardMatcher(body), because, becauseArgs);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBodyAsJson(object body, string because = "", params object[] becauseArgs)
{
return WithBodyAsJson(new JsonMatcher(body), because, becauseArgs);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBodyAsJson(string body, string because = "", params object[] becauseArgs)
{
return WithBodyAsJson(new JsonMatcher(body), because, becauseArgs);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBodyAsBytes(byte[] body, string because = "", params object[] becauseArgs)
{
return WithBodyAsBytes(new ExactObjectMatcher(body), because, becauseArgs);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBody(IStringMatcher matcher, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(r => r.Body, matcher);
return ExecuteAssertionWithBodyStringMatcher(matcher, because, becauseArgs, condition, filter, r => r.Body);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBodyAsJson(IValueMatcher matcher, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(r => r.BodyAsJson, matcher);
return ExecuteAssertionWithBodyAsJsonValueMatcher(matcher, because, becauseArgs, condition, filter, r => r.BodyAsJson);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBodyAsBytes(ExactObjectMatcher matcher, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(r => r.BodyAsBytes, matcher);
return ExecuteAssertionWithBodyAsBytesExactObjectMatcher(matcher, because, becauseArgs, condition, filter, r => r.BodyAsBytes);
}
private AndConstraint<WireMockAssertions> ExecuteAssertionWithBodyStringMatcher(
IStringMatcher matcher,
string because,
object[] becauseArgs,
Func<IReadOnlyList<IRequestMessage>, bool> condition,
Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> filter,
Func<IRequestMessage, object?> expression
)
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
.Given(() => _requestMessages)
.ForCondition(requests => _callsCount == 0 || requests.Any())
.FailWith(
MessageFormatNoCalls,
matcher.GetPatterns()
)
.Then
.ForCondition(condition)
.FailWith(
MessageFormat,
_ => matcher.GetPatterns(),
requests => requests.Select(expression)
);
_requestMessages = filter(_requestMessages).ToList();
return new AndConstraint<WireMockAssertions>(this);
}
private AndConstraint<WireMockAssertions> ExecuteAssertionWithBodyAsJsonValueMatcher(
IValueMatcher matcher,
string because,
object[] becauseArgs,
Func<IReadOnlyList<IRequestMessage>, bool> condition,
Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> filter,
Func<IRequestMessage, object?> expression
)
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
.Given(() => _requestMessages)
.ForCondition(requests => _callsCount == 0 || requests.Any())
.FailWith(
MessageFormatNoCalls,
matcher.Value
)
.Then
.ForCondition(condition)
.FailWith(
MessageFormat,
_ => matcher.Value,
requests => requests.Select(expression)
);
_requestMessages = filter(_requestMessages).ToList();
return new AndConstraint<WireMockAssertions>(this);
}
private AndConstraint<WireMockAssertions> ExecuteAssertionWithBodyAsBytesExactObjectMatcher(
ExactObjectMatcher matcher,
string because,
object[] becauseArgs,
Func<IReadOnlyList<IRequestMessage>, bool> condition,
Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> filter,
Func<IRequestMessage, object?> expression
)
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
.Given(() => _requestMessages)
.ForCondition(requests => _callsCount == 0 || requests.Any())
.FailWith(
MessageFormatNoCalls,
matcher.ValueAsObject ?? matcher.ValueAsBytes
)
.Then
.ForCondition(condition)
.FailWith(
MessageFormat,
_ => matcher.ValueAsObject ?? matcher.ValueAsBytes,
requests => requests.Select(expression)
);
_requestMessages = filter(_requestMessages).ToList();
return new AndConstraint<WireMockAssertions>(this);
}
}

View File

@@ -1,17 +1,14 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using FluentAssertions.Execution;
using WireMock.Constants;
using WireMock.Matchers;
using WireMock.Server;
using WireMock.Types;
// ReSharper disable once CheckNamespace
namespace WireMock.FluentAssertions;
public class WireMockAssertions
public partial class WireMockAssertions
{
private const string Any = "*";
private readonly int? _callsCount;
@@ -28,9 +25,7 @@ public class WireMockAssertions
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, string> AtAbsoluteUrl(string absoluteUrl, string because = "", params object[] becauseArgs)
{
Func<IRequestMessage, bool> predicate = request => string.Equals(request.AbsoluteUrl, absoluteUrl, StringComparison.OrdinalIgnoreCase);
var (filter, condition) = BuildFilterAndCondition(predicate);
var (filter, condition) = BuildFilterAndCondition(request => string.Equals(request.AbsoluteUrl, absoluteUrl, StringComparison.OrdinalIgnoreCase));
Execute.Assertion
.BecauseOf(because, becauseArgs)
@@ -55,9 +50,7 @@ public class WireMockAssertions
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, string> AtUrl(string url, string because = "", params object[] becauseArgs)
{
Func<IRequestMessage, bool> predicate = request => string.Equals(request.Url, url, StringComparison.OrdinalIgnoreCase);
var (filter, condition) = BuildFilterAndCondition(predicate);
var (filter, condition) = BuildFilterAndCondition(request => string.Equals(request.Url, url, StringComparison.OrdinalIgnoreCase));
Execute.Assertion
.BecauseOf(because, becauseArgs)
@@ -83,9 +76,7 @@ public class WireMockAssertions
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, string> WithProxyUrl(string proxyUrl, string because = "", params object[] becauseArgs)
{
Func<IRequestMessage, bool> predicate = request => string.Equals(request.ProxyUrl, proxyUrl, StringComparison.OrdinalIgnoreCase);
var (filter, condition) = BuildFilterAndCondition(predicate);
var (filter, condition) = BuildFilterAndCondition(request => string.Equals(request.ProxyUrl, proxyUrl, StringComparison.OrdinalIgnoreCase));
Execute.Assertion
.BecauseOf(because, becauseArgs)
@@ -111,9 +102,7 @@ public class WireMockAssertions
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, string> FromClientIP(string clientIP, string because = "", params object[] becauseArgs)
{
Func<IRequestMessage, bool> predicate = request => string.Equals(request.ClientIP, clientIP, StringComparison.OrdinalIgnoreCase);
var (filter, condition) = BuildFilterAndCondition(predicate);
var (filter, condition) = BuildFilterAndCondition(request => string.Equals(request.ClientIP, clientIP, StringComparison.OrdinalIgnoreCase));
Execute.Assertion
.BecauseOf(because, becauseArgs)
@@ -168,80 +157,20 @@ public class WireMockAssertions
return new AndConstraint<WireMockAssertions>(this);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingConnect(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.CONNECT, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingDelete(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.DELETE, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingGet(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.GET, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingHead(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.HEAD, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingOptions(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.OPTIONS, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPost(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.POST, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPatch(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.PATCH, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPut(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.PUT, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingTrace(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.TRACE, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingAnyMethod(string because = "", params object[] becauseArgs)
=> UsingMethod(Any, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingMethod(string method, string because = "", params object[] becauseArgs)
{
var any = method == Any;
Func<IRequestMessage, bool> predicate = request => (any && !string.IsNullOrEmpty(request.Method)) ||
string.Equals(request.Method, method, StringComparison.OrdinalIgnoreCase);
var (filter, condition) = BuildFilterAndCondition(predicate);
Execute.Assertion
.BecauseOf(because, becauseArgs)
.Given(() => _requestMessages)
.ForCondition(requests => _callsCount == 0 || requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called using method {0}{reason}, but no calls were made.",
method
)
.Then
.ForCondition(condition)
.FailWith(
"Expected {context:wiremockserver} to have been called using method {0}{reason}, but didn't find it among the methods {1}.",
_ => method,
requests => requests.Select(request => request.Method)
);
_requestMessages = filter(_requestMessages).ToList();
return new AndConstraint<WireMockAssertions>(this);
}
private (Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> Filter, Func<IReadOnlyList<IRequestMessage>, bool> Condition) BuildFilterAndCondition(Func<IRequestMessage, bool> predicate)
{
Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> filter = requests => requests.Where(predicate).ToList();
return (filter, requests => (_callsCount is null && filter(requests).Any()) || _callsCount == filter(requests).Count);
}
private (Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> Filter, Func<IReadOnlyList<IRequestMessage>, bool> Condition) BuildFilterAndCondition(Func<IRequestMessage, string?> expression, IStringMatcher matcher)
{
return BuildFilterAndCondition(r => matcher.IsMatch(expression(r)).IsPerfect());
}
private (Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> Filter, Func<IReadOnlyList<IRequestMessage>, bool> Condition) BuildFilterAndCondition(Func<IRequestMessage, object?> expression, IObjectMatcher matcher)
{
return BuildFilterAndCondition(r => matcher.IsMatch(expression(r)).IsPerfect());
}
}

View File

@@ -45,7 +45,7 @@ namespace WireMock.FluentAssertions
return new WireMockANumberOfCallsAssertions(Subject, callsCount);
}
/// <inheritdoc cref="ReferenceTypeAssertions{IWireMockServer, WireMockReceivedAssertions}.Identifier"/>
/// <inheritdoc />
protected override string Identifier => "wiremockserver";
}
}

View File

@@ -0,0 +1,3 @@
global using System.Linq;
global using FluentAssertions;
global using FluentAssertions.Execution;

View File

@@ -22,7 +22,7 @@
<!--<DelaySign>true</DelaySign>-->
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<LangVersion>10</LangVersion>
<LangVersion>11</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
@@ -43,7 +43,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
<ProjectReference Include="..\WireMock.Net\WireMock.Net.csproj" />
</ItemGroup>
</Project>

View File

@@ -137,9 +137,14 @@ public class GraphQLMatcher : IStringMatcher
}
}
private static ISchema BuildSchema(string schema)
private static ISchema BuildSchema(string typeDefinitions)
{
return Schema.For(schema);
var schema = Schema.For(typeDefinitions);
// #984
schema.RegisterTypes(schema.BuiltInTypeMappings.Select(x => x.graphType).ToArray());
return schema;
}
}
#endif

View File

@@ -53,7 +53,7 @@ public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
public JsonMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false)
{
Guard.NotNull(value, nameof(value));
Guard.NotNull(value);
MatchBehaviour = matchBehaviour;
IgnoreCase = ignoreCase;

View File

@@ -85,11 +85,11 @@ public class RequestMessageParamMatcher : IRequestMatcher
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
var (score, exception) = GetMatchResult(requestMessage).Expand();
return requestMatchResult.AddScore(GetType(), score, exception);
var score = GetMatchScore(requestMessage);
return requestMatchResult.AddScore(GetType(), MatchBehaviourHelper.Convert(MatchBehaviour, score), null);
}
private MatchResult GetMatchResult(IRequestMessage requestMessage)
private double GetMatchScore(IRequestMessage requestMessage)
{
if (Funcs != null)
{
@@ -100,7 +100,7 @@ public class RequestMessageParamMatcher : IRequestMatcher
if (valuesPresentInRequestMessage == null)
{
// Key is not present at all, just return Mismatch
return default;
return MatchScores.Mismatch;
}
if (Matchers != null && Matchers.Any())
@@ -115,10 +115,10 @@ public class RequestMessageParamMatcher : IRequestMatcher
return MatchScores.Perfect;
}
return default;
return MatchScores.Mismatch;
}
private static MatchResult CalculateScore(IReadOnlyList<IStringMatcher> matchers, WireMockList<string> valuesPresentInRequestMessage)
private static double CalculateScore(IReadOnlyList<IStringMatcher> matchers, WireMockList<string> valuesPresentInRequestMessage)
{
var total = new List<double>();

View File

@@ -12,8 +12,6 @@ internal class HostUrlOptions
public int? Port { get; set; }
public int? HttpsPort { get; set; }
public HostingScheme HostingScheme { get; set; }
public IReadOnlyList<HostUrlDetails> GetDetails()

View File

@@ -35,11 +35,7 @@ internal class MappingMatcher : IMappingMatcher
{
var nextState = GetNextState(mapping);
var mappingMatcherResult = new MappingMatcherResult
{
Mapping = mapping,
RequestMatchResult = mapping.GetRequestMatchResult(request, nextState)
};
var mappingMatcherResult = new MappingMatcherResult(mapping, mapping.GetRequestMatchResult(request, nextState));
var exceptions = mappingMatcherResult.RequestMatchResult.MatchDetails
.Where(md => md.Exception != null)
@@ -66,7 +62,10 @@ internal class MappingMatcher : IMappingMatcher
var partialMappings = possibleMappings
.Where(pm => (pm.Mapping.IsAdminInterface && pm.RequestMatchResult.IsPerfectMatch) || !pm.Mapping.IsAdminInterface)
.OrderBy(m => m.RequestMatchResult).ThenBy(m => m.Mapping.Priority).ThenByDescending(m => m.Mapping.UpdatedAt)
.OrderBy(m => m.RequestMatchResult)
.ThenBy(m => m.RequestMatchResult.TotalNumber)
.ThenBy(m => m.Mapping.Priority)
.ThenByDescending(m => m.Mapping.UpdatedAt)
.ToList();
var partialMatch = partialMappings.FirstOrDefault(pm => pm.RequestMatchResult.AverageTotalScore > 0.0);

View File

@@ -1,10 +1,17 @@
using Stef.Validation;
using WireMock.Matchers.Request;
namespace WireMock.Owin;
internal class MappingMatcherResult
{
public IMapping Mapping { get; set; }
public IMapping Mapping { get; }
public IRequestMatchResult RequestMatchResult { get; set; }
public IRequestMatchResult RequestMatchResult { get; }
public MappingMatcherResult(IMapping mapping, IRequestMatchResult requestMatchResult)
{
Mapping = Guard.NotNull(mapping);
RequestMatchResult = Guard.NotNull(requestMatchResult);
}
}

View File

@@ -61,7 +61,7 @@ public interface IRespondWithAProvider
/// <summary>
/// Define the priority for this mapping.
/// </summary>
/// <param name="priority">The priority.</param>
/// <param name="priority">The priority. (A lower value means a higher priority.)</param>
/// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
IRespondWithAProvider AtPriority(int priority);

View File

@@ -141,6 +141,31 @@ public partial class WireMockServer : IWireMockServer
return client;
}
/// <summary>
/// Create a <see cref="HttpClient"/> which can be used to call this instance.
/// <param name="handlers">
/// <param name="innerHandler">The inner handler represents the destination of the HTTP message channel.</param>
/// An ordered list of System.Net.Http.DelegatingHandler instances to be invoked
/// as an System.Net.Http.HttpRequestMessage travels from the System.Net.Http.HttpClient
/// to the network and an System.Net.Http.HttpResponseMessage travels from the network
/// back to System.Net.Http.HttpClient. The handlers are invoked in a top-down fashion.
/// That is, the first entry is invoked first for an outbound request message but
/// last for an inbound response message.
/// </param>
/// </summary>
[PublicAPI]
public HttpClient CreateClient(HttpMessageHandler innerHandler, params DelegatingHandler[] handlers)
{
if (!IsStarted)
{
throw new InvalidOperationException("Unable to create HttpClient because the service is not started.");
}
var client = HttpClientFactory2.Create(innerHandler, handlers);
client.BaseAddress = new Uri(Url!);
return client;
}
/// <summary>
/// Create <see cref="HttpClient"/>s (one for each URL) which can be used to call this instance.
/// <param name="innerHandler">The inner handler represents the destination of the HTTP message channel.</param>

View File

@@ -36,7 +36,7 @@ internal static class RegexUtils
{
if (useRegexExtended)
{
var regexExtended = new RegexExtended(pattern, RegexOptions.None, RegexTimeOut);
var regexExtended = new RegexExtended(pattern!, RegexOptions.None, RegexTimeOut);
return (true, regexExtended.IsMatch(input));
}

View File

@@ -6,6 +6,7 @@ using System.Net.Http.Headers;
using System.Threading.Tasks;
using FluentAssertions;
using WireMock.FluentAssertions;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
@@ -215,10 +216,13 @@ public class WireMockAssertionsTests : IDisposable
{
// Arrange
using var server = WireMockServer.Start();
using var client = server.CreateClient();
using var client1 = server.CreateClient();
var handler = new HttpClientHandler();
using var client2 = server.CreateClient(handler);
// Act 1
await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/")
await client1.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/")
{
Headers =
{
@@ -227,7 +231,7 @@ public class WireMockAssertionsTests : IDisposable
});
// Act 2
await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/")
await client2.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/")
{
Headers =
{
@@ -630,6 +634,194 @@ public class WireMockAssertionsTests : IDisposable
.AtUrl(_server.Url ?? string.Empty);
}
[Fact]
public async Task HaveReceived1Call_WithBodyAsString()
{
// Arrange
var server = WireMockServer.Start();
server
.Given(Request.Create().WithPath("/a").UsingPost().WithBody("x"))
.RespondWith(Response.Create().WithBody("A response"));
// Act
var httpClient = new HttpClient();
await httpClient.PostAsync($"{server.Url}/a", new StringContent("x"));
// Assert
server
.Should()
.HaveReceived(1)
.Calls()
.WithBody("*")
.And
.UsingPost();
server
.Should()
.HaveReceived(1)
.Calls()
.WithBody("x")
.And
.UsingPost();
server
.Should()
.HaveReceived(0)
.Calls()
.WithBody("")
.And
.UsingPost();
server
.Should()
.HaveReceived(0)
.Calls()
.WithBody("y")
.And
.UsingPost();
server.Stop();
}
[Fact]
public async Task HaveReceived1Call_WithBodyAsJson()
{
// Arrange
var server = WireMockServer.Start();
server
.Given(Request.Create().WithPath("/a").UsingPost().WithBodyAsJson(new { x = "y" }))
.RespondWith(Response.Create().WithBody("A response"));
// Act
var httpClient = new HttpClient();
await httpClient.PostAsync($"{server.Url}/a", new StringContent(@"{ ""x"": ""y"" }"));
// Assert
server
.Should()
.HaveReceived(1)
.Calls()
.WithBodyAsJson(new { x = "y" })
.And
.UsingPost();
server
.Should()
.HaveReceived(1)
.Calls()
.WithBodyAsJson(@"{ ""x"": ""y"" }")
.And
.UsingPost();
server
.Should()
.HaveReceived(0)
.Calls()
.WithBodyAsJson(new { x = "?" })
.And
.UsingPost();
server
.Should()
.HaveReceived(0)
.Calls()
.WithBodyAsJson(@"{ ""x"": 1234 }")
.And
.UsingPost();
server.Stop();
}
[Fact]
public async Task HaveReceived1Call_WithBodyAsBytes()
{
// Arrange
var server = WireMockServer.Start();
server
.Given(Request.Create().WithPath("/a").UsingPut().WithBody(new byte[] { 100 }))
.RespondWith(Response.Create().WithBody("A response"));
// Act
var httpClient = new HttpClient();
await httpClient.PutAsync($"{server.Url}/a", new ByteArrayContent(new byte[] { 100 }));
// Assert
server
.Should()
.HaveReceived(1)
.Calls()
.WithBodyAsBytes(new byte[] { 100 })
.And
.UsingPut();
server
.Should()
.HaveReceived(0)
.Calls()
.WithBodyAsBytes(new byte[0])
.And
.UsingPut();
server
.Should()
.HaveReceived(0)
.Calls()
.WithBodyAsBytes(new byte[] { 42 })
.And
.UsingPut();
server.Stop();
}
[Fact]
public async Task HaveReceived1Call_WithBodyAsString_UsingStringMatcher()
{
// Arrange
var server = WireMockServer.Start();
server
.Given(Request.Create().WithPath("/a").UsingPost().WithBody("x"))
.RespondWith(Response.Create().WithBody("A response"));
// Act
var httpClient = new HttpClient();
await httpClient.PostAsync($"{server.Url}/a", new StringContent("x"));
// Assert
server
.Should()
.HaveReceived(1)
.Calls()
.WithBody(new ExactMatcher("x"))
.And
.UsingPost();
server
.Should()
.HaveReceived(0)
.Calls()
.WithBody(new ExactMatcher(""))
.And
.UsingPost();
server
.Should()
.HaveReceived(0)
.Calls()
.WithBody(new ExactMatcher("y"))
.And
.UsingPost();
server.Stop();
}
public void Dispose()
{
_server?.Stop();

View File

@@ -11,7 +11,10 @@ namespace WireMock.Net.Tests.Matchers;
public class GraphQLMatcherTests
{
private const string TestSchema = @"
scalar DateTime
input MessageInput {
date: DateTime
content: String
author: String
}
@@ -24,20 +27,21 @@ public class GraphQLMatcherTests
type Mutation {
createMessage(input: MessageInput): Message
createAnotherMessage(date: DateTime, content: String, author: String): Message
updateMessage(id: ID!, input: MessageInput): Message
}
type Query {
greeting:String
students:[Student]
studentById(id:ID!):Student
greeting: String
students: [Student]
studentById(id: ID!):Student
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
id: ID!
firstName: String
lastName: String
fullName: String
}";
[Fact]
@@ -57,7 +61,7 @@ public class GraphQLMatcherTests
}
[Fact]
public void GraphQLMatcher_For_ValidSchema_And_CorrectGraphQLQuery_IsMatch()
public void GraphQLMatcher_For_ValidSchema_And_CorrectGraphQL_Query_IsMatch()
{
// Arrange
var input = @"{
@@ -76,6 +80,25 @@ public class GraphQLMatcherTests
matcher.GetPatterns().Should().Contain(TestSchema);
}
[Fact]
public void GraphQLMatcher_For_ValidSchema_And_CorrectGraphQL_Mutation_IsMatch()
{
// Arrange
var input = @"{
""query"": ""mutation CreateAnotherMessage($date: DateTime!, $content: String!, $author: String!) { createAnotherMessage(date: $date, content: $content, author: $author) { id } }"",
""variables"": { ""date"": ""2007-12-03T10:15:30Z"", ""content"": ""--content--"", ""author"": ""--author--"" }
}";
// Act
var matcher = new GraphQLMatcher(TestSchema);
var result = matcher.IsMatch(input);
// Assert
result.Score.Should().Be(MatchScores.Perfect);
matcher.GetPatterns().Should().Contain(TestSchema);
}
[Fact]
public void GraphQLMatcher_For_ValidSchema_And_IncorrectQuery_IsMismatch()
{

View File

@@ -0,0 +1,60 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using FluentAssertions;
using WireMock.Owin;
using WireMock.Types;
using Xunit;
namespace WireMock.Net.Tests.Owin;
[ExcludeFromCodeCoverage]
public class HostUrlOptionsTests
{
[Fact]
public void GetDetails_WithNoUrlsAndHttpScheme_ShouldReturnCorrectDetails()
{
// Arrange
var options = new HostUrlOptions
{
HostingScheme = HostingScheme.Http,
Port = 8080
};
// Act
var details = options.GetDetails();
// Assert
details.Should().HaveCount(1);
var detail = details.Single();
detail.Should().Match<HostUrlDetails>(d =>
d.Scheme == "http" &&
d.Host == "localhost" &&
d.Port == 8080 &&
d.IsHttps == false
);
}
[Fact]
public void GetDetails_WithNoUrlsAndHttpsScheme_ShouldReturnCorrectDetails()
{
// Arrange
var options = new HostUrlOptions
{
HostingScheme = HostingScheme.Https,
Port = 8081
};
// Act
var details = options.GetDetails();
// Assert
details.Should().HaveCount(1);
var detail = details.Single();
detail.Should().Match<HostUrlDetails>(d =>
d.Scheme == "https" &&
d.Host == "localhost" &&
d.Port == 8081 &&
d.IsHttps == true
);
}
}

View File

@@ -16,6 +16,7 @@ using WireMock.Admin.Requests;
using WireMock.Settings;
using FluentAssertions;
using WireMock.Handlers;
using WireMock.Matchers.Request;
using WireMock.ResponseBuilders;
using WireMock.RequestBuilders;
#if NET452
@@ -43,6 +44,7 @@ public class WireMockMiddlewareTests
private readonly Mock<IOwinResponseMapper> _responseMapperMock;
private readonly Mock<IMappingMatcher> _matcherMock;
private readonly Mock<IMapping> _mappingMock;
private readonly Mock<IRequestMatchResult> _requestMatchResultMock;
private readonly Mock<IContext> _contextMock;
private readonly WireMockMiddleware _sut;
@@ -72,12 +74,16 @@ public class WireMockMiddlewareTests
_matcherMock = new Mock<IMappingMatcher>();
_matcherMock.SetupAllProperties();
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((new MappingMatcherResult(), new MappingMatcherResult()));
// _matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((new MappingMatcherResult(), new MappingMatcherResult()));
_contextMock = new Mock<IContext>();
_mappingMock = new Mock<IMapping>();
_requestMatchResultMock = new Mock<IRequestMatchResult>();
_requestMatchResultMock.Setup(r => r.TotalNumber).Returns(1);
_requestMatchResultMock.Setup(r => r.MatchDetails).Returns(new List<MatchDetail>());
_sut = new WireMockMiddleware(
null,
_optionsMock.Object,
@@ -133,7 +139,7 @@ public class WireMockMiddlewareTests
_optionsMock.SetupGet(o => o.AuthenticationMatcher).Returns(new ExactMatcher());
_mappingMock.SetupGet(m => m.IsAdminInterface).Returns(true);
var result = new MappingMatcherResult { Mapping = _mappingMock.Object };
var result = new MappingMatcherResult(_mappingMock.Object, _requestMatchResultMock.Object);
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((result, result));
// Act
@@ -156,7 +162,7 @@ public class WireMockMiddlewareTests
_optionsMock.SetupGet(o => o.AuthenticationMatcher).Returns(new ExactMatcher());
_mappingMock.SetupGet(m => m.IsAdminInterface).Returns(true);
var result = new MappingMatcherResult { Mapping = _mappingMock.Object };
var result = new MappingMatcherResult(_mappingMock.Object, _requestMatchResultMock.Object);
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((result, result));
// Act
@@ -216,7 +222,7 @@ public class WireMockMiddlewareTests
var requestBuilder = Request.Create().UsingAnyMethod();
_mappingMock.SetupGet(m => m.RequestMatcher).Returns(requestBuilder);
var result = new MappingMatcherResult { Mapping = _mappingMock.Object };
var result = new MappingMatcherResult(_mappingMock.Object, _requestMatchResultMock.Object);
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((result, result));
// Act
@@ -270,7 +276,7 @@ public class WireMockMiddlewareTests
var requestBuilder = Request.Create().UsingAnyMethod();
_mappingMock.SetupGet(m => m.RequestMatcher).Returns(requestBuilder);
var result = new MappingMatcherResult { Mapping = _mappingMock.Object };
var result = new MappingMatcherResult (_mappingMock.Object, _requestMatchResultMock.Object);
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((result, result));
// Act

View File

@@ -300,6 +300,31 @@ public class RequestMessageBodyMatcherTests
Check.That(score).IsEqualTo(1.0d);
}
[Fact]
public void RequestMessageBodyMatcher_GetMatchingScore_BodyAsJson_JmesPathMatchers()
{
// Arrange
var body = new BodyData
{
BodyAsJson = new { requestId = "1", value = "A" },
DetectedBodyType = BodyType.Json
};
var requestMessage = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.1", body);
var jmesMatcher1 = new JmesPathMatcher("requestId == '1'");
var jmesMatcher2 = new JmesPathMatcher("value == 'A'");
var bodyMatcher = new RequestMessageBodyMatcher(MatchOperator.And, jmesMatcher1, jmesMatcher2);
// Act
var result = new RequestMatchResult();
double score = bodyMatcher.GetMatchingScore(requestMessage, result);
// Assert
score.Should().Be(MatchScores.Perfect);
}
[Theory]
[InlineData(null, 0.0)]
[InlineData(new byte[0], 0.0)]

View File

@@ -30,8 +30,7 @@ public class RegexUtilsTests
[InlineData(null, "test", false, false)]
[InlineData(".*", "test", true, true)]
[InlineData("invalid[", "test", false, false)]
public void MatchRegex_WithVariousPatterns_ReturnsExpectedResults(
string? pattern, string input, bool expectedIsValid, bool expectedResult)
public void MatchRegex_WithVariousPatterns_ReturnsExpectedResults(string? pattern, string input, bool expectedIsValid, bool expectedResult)
{
// Act
var (isValidResult, matchResult) = RegexUtils.MatchRegex(pattern, input);
@@ -46,8 +45,7 @@ public class RegexUtilsTests
[InlineData(null, "test", false, false)]
[InlineData(".*", "test", true, true)]
[InlineData("invalid[", "test", false, false)]
public void MatchRegex_WithVariousPatternsAndExtendedRegex_ReturnsExpectedResults(
string? pattern, string input, bool expectedIsValid, bool expectedResult)
public void MatchRegex_WithVariousPatternsAndExtendedRegex_ReturnsExpectedResults(string? pattern, string input, bool expectedIsValid, bool expectedResult)
{
// Act
var (isValidResult, matchResult) = RegexUtils.MatchRegex(pattern, input, useRegexExtended: true);

View File

@@ -1,4 +1,5 @@
using FluentAssertions;
using WireMock.Matchers;
using WireMock.Util;
using Xunit;
@@ -6,13 +7,39 @@ namespace WireMock.Net.Tests.Util;
public class StringUtilsTests
{
[Theory]
[InlineData("And", MatchOperator.And)]
[InlineData("Or", MatchOperator.Or)]
public void ParseMatchOperator_ShouldReturnCorrectEnumValue_WhenValidStringIsProvided(string value, MatchOperator expected)
{
// Arrange & Act
var result = StringUtils.ParseMatchOperator(value);
// Assert
result.Should().Be(expected);
}
[Theory]
[InlineData(null, MatchOperator.Or)]
[InlineData("", MatchOperator.Or)]
[InlineData("and", MatchOperator.Or)]
[InlineData("InvalidValue", MatchOperator.Or)]
public void ParseMatchOperator_ShouldReturnDefaultEnumValue_WhenInvalidOrNullStringIsProvided(string? value, MatchOperator expected)
{
// Arrange & Act
var result = StringUtils.ParseMatchOperator(value);
// Assert
result.Should().Be(expected);
}
[Theory]
[InlineData("'s")]
[InlineData("\"s")]
public void StringUtils_TryParseQuotedString_With_UnexpectedUnclosedString_Returns_False(string input)
{
// Act
bool valid = StringUtils.TryParseQuotedString(input, out var result, out var quote);
var valid = StringUtils.TryParseQuotedString(input, out _, out _);
// Assert
valid.Should().BeFalse();
@@ -25,7 +52,7 @@ public class StringUtilsTests
public void StringUtils_TryParseQuotedString_With_InvalidStringLength_Returns_False(string input)
{
// Act
bool valid = StringUtils.TryParseQuotedString(input, out var result, out var quote);
var valid = StringUtils.TryParseQuotedString(input, out _, out _);
// Assert
valid.Should().BeFalse();
@@ -37,7 +64,7 @@ public class StringUtilsTests
public void StringUtils_TryParseQuotedString_With_InvalidStringQuoteCharacter_Returns_False(string input)
{
// Act
bool valid = StringUtils.TryParseQuotedString(input, out var result, out var quote);
var valid = StringUtils.TryParseQuotedString(input, out _, out _);
// Assert
valid.Should().BeFalse();
@@ -47,10 +74,10 @@ public class StringUtilsTests
public void StringUtils_TryParseQuotedString_With_UnexpectedUnrecognizedEscapeSequence_Returns_False()
{
// Arrange
string input = new string(new[] { '"', '\\', 'u', '?', '"' });
var input = new string(new[] { '"', '\\', 'u', '?', '"' });
// Act
bool valid = StringUtils.TryParseQuotedString(input, out var result, out var quote);
var valid = StringUtils.TryParseQuotedString(input, out _, out _);
// Assert
valid.Should().BeFalse();
@@ -64,7 +91,7 @@ public class StringUtilsTests
public void StringUtils_TryParseQuotedString_SingleQuotedString(string input, string expectedResult)
{
// Act
bool valid = StringUtils.TryParseQuotedString(input, out var result, out var quote);
var valid = StringUtils.TryParseQuotedString(input, out var result, out var quote);
// Assert
valid.Should().BeTrue();
@@ -93,7 +120,7 @@ public class StringUtilsTests
public void StringUtils_TryParseQuotedString_DoubleQuotedString(string input, string expectedResult)
{
// Act
bool valid = StringUtils.TryParseQuotedString(input, out var result, out var quote);
var valid = StringUtils.TryParseQuotedString(input, out var result, out var quote);
// Assert
valid.Should().BeTrue();

View File

@@ -3,6 +3,8 @@
<PropertyGroup>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;net461;netcoreapp3.1;net6.0;net7.0</TargetFrameworks>
<LangVersion>11</LangVersion>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<DebugType>full</DebugType>
<AssemblyName>WireMock.Net.Tests</AssemblyName>
@@ -110,6 +112,9 @@
<None Update="OpenApiParser\*.yml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="cert.pem">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="responsebody.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View File

@@ -1,9 +1,8 @@
#if !NET452
//using System;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
//using System.Net.Http.Json;
using System.Threading.Tasks;
using FluentAssertions;
using WireMock.Matchers;
@@ -21,6 +20,103 @@ public partial class WireMockServerTests
public string? Hi { get; set; }
}
[Fact]
public async Task WireMockServer_WithBodyAsJson_Using_PostAsJsonAsync_And_MultipleJmesPathMatchers_ShouldMatch()
{
// Arrange
var server = WireMockServer.Start();
server.Given(
Request.Create()
.WithPath("/a")
.WithBody(
new IMatcher[]
{
new JmesPathMatcher("requestId == '1'"),
new JmesPathMatcher("value == 'A'")
},
MatchOperator.And
)
.UsingPost()
)
.RespondWith(Response.Create().WithStatusCode(HttpStatusCode.OK));
server.Given(
Request.Create()
.WithPath("/a")
.WithBody(
new IMatcher[]
{
new JmesPathMatcher("requestId == '2'"),
new JmesPathMatcher("value == 'A'")
},
MatchOperator.And
)
.UsingPost()
)
.RespondWith(Response.Create().WithStatusCode(HttpStatusCode.Moved));
// Act
var requestUri = new Uri($"http://localhost:{server.Port}/a");
var json = new { requestId = "1", value = "A" };
var response = await server.CreateClient().PostAsJsonAsync(requestUri, json).ConfigureAwait(false);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
server.Stop();
}
[Fact]
public async Task WireMockServer_WithBodyAsJson_Using_PostAsJsonAsync_And_MultipleJmesPathMatchers_ShouldMatch_BestMatching()
{
// Arrange
var server = WireMockServer.Start();
server.Given(
Request.Create()
.WithPath("/a")
.WithBody(
new IMatcher[]
{
new JmesPathMatcher("extra == 'X'"),
new JmesPathMatcher("requestId == '1'"),
new JmesPathMatcher("value == 'A'")
},
MatchOperator.And
)
.UsingPost()
)
.AtPriority(1) // Higher priority
.RespondWith(Response.Create().WithStatusCode(HttpStatusCode.OK));
server.Given(
Request.Create()
.WithPath("/a")
.WithBody(
new IMatcher[]
{
new JmesPathMatcher("requestId == '1'"),
new JmesPathMatcher("value == 'A'")
},
MatchOperator.And
)
.UsingPost()
)
.AtPriority(2)
.RespondWith(Response.Create().WithStatusCode(HttpStatusCode.Moved));
// Act
var requestUri = new Uri($"http://localhost:{server.Port}/a");
var json = new { extra = "X", requestId = "1", value = "A" };
var response = await server.CreateClient().PostAsJsonAsync(requestUri, json).ConfigureAwait(false);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
server.Stop();
}
[Fact]
public async Task WireMockServer_WithBodyAsJson_Using_PostAsJsonAsync_And_WildcardMatcher_ShouldMatch()
{

View File

@@ -2,6 +2,7 @@ using System;
using System.Net;
using System.Threading.Tasks;
using FluentAssertions;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
@@ -26,10 +27,10 @@ public partial class WireMockServerTests
};
var server = WireMockServer.Start(settings);
server.Given(
Request.Create()
.UsingGet()
.WithPath("/foo")
.WithParam("query", queryValue)
Request.Create()
.UsingGet()
.WithPath("/foo")
.WithParam("query", queryValue)
)
.RespondWith(
Response.Create().WithStatusCode(200)
@@ -52,10 +53,10 @@ public partial class WireMockServerTests
var queryValue = "1,2,3";
var server = WireMockServer.Start();
server.Given(
Request.Create()
.UsingGet()
.WithPath("/foo")
.WithParam("query", "1", "2", "3")
Request.Create()
.UsingGet()
.WithPath("/foo")
.WithParam("query", "1", "2", "3")
)
.RespondWith(
Response.Create().WithStatusCode(200)
@@ -70,4 +71,54 @@ public partial class WireMockServerTests
server.Stop();
}
[Fact]
public async Task WireMockServer_WithParam_RejectOnMatch_OnNonMatchingParam_ShouldReturnMappingOk()
{
// Arrange
var server = WireMockServer.Start();
server.Given(
Request.Create()
.WithPath("/v1/person/workers")
.WithParam("delta_from", MatchBehaviour.RejectOnMatch)
.UsingGet()
)
.RespondWith(
Response.Create()
);
// Act
var requestUri = new Uri($"http://localhost:{server.Port}/v1/person/workers?showsourcesystem=true&count=700&page=1&sections=personal%2Corganizations%2Cemployment");
var response = await server.CreateClient().GetAsync(requestUri).ConfigureAwait(false);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
server.Stop();
}
[Fact]
public async Task WireMockServer_WithParam_AcceptOnMatch_OnNonMatchingParam_ShouldReturnMappingOk()
{
// Arrange
var server = WireMockServer.Start();
server.Given(
Request.Create()
.WithPath("/v1/person/workers")
.WithParam("delta_from")
.UsingGet()
)
.RespondWith(
Response.Create()
);
// Act
var requestUri = new Uri($"http://localhost:{server.Port}/v1/person/workers?showsourcesystem=true&count=700&page=1&sections=personal%2Corganizations%2Cemployment");
var response = await server.CreateClient().GetAsync(requestUri).ConfigureAwait(false);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
server.Stop();
}
}

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
@@ -100,6 +101,99 @@ public partial class WireMockServerTests
server.Stop();
}
#if NET461_OR_GREATER || NET6_0_OR_GREATER
[Fact]
public async Task WireMockServer_Should_Support_Https()
{
// Arrange
const string body = "example";
var path = $"/foo_{Guid.NewGuid()}";
var settings = new WireMockServerSettings
{
UseSSL = true
};
var server = WireMockServer.Start(settings);
server
.Given(Request.Create()
.WithPath(path)
.UsingGet()
)
.RespondWith(Response.Create()
.WithBody(body)
);
// Configure the HttpClient to trust self-signed certificates
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (_, _, _, _) => true
};
using var client = new HttpClient(handler);
// Act
var result = await client.GetStringAsync($"{server.Url}{path}").ConfigureAwait(false);
// Assert
result.Should().Be(body);
server.Stop();
}
#endif
#if NET6_0_OR_GREATER
[Fact]
public async Task WireMockServer_When_HttpClientWithWebProxyCallsHttp_Should_Work_Correct()
{
// Arrange
const string body = "example";
var settings = new WireMockServerSettings
{
HostingScheme = HostingScheme.Http
};
var server = WireMockServer.Start(settings);
// The response to an HTTP CONNECT method, which is used to establish a tunnel with a proxy, should typically be a 200 OK status code if the connection is successful.
// This indicates that a tunnel has been established successfully between the client and the server via the proxy.
server
.Given(Request.Create()
.UsingConnect()
)
.RespondWith(Response.Create()
.WithBody("Connection established")
);
server
.Given(Request.Create()
.UsingGet()
)
.RespondWith(Response.Create()
.WithBody(body)
);
var httpUrl = server.Urls.First();
// Act
string result;
var currentProxy = HttpClient.DefaultProxy;
try
{
HttpClient.DefaultProxy = new WebProxy(httpUrl, false);
result = await new HttpClient().GetStringAsync(httpUrl).ConfigureAwait(false);
}
finally
{
// Revert
HttpClient.DefaultProxy = currentProxy;
}
// Assert
result.Should().Be(body);
server.Stop();
}
#endif
[Fact]
public async Task WireMockServer_Should_respond_a_redirect_without_body()
{

View File

@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB9TCCAZugAwIBAgIUYH7UM/DAXzosxsT+ea2jdYvhqqMwCgYIKoZIzj0EAwIw
UDELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNvbWUtU3RhdGUxFTATBgNVBAoMDFdp
cmVNb2NrLk5ldDEVMBMGA1UEAwwMV2lyZU1vY2suTmV0MB4XDTIyMDgxMTE2MjE0
NFoXDTMyMDYxOTE2MjE0NFowUDELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNvbWUt
U3RhdGUxFTATBgNVBAoMDFdpcmVNb2NrLk5ldDEVMBMGA1UEAwwMV2lyZU1vY2su
TmV0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE39VoI268uDuIeKmRzr9e9jgM
SGeuJTvTG7+cSXmeDymrVgIGXQgmqKA8TDXpJNrRhWMd/fpsnWu1JwJUjBmspaNT
MFEwHQYDVR0OBBYEFILL8V+fAtMnccWKGAdkx2Dh/v/TMB8GA1UdIwQYMBaAFILL
8V+fAtMnccWKGAdkx2Dh/v/TMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwID
SAAwRQIgKDLAG8OWK6GF5HV4kmWz3kp2V3yVsNK2V9Lw3dSE+YsCIQCK1EEBvuqc
0ncZV4ETVnOY23PWFOMk1VwN2aoTi5n++Q==
-----END CERTIFICATE-----