mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-02-21 00:08:05 +01:00
Compare commits
5 Commits
bug/1149-A
...
1.6.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95573eeb96 | ||
|
|
487d6d2db1 | ||
|
|
d2b53893db | ||
|
|
088444024f | ||
|
|
7e162a00ab |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,3 +1,17 @@
|
|||||||
|
# 1.6.1 (22 August 2024)
|
||||||
|
- [#1160](https://github.com/WireMock-Net/WireMock.Net/pull/1160) - Use default timeout for Regex [bug] contributed by [StefH](https://github.com/StefH)
|
||||||
|
- [#1159](https://github.com/WireMock-Net/WireMock.Net/issues/1159) - RegexMatchTimeoutException when trying to parse HTTP version [bug]
|
||||||
|
|
||||||
|
# 1.6.0 (16 August 2024)
|
||||||
|
- [#1042](https://github.com/WireMock-Net/WireMock.Net/pull/1042) - Update + add fluent builder methods [feature] contributed by [StefH](https://github.com/StefH)
|
||||||
|
- [#1109](https://github.com/WireMock-Net/WireMock.Net/pull/1109) - Add Aspire Extension [feature] contributed by [StefH](https://github.com/StefH)
|
||||||
|
- [#1148](https://github.com/WireMock-Net/WireMock.Net/pull/1148) - Use Guid.TryParseExact with format "D" contributed by [StefH](https://github.com/StefH)
|
||||||
|
- [#1157](https://github.com/WireMock-Net/WireMock.Net/pull/1157) - Fix FormUrlEncodedMatcher (MatchOperator.And) [bug] contributed by [StefH](https://github.com/StefH)
|
||||||
|
- [#1158](https://github.com/WireMock-Net/WireMock.Net/pull/1158) - Allow setting Content-Length header on the response [feature] contributed by [StefH](https://github.com/StefH)
|
||||||
|
- [#720](https://github.com/WireMock-Net/WireMock.Net/issues/720) - Response Header Content-Length not available when call HEAD Method [feature]
|
||||||
|
- [#1145](https://github.com/WireMock-Net/WireMock.Net/issues/1145) - Response is auto converting string to guid [bug]
|
||||||
|
- [#1156](https://github.com/WireMock-Net/WireMock.Net/issues/1156) - FormUrlEncodedMatcher is not requiring to match all properties when MatchOperator.And [bug]
|
||||||
|
|
||||||
# 1.5.62 (27 July 2024)
|
# 1.5.62 (27 July 2024)
|
||||||
- [#1147](https://github.com/WireMock-Net/WireMock.Net/pull/1147) - Add FormUrlEncodedMatcher [feature] contributed by [StefH](https://github.com/StefH)
|
- [#1147](https://github.com/WireMock-Net/WireMock.Net/pull/1147) - Add FormUrlEncodedMatcher [feature] contributed by [StefH](https://github.com/StefH)
|
||||||
- [#1143](https://github.com/WireMock-Net/WireMock.Net/issues/1143) - FormEncoded Request fails (404 Not Found) if key value pairs order in mapping is different from request body order [bug]
|
- [#1143](https://github.com/WireMock-Net/WireMock.Net/issues/1143) - FormEncoded Request fails (404 Not Found) if key value pairs order in mapping is different from request body order [bug]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<VersionPrefix>1.5.62</VersionPrefix>
|
<VersionPrefix>1.6.1</VersionPrefix>
|
||||||
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
|
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
|
||||||
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>
|
||||||
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" PrivateAssets="All" />
|
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" PrivateAssets="All" />
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
|
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
rem https://github.com/StefH/GitHubReleaseNotes
|
rem https://github.com/StefH/GitHubReleaseNotes
|
||||||
|
|
||||||
SET version=1.5.62
|
SET version=1.6.1
|
||||||
|
|
||||||
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc duplicate example environment --version %version% --token %GH_TOKEN%
|
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc duplicate example environment --version %version% --token %GH_TOKEN%
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# 1.5.62 (27 July 2024)
|
# 1.6.1 (22 August 2024)
|
||||||
- #1147 Add FormUrlEncodedMatcher [feature]
|
- #1160 Use default timeout for Regex [bug]
|
||||||
- #1143 FormEncoded Request fails (404 Not Found) if key value pairs order in mapping is different from request body order [bug]
|
- #1159 RegexMatchTimeoutException when trying to parse HTTP version [bug]
|
||||||
|
|
||||||
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md
|
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md
|
||||||
@@ -137,7 +137,6 @@ message HelloReply {
|
|||||||
public static void Run()
|
public static void Run()
|
||||||
{
|
{
|
||||||
RunOnLocal();
|
RunOnLocal();
|
||||||
return;
|
|
||||||
|
|
||||||
var mappingBuilder = new MappingBuilder();
|
var mappingBuilder = new MappingBuilder();
|
||||||
mappingBuilder
|
mappingBuilder
|
||||||
@@ -308,17 +307,6 @@ message HelloReply {
|
|||||||
.RespondWith(Response.Create()
|
.RespondWith(Response.Create()
|
||||||
.WithBody("GraphQL is ok")
|
.WithBody("GraphQL is ok")
|
||||||
);
|
);
|
||||||
|
|
||||||
//server
|
|
||||||
// .AddGraphQLSchema("my-graphql", TestSchema, customScalars)
|
|
||||||
// .Given(Request.Create()
|
|
||||||
// .WithPath("/graphql2")
|
|
||||||
// .UsingPost()
|
|
||||||
// )
|
|
||||||
// .WithGraphQLSchema("my-graphql")
|
|
||||||
// .RespondWith(Response.Create()
|
|
||||||
// .WithBody("GraphQL is ok")
|
|
||||||
// );
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MIMEKIT
|
#if MIMEKIT
|
||||||
@@ -377,6 +365,15 @@ message HelloReply {
|
|||||||
.WithHeader("Content-Type", "text/plain")
|
.WithHeader("Content-Type", "text/plain")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
server
|
||||||
|
.Given(Request.Create()
|
||||||
|
.UsingHead()
|
||||||
|
.WithPath("/cl")
|
||||||
|
)
|
||||||
|
.RespondWith(Response.Create()
|
||||||
|
.WithHeader("Content-Length", "42")
|
||||||
|
);
|
||||||
|
|
||||||
server
|
server
|
||||||
.Given(Request.Create()
|
.Given(Request.Create()
|
||||||
.UsingMethod("GET")
|
.UsingMethod("GET")
|
||||||
|
|||||||
@@ -37,7 +37,6 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Aspire.Hosting" Version="8.0.0" />
|
<PackageReference Include="Aspire.Hosting" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Microsoft.IdentityModel.Protocols;
|
|||||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
|
using WireMock.Constants;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
|
|
||||||
@@ -50,7 +51,7 @@ internal class AzureADAuthenticationMatcher : IStringMatcher
|
|||||||
return MatchScores.Mismatch;
|
return MatchScores.Mismatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
var token = Regex.Replace(input, BearerPrefix, string.Empty, RegexOptions.IgnoreCase);
|
var token = Regex.Replace(input, BearerPrefix, string.Empty, RegexOptions.IgnoreCase, WireMockConstants.DefaultRegexTimeout);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,12 +6,9 @@ using WireMock.Matchers;
|
|||||||
|
|
||||||
namespace WireMock.Authentication;
|
namespace WireMock.Authentication;
|
||||||
|
|
||||||
internal class BasicAuthenticationMatcher : RegexMatcher
|
internal class BasicAuthenticationMatcher(string username, string password)
|
||||||
|
: RegexMatcher(BuildPattern(username, password))
|
||||||
{
|
{
|
||||||
public BasicAuthenticationMatcher(string username, string password) : base(BuildPattern(username, password))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string Name => nameof(BasicAuthenticationMatcher);
|
public override string Name => nameof(BasicAuthenticationMatcher);
|
||||||
|
|
||||||
private static string BuildPattern(string username, string password)
|
private static string BuildPattern(string username, string password)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#if NET451 || NET452 || NET46 || NET451 || NET461 || NETSTANDARD1_3 || NETSTANDARD2_0
|
#if NET451 || NET452 || NET46 || NET451 || NET461 || NETSTANDARD1_3 || NETSTANDARD2_0
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using WireMock.Constants;
|
||||||
|
|
||||||
// ReSharper disable once CheckNamespace
|
// ReSharper disable once CheckNamespace
|
||||||
namespace System;
|
namespace System;
|
||||||
@@ -11,7 +12,7 @@ internal static class StringExtensions
|
|||||||
public static string Replace(this string text, string oldValue, string newValue, StringComparison stringComparison)
|
public static string Replace(this string text, string oldValue, string newValue, StringComparison stringComparison)
|
||||||
{
|
{
|
||||||
var options = stringComparison == StringComparison.OrdinalIgnoreCase ? RegexOptions.IgnoreCase : RegexOptions.None;
|
var options = stringComparison == StringComparison.OrdinalIgnoreCase ? RegexOptions.IgnoreCase : RegexOptions.None;
|
||||||
return Regex.Replace(text, oldValue, newValue, options);
|
return Regex.Replace(text, oldValue, newValue, options, WireMockConstants.DefaultRegexTimeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1,15 +1,19 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace WireMock.Constants;
|
namespace WireMock.Constants;
|
||||||
|
|
||||||
internal static class WireMockConstants
|
internal static class WireMockConstants
|
||||||
{
|
{
|
||||||
public const int AdminPriority = int.MinValue;
|
internal static readonly TimeSpan DefaultRegexTimeout = TimeSpan.FromSeconds(10);
|
||||||
public const int MinPriority = -1_000_000;
|
|
||||||
public const int ProxyPriority = -2_000_000;
|
internal const int AdminPriority = int.MinValue;
|
||||||
|
internal const int MinPriority = -1_000_000;
|
||||||
|
internal const int ProxyPriority = -2_000_000;
|
||||||
|
|
||||||
public const string ContentTypeJson = "application/json";
|
internal const string ContentTypeJson = "application/json";
|
||||||
public const string ContentTypeTextPlain = "text/plain";
|
internal const string ContentTypeTextPlain = "text/plain";
|
||||||
|
|
||||||
public const string NoMatchingFound = "No matching mapping found";
|
internal const string NoMatchingFound = "No matching mapping found";
|
||||||
}
|
}
|
||||||
@@ -14,12 +14,12 @@ namespace WireMock.Http;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class HttpKnownHeaderNames
|
internal static class HttpKnownHeaderNames
|
||||||
{
|
{
|
||||||
// https://docs.microsoft.com/en-us/dotnet/api/system.net.webheadercollection.isrestricted
|
// - https://docs.microsoft.com/en-us/dotnet/api/system.net.webheadercollection.isrestricted
|
||||||
|
// - ContentLength is allowed per #720
|
||||||
private static readonly string[] RestrictedResponseHeaders =
|
private static readonly string[] RestrictedResponseHeaders =
|
||||||
{
|
{
|
||||||
Accept,
|
Accept,
|
||||||
Connection,
|
Connection,
|
||||||
ContentLength,
|
|
||||||
ContentType,
|
ContentType,
|
||||||
Date, // RFC1123Pattern
|
Date, // RFC1123Pattern
|
||||||
Expect,
|
Expect,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
@@ -27,7 +28,7 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pattern">The pattern.</param>
|
/// <param name="pattern">The pattern.</param>
|
||||||
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
||||||
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
|
||||||
public FormUrlEncodedMatcher(
|
public FormUrlEncodedMatcher(
|
||||||
AnyOf<string, StringPattern> pattern,
|
AnyOf<string, StringPattern> pattern,
|
||||||
bool ignoreCase = false,
|
bool ignoreCase = false,
|
||||||
@@ -42,7 +43,7 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
|
|||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="pattern">The pattern.</param>
|
/// <param name="pattern">The pattern.</param>
|
||||||
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
||||||
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
|
||||||
public FormUrlEncodedMatcher(
|
public FormUrlEncodedMatcher(
|
||||||
MatchBehaviour matchBehaviour,
|
MatchBehaviour matchBehaviour,
|
||||||
AnyOf<string, StringPattern> pattern,
|
AnyOf<string, StringPattern> pattern,
|
||||||
@@ -57,7 +58,7 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
||||||
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
|
||||||
public FormUrlEncodedMatcher(
|
public FormUrlEncodedMatcher(
|
||||||
AnyOf<string, StringPattern>[] patterns,
|
AnyOf<string, StringPattern>[] patterns,
|
||||||
bool ignoreCase = false,
|
bool ignoreCase = false,
|
||||||
@@ -72,7 +73,7 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
|
|||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
||||||
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
|
||||||
public FormUrlEncodedMatcher(
|
public FormUrlEncodedMatcher(
|
||||||
MatchBehaviour matchBehaviour,
|
MatchBehaviour matchBehaviour,
|
||||||
AnyOf<string, StringPattern>[] patterns,
|
AnyOf<string, StringPattern>[] patterns,
|
||||||
@@ -112,7 +113,20 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
|
|||||||
return new MatchResult(MatchScores.Mismatch);
|
return new MatchResult(MatchScores.Mismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var matches = GetMatches(inputNameValueCollection);
|
||||||
|
|
||||||
|
var score = MatchScores.ToScore(matches, MatchOperator);
|
||||||
|
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score));
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool[] GetMatches(IDictionary<string, string> inputNameValueCollection)
|
||||||
|
{
|
||||||
var matches = new List<bool>();
|
var matches = new List<bool>();
|
||||||
|
if (_pairs.Count > inputNameValueCollection.Count)
|
||||||
|
{
|
||||||
|
matches.AddRange(Enumerable.Repeat(false, _pairs.Count - inputNameValueCollection.Count));
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var inputKeyValuePair in inputNameValueCollection)
|
foreach (var inputKeyValuePair in inputNameValueCollection)
|
||||||
{
|
{
|
||||||
var match = false;
|
var match = false;
|
||||||
@@ -132,8 +146,7 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
|
|||||||
matches.Add(match);
|
matches.Add(match);
|
||||||
}
|
}
|
||||||
|
|
||||||
var score = MatchScores.ToScore(matches.ToArray(), MatchOperator);
|
return matches.ToArray();
|
||||||
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ using System.Linq;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using Stef.Validation;
|
||||||
|
using WireMock.Constants;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.RegularExpressions;
|
using WireMock.RegularExpressions;
|
||||||
using Stef.Validation;
|
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
|
|||||||
bool ignoreCase = false,
|
bool ignoreCase = false,
|
||||||
bool useRegexExtended = true,
|
bool useRegexExtended = true,
|
||||||
MatchOperator matchOperator = MatchOperator.Or) :
|
MatchOperator matchOperator = MatchOperator.Or) :
|
||||||
this(MatchBehaviour.AcceptOnMatch, new[] { pattern }, ignoreCase, useRegexExtended, matchOperator)
|
this(MatchBehaviour.AcceptOnMatch, [pattern], ignoreCase, useRegexExtended, matchOperator)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
|
|||||||
bool ignoreCase = false,
|
bool ignoreCase = false,
|
||||||
bool useRegexExtended = true,
|
bool useRegexExtended = true,
|
||||||
MatchOperator matchOperator = MatchOperator.Or) :
|
MatchOperator matchOperator = MatchOperator.Or) :
|
||||||
this(matchBehaviour, new[] { pattern }, ignoreCase, useRegexExtended, matchOperator)
|
this(matchBehaviour, [pattern], ignoreCase, useRegexExtended, matchOperator)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +87,7 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
|
|||||||
options |= RegexOptions.IgnoreCase;
|
options |= RegexOptions.IgnoreCase;
|
||||||
}
|
}
|
||||||
|
|
||||||
_expressions = patterns.Select(p => useRegexExtended ? new RegexExtended(p.GetPattern(), options) : new Regex(p.GetPattern(), options)).ToArray();
|
_expressions = patterns.Select(p => useRegexExtended ? new RegexExtended(p.GetPattern(), options) : new Regex(p.GetPattern(), options, WireMockConstants.DefaultRegexTimeout)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -37,13 +37,20 @@ namespace WireMock.Owin.Mappers
|
|||||||
private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
|
private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
|
||||||
|
|
||||||
// https://msdn.microsoft.com/en-us/library/78h415ay(v=vs.110).aspx
|
// https://msdn.microsoft.com/en-us/library/78h415ay(v=vs.110).aspx
|
||||||
#if !USE_ASPNETCORE
|
private static readonly IDictionary<string, Action<IResponse, bool, WireMockList<string>>> ResponseHeadersToFix =
|
||||||
private static readonly IDictionary<string, Action<IResponse, WireMockList<string>>> ResponseHeadersToFix = new Dictionary<string, Action<IResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
|
new Dictionary<string, Action<IResponse, bool, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase)
|
||||||
#else
|
{
|
||||||
private static readonly IDictionary<string, Action<IResponse, WireMockList<string>>> ResponseHeadersToFix = new Dictionary<string, Action<IResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
|
{ HttpKnownHeaderNames.ContentType, (r, _, v) => r.ContentType = v.FirstOrDefault() },
|
||||||
#endif
|
{ HttpKnownHeaderNames.ContentLength, (r, hasBody, v) =>
|
||||||
{ HttpKnownHeaderNames.ContentType, (r, v) => r.ContentType = v.FirstOrDefault() }
|
{
|
||||||
};
|
// Only set the Content-Length header if the response does not have a body
|
||||||
|
if (!hasBody && long.TryParse(v.FirstOrDefault(), out var contentLength))
|
||||||
|
{
|
||||||
|
r.ContentLength = contentLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor
|
/// Constructor
|
||||||
@@ -83,23 +90,21 @@ namespace WireMock.Owin.Mappers
|
|||||||
}
|
}
|
||||||
|
|
||||||
var statusCodeType = responseMessage.StatusCode?.GetType();
|
var statusCodeType = responseMessage.StatusCode?.GetType();
|
||||||
switch (statusCodeType)
|
if (statusCodeType != null)
|
||||||
{
|
{
|
||||||
case { } when statusCodeType == typeof(int) || statusCodeType == typeof(int?) || statusCodeType.GetTypeInfo().IsEnum:
|
if (statusCodeType == typeof(int) || statusCodeType == typeof(int?) || statusCodeType.GetTypeInfo().IsEnum)
|
||||||
|
{
|
||||||
response.StatusCode = MapStatusCode((int)responseMessage.StatusCode!);
|
response.StatusCode = MapStatusCode((int)responseMessage.StatusCode!);
|
||||||
break;
|
}
|
||||||
|
else if (statusCodeType == typeof(string))
|
||||||
case { } when statusCodeType == typeof(string):
|
{
|
||||||
// Note: this case will also match on null
|
// Note: this case will also match on null
|
||||||
int.TryParse(responseMessage.StatusCode as string, out var result);
|
int.TryParse(responseMessage.StatusCode as string, out var statusCodeTypeAsInt);
|
||||||
response.StatusCode = MapStatusCode(result);
|
response.StatusCode = MapStatusCode(statusCodeTypeAsInt);
|
||||||
break;
|
}
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetResponseHeaders(responseMessage, response);
|
SetResponseHeaders(responseMessage, bytes, response);
|
||||||
|
|
||||||
if (bytes != null)
|
if (bytes != null)
|
||||||
{
|
{
|
||||||
@@ -160,7 +165,7 @@ namespace WireMock.Owin.Mappers
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetResponseHeaders(IResponseMessage responseMessage, IResponse response)
|
private static void SetResponseHeaders(IResponseMessage responseMessage, byte[]? bytes, IResponse response)
|
||||||
{
|
{
|
||||||
// Force setting the Date header (#577)
|
// Force setting the Date header (#577)
|
||||||
AppendResponseHeader(
|
AppendResponseHeader(
|
||||||
@@ -179,11 +184,11 @@ namespace WireMock.Owin.Mappers
|
|||||||
var value = item.Value;
|
var value = item.Value;
|
||||||
if (ResponseHeadersToFix.TryGetValue(headerName, out var action))
|
if (ResponseHeadersToFix.TryGetValue(headerName, out var action))
|
||||||
{
|
{
|
||||||
action?.Invoke(response, value);
|
action?.Invoke(response, bytes != null, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Check if this response header can be added (#148 and #227)
|
// Check if this response header can be added (#148, #227 and #720)
|
||||||
if (!HttpKnownHeaderNames.IsRestrictedResponseHeader(headerName))
|
if (!HttpKnownHeaderNames.IsRestrictedResponseHeader(headerName))
|
||||||
{
|
{
|
||||||
AppendResponseHeader(response, headerName, value.ToArray());
|
AppendResponseHeader(response, headerName, value.ToArray());
|
||||||
@@ -206,7 +211,7 @@ namespace WireMock.Owin.Mappers
|
|||||||
var value = item.Value;
|
var value = item.Value;
|
||||||
if (ResponseHeadersToFix.TryGetValue(headerName, out var action))
|
if (ResponseHeadersToFix.TryGetValue(headerName, out var action))
|
||||||
{
|
{
|
||||||
action?.Invoke(response, value);
|
action?.Invoke(response, false, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,22 +10,28 @@ namespace WireMock.Serialization;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates sanitized file names for mappings
|
/// Creates sanitized file names for mappings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class MappingFileNameSanitizer
|
public class MappingFileNameSanitizer
|
||||||
{
|
{
|
||||||
private const string SpaceChar = " ";
|
|
||||||
private const char ReplaceChar = '_';
|
private const char ReplaceChar = '_';
|
||||||
|
|
||||||
|
private readonly WireMockServerSettings _settings;
|
||||||
|
|
||||||
|
public MappingFileNameSanitizer(WireMockServerSettings settings)
|
||||||
|
{
|
||||||
|
_settings = Guard.NotNull(settings);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates sanitized file names for mappings
|
/// Creates sanitized file names for mappings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string BuildSanitizedFileName(IMapping mapping, ProxyAndRecordSettings? proxyAndRecordSettings)
|
public string BuildSanitizedFileName(IMapping mapping)
|
||||||
{
|
{
|
||||||
string name;
|
string name;
|
||||||
if (!string.IsNullOrEmpty(mapping.Title))
|
if (!string.IsNullOrEmpty(mapping.Title))
|
||||||
{
|
{
|
||||||
// remove 'Proxy Mapping for ' and an extra space character after the HTTP request method
|
// remove 'Proxy Mapping for ' and an extra space character after the HTTP request method
|
||||||
name = mapping.Title!.Replace(ProxyAndRecordSettings.DefaultPrefixForSavedMappingFile, string.Empty).Replace(SpaceChar, string.Empty);
|
name = mapping.Title.Replace(ProxyAndRecordSettings.DefaultPrefixForSavedMappingFile, "").Replace(' '.ToString(), string.Empty);
|
||||||
if (proxyAndRecordSettings?.AppendGuidToSavedMappingFile == true)
|
if (_settings.ProxyAndRecordSettings?.AppendGuidToSavedMappingFile == true)
|
||||||
{
|
{
|
||||||
name += $"{ReplaceChar}{mapping.Guid}";
|
name += $"{ReplaceChar}{mapping.Guid}";
|
||||||
}
|
}
|
||||||
@@ -35,11 +41,10 @@ internal class MappingFileNameSanitizer
|
|||||||
name = mapping.Guid.ToString();
|
name = mapping.Guid.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(proxyAndRecordSettings?.PrefixForSavedMappingFile))
|
if (!string.IsNullOrEmpty(_settings.ProxyAndRecordSettings?.PrefixForSavedMappingFile))
|
||||||
{
|
{
|
||||||
name = $"{proxyAndRecordSettings.PrefixForSavedMappingFile}{ReplaceChar}{name}";
|
name = $"{_settings.ProxyAndRecordSettings.PrefixForSavedMappingFile}{ReplaceChar}{name}";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"{Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, ReplaceChar))}.json";
|
return $"{Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, ReplaceChar))}.json";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
|
using WireMock.Constants;
|
||||||
|
|
||||||
namespace WireMock.Util;
|
namespace WireMock.Util;
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ namespace WireMock.Util;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class HttpVersionParser
|
internal static class HttpVersionParser
|
||||||
{
|
{
|
||||||
private static readonly Regex HttpVersionRegex = new(@"HTTP/(\d+(\.\d+)?(?!\.))", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled, TimeSpan.FromMilliseconds(100));
|
private static readonly Regex HttpVersionRegex = new(@"HTTP/(\d+(\.\d+)?(?!\.))", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled, WireMockConstants.DefaultRegexTimeout);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Try to extract the version (as a string) from the protocol.
|
/// Try to extract the version (as a string) from the protocol.
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using WireMock.Constants;
|
||||||
|
|
||||||
namespace WireMock.Util;
|
namespace WireMock.Util;
|
||||||
|
|
||||||
@@ -13,7 +14,7 @@ namespace WireMock.Util;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class PortUtils
|
internal static class PortUtils
|
||||||
{
|
{
|
||||||
private static readonly Regex UrlDetailsRegex = new(@"^((?<proto>\w+)://)(?<host>[^/]+?):(?<port>\d+)\/?$", RegexOptions.Compiled);
|
private static readonly Regex UrlDetailsRegex = new(@"^((?<proto>\w+)://)(?<host>[^/]+?):(?<port>\d+)\/?$", RegexOptions.Compiled, WireMockConstants.DefaultRegexTimeout);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds a free TCP port.
|
/// Finds a free TCP port.
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using WireMock.Constants;
|
||||||
using WireMock.RegularExpressions;
|
using WireMock.RegularExpressions;
|
||||||
|
|
||||||
namespace WireMock.Util;
|
namespace WireMock.Util;
|
||||||
|
|
||||||
internal static class RegexUtils
|
internal static class RegexUtils
|
||||||
{
|
{
|
||||||
private static readonly TimeSpan RegexTimeOut = new(0, 0, 10);
|
|
||||||
|
|
||||||
public static Dictionary<string, string> GetNamedGroups(Regex regex, string input)
|
public static Dictionary<string, string> GetNamedGroups(Regex regex, string input)
|
||||||
{
|
{
|
||||||
var namedGroupsDictionary = new Dictionary<string, string>();
|
var namedGroupsDictionary = new Dictionary<string, string>();
|
||||||
@@ -38,11 +36,11 @@ internal static class RegexUtils
|
|||||||
{
|
{
|
||||||
if (useRegexExtended)
|
if (useRegexExtended)
|
||||||
{
|
{
|
||||||
var regexExtended = new RegexExtended(pattern!, RegexOptions.None, RegexTimeOut);
|
var regexExtended = new RegexExtended(pattern!, RegexOptions.None, WireMockConstants.DefaultRegexTimeout);
|
||||||
return (true, regexExtended.IsMatch(input));
|
return (true, regexExtended.IsMatch(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
var regex = new Regex(pattern, RegexOptions.None, RegexTimeOut);
|
var regex = new Regex(pattern, RegexOptions.None, WireMockConstants.DefaultRegexTimeout);
|
||||||
return (true, regex.IsMatch(input));
|
return (true, regex.IsMatch(input));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|||||||
@@ -75,4 +75,25 @@ public class FormUrlEncodedMatcherTest
|
|||||||
// Assert
|
// Assert
|
||||||
score.Should().Be(expected);
|
score.Should().Be(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task FormUrlEncodedMatcher_IsMatch_And_MatchAllProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var content = new FormUrlEncodedContent(new[]
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, string>("name", "John Doe"),
|
||||||
|
new KeyValuePair<string, string>("email", "johndoe@example.com")
|
||||||
|
});
|
||||||
|
var contentAsString = await content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
// The expectation is that the matcher requires all properties to be present in the content.
|
||||||
|
var matcher = new FormUrlEncodedMatcher(["name=*", "email=*", "required=*"], matchOperator: MatchOperator.And);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var score = matcher.IsMatch(contentAsString).IsPerfect();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
score.Should().BeFalse();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -25,278 +25,277 @@ using Response = Microsoft.AspNetCore.Http.HttpResponse;
|
|||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace WireMock.Net.Tests.Owin.Mappers
|
namespace WireMock.Net.Tests.Owin.Mappers;
|
||||||
|
|
||||||
|
public class OwinResponseMapperTests
|
||||||
{
|
{
|
||||||
public class OwinResponseMapperTests
|
private static readonly Task CompletedTask = Task.FromResult(true);
|
||||||
|
private readonly OwinResponseMapper _sut;
|
||||||
|
private readonly Mock<IResponse> _responseMock;
|
||||||
|
private readonly Mock<Stream> _stream;
|
||||||
|
private readonly Mock<IHeaderDictionary> _headers;
|
||||||
|
private readonly Mock<IFileSystemHandler> _fileSystemHandlerMock;
|
||||||
|
private readonly Mock<IWireMockMiddlewareOptions> _optionsMock;
|
||||||
|
|
||||||
|
public OwinResponseMapperTests()
|
||||||
{
|
{
|
||||||
private static readonly Task CompletedTask = Task.FromResult(true);
|
_stream = new Mock<Stream>();
|
||||||
private readonly OwinResponseMapper _sut;
|
_stream.SetupAllProperties();
|
||||||
private readonly Mock<IResponse> _responseMock;
|
_stream.Setup(s => s.WriteAsync(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<CancellationToken>())).Returns(CompletedTask);
|
||||||
private readonly Mock<Stream> _stream;
|
|
||||||
private readonly Mock<IHeaderDictionary> _headers;
|
|
||||||
private readonly Mock<IFileSystemHandler> _fileSystemHandlerMock;
|
|
||||||
private readonly Mock<IWireMockMiddlewareOptions> _optionsMock;
|
|
||||||
|
|
||||||
public OwinResponseMapperTests()
|
_fileSystemHandlerMock = new Mock<IFileSystemHandler>();
|
||||||
{
|
_fileSystemHandlerMock.SetupAllProperties();
|
||||||
_stream = new Mock<Stream>();
|
|
||||||
_stream.SetupAllProperties();
|
|
||||||
_stream.Setup(s => s.WriteAsync(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<CancellationToken>())).Returns(CompletedTask);
|
|
||||||
|
|
||||||
_fileSystemHandlerMock = new Mock<IFileSystemHandler>();
|
_optionsMock = new Mock<IWireMockMiddlewareOptions>();
|
||||||
_fileSystemHandlerMock.SetupAllProperties();
|
_optionsMock.SetupAllProperties();
|
||||||
|
_optionsMock.SetupGet(o => o.FileSystemHandler).Returns(_fileSystemHandlerMock.Object);
|
||||||
|
|
||||||
_optionsMock = new Mock<IWireMockMiddlewareOptions>();
|
_headers = new Mock<IHeaderDictionary>();
|
||||||
_optionsMock.SetupAllProperties();
|
_headers.SetupAllProperties();
|
||||||
_optionsMock.SetupGet(o => o.FileSystemHandler).Returns(_fileSystemHandlerMock.Object);
|
|
||||||
|
|
||||||
_headers = new Mock<IHeaderDictionary>();
|
|
||||||
_headers.SetupAllProperties();
|
|
||||||
#if NET452
|
#if NET452
|
||||||
_headers.Setup(h => h.AppendValues(It.IsAny<string>(), It.IsAny<string[]>()));
|
_headers.Setup(h => h.AppendValues(It.IsAny<string>(), It.IsAny<string[]>()));
|
||||||
#else
|
#else
|
||||||
_headers.Setup(h => h.Add(It.IsAny<string>(), It.IsAny<StringValues>()));
|
_headers.Setup(h => h.Add(It.IsAny<string>(), It.IsAny<StringValues>()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_responseMock = new Mock<IResponse>();
|
_responseMock = new Mock<IResponse>();
|
||||||
_responseMock.SetupAllProperties();
|
_responseMock.SetupAllProperties();
|
||||||
_responseMock.SetupGet(r => r.Body).Returns(_stream.Object);
|
_responseMock.SetupGet(r => r.Body).Returns(_stream.Object);
|
||||||
_responseMock.SetupGet(r => r.Headers).Returns(_headers.Object);
|
_responseMock.SetupGet(r => r.Headers).Returns(_headers.Object);
|
||||||
|
|
||||||
_sut = new OwinResponseMapper(_optionsMock.Object);
|
_sut = new OwinResponseMapper(_optionsMock.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task OwinResponseMapper_MapAsync_Null()
|
public async Task OwinResponseMapper_MapAsync_Null()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
await _sut.MapAsync(null, _responseMock.Object).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(300, 300)]
|
||||||
|
[InlineData(500, 500)]
|
||||||
|
public async Task OwinResponseMapper_MapAsync_Valid_StatusCode(object code, int expected)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var responseMessage = new ResponseMessage
|
||||||
{
|
{
|
||||||
// Act
|
StatusCode = code
|
||||||
await _sut.MapAsync(null, _responseMock.Object).ConfigureAwait(false);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
// Act
|
||||||
[InlineData(300, 300)]
|
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
||||||
[InlineData(500, 500)]
|
|
||||||
public async Task OwinResponseMapper_MapAsync_Valid_StatusCode(object code, int expected)
|
// Assert
|
||||||
|
_responseMock.VerifySet(r => r.StatusCode = expected, Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(0, 200)]
|
||||||
|
[InlineData(-1, 200)]
|
||||||
|
[InlineData(10000, 200)]
|
||||||
|
[InlineData(300, 300)]
|
||||||
|
public async Task OwinResponseMapper_MapAsync_Invalid_StatusCode_When_AllowOnlyDefinedHttpStatusCodeInResponseSet_Is_True(object code, int expected)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_optionsMock.SetupGet(o => o.AllowOnlyDefinedHttpStatusCodeInResponse).Returns(true);
|
||||||
|
var responseMessage = new ResponseMessage
|
||||||
{
|
{
|
||||||
// Arrange
|
StatusCode = code
|
||||||
var responseMessage = new ResponseMessage
|
};
|
||||||
{
|
|
||||||
StatusCode = code
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_responseMock.VerifySet(r => r.StatusCode = expected, Times.Once);
|
_responseMock.VerifySet(r => r.StatusCode = expected, Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData(0, 200)]
|
public async Task OwinResponseMapper_MapAsync_StatusCode_Is_Null()
|
||||||
[InlineData(-1, 200)]
|
{
|
||||||
[InlineData(10000, 200)]
|
// Arrange
|
||||||
[InlineData(300, 300)]
|
var responseMessage = new ResponseMessage
|
||||||
public async Task OwinResponseMapper_MapAsync_Invalid_StatusCode_When_AllowOnlyDefinedHttpStatusCodeInResponseSet_Is_True(object code, int expected)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
StatusCode = null
|
||||||
_optionsMock.SetupGet(o => o.AllowOnlyDefinedHttpStatusCodeInResponse).Returns(true);
|
};
|
||||||
var responseMessage = new ResponseMessage
|
|
||||||
{
|
|
||||||
StatusCode = code
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_responseMock.VerifySet(r => r.StatusCode = expected, Times.Once);
|
_responseMock.VerifySet(r => r.StatusCode = It.IsAny<int>(), Times.Never);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Theory]
|
||||||
public async Task OwinResponseMapper_MapAsync_StatusCode_Is_Null()
|
[InlineData(0, 0)]
|
||||||
|
[InlineData(-1, -1)]
|
||||||
|
[InlineData(10000, 10000)]
|
||||||
|
[InlineData(300, 300)]
|
||||||
|
public async Task OwinResponseMapper_MapAsync_StatusCode_Is_NotInEnumRange(object code, int expected)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var responseMessage = new ResponseMessage
|
||||||
{
|
{
|
||||||
// Arrange
|
StatusCode = code
|
||||||
var responseMessage = new ResponseMessage
|
};
|
||||||
{
|
|
||||||
StatusCode = null
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_responseMock.VerifySet(r => r.StatusCode = It.IsAny<int>(), Times.Never);
|
_responseMock.VerifySet(r => r.StatusCode = expected, Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData(0, 0)]
|
public async Task OwinResponseMapper_MapAsync_NoBody()
|
||||||
[InlineData(-1, -1)]
|
{
|
||||||
[InlineData(10000, 10000)]
|
// Arrange
|
||||||
[InlineData(300, 300)]
|
var responseMessage = new ResponseMessage
|
||||||
public async Task OwinResponseMapper_MapAsync_StatusCode_Is_NotInEnumRange(object code, int expected)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
Headers = new Dictionary<string, WireMockList<string>>()
|
||||||
var responseMessage = new ResponseMessage
|
};
|
||||||
{
|
|
||||||
StatusCode = code
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_responseMock.VerifySet(r => r.StatusCode = expected, Times.Once);
|
_stream.Verify(s => s.WriteAsync(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<CancellationToken>()), Times.Never);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task OwinResponseMapper_MapAsync_NoBody()
|
public async Task OwinResponseMapper_MapAsync_Body()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
string body = "abcd";
|
||||||
|
var responseMessage = new ResponseMessage
|
||||||
{
|
{
|
||||||
// Arrange
|
Headers = new Dictionary<string, WireMockList<string>>(),
|
||||||
var responseMessage = new ResponseMessage
|
BodyData = new BodyData { DetectedBodyType = BodyType.String, BodyAsString = body }
|
||||||
{
|
};
|
||||||
Headers = new Dictionary<string, WireMockList<string>>()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_stream.Verify(s => s.WriteAsync(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<CancellationToken>()), Times.Never);
|
_stream.Verify(s => s.WriteAsync(new byte[] { 97, 98, 99, 100 }, 0, 4, It.IsAny<CancellationToken>()), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task OwinResponseMapper_MapAsync_Body()
|
public async Task OwinResponseMapper_MapAsync_BodyAsBytes()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var bytes = new byte[] { 48, 49 };
|
||||||
|
var responseMessage = new ResponseMessage
|
||||||
{
|
{
|
||||||
// Arrange
|
Headers = new Dictionary<string, WireMockList<string>>(),
|
||||||
string body = "abcd";
|
BodyData = new BodyData { DetectedBodyType = BodyType.Bytes, BodyAsBytes = bytes }
|
||||||
var responseMessage = new ResponseMessage
|
};
|
||||||
{
|
|
||||||
Headers = new Dictionary<string, WireMockList<string>>(),
|
|
||||||
BodyData = new BodyData { DetectedBodyType = BodyType.String, BodyAsString = body }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_stream.Verify(s => s.WriteAsync(new byte[] { 97, 98, 99, 100 }, 0, 4, It.IsAny<CancellationToken>()), Times.Once);
|
_stream.Verify(s => s.WriteAsync(bytes, 0, bytes.Length, It.IsAny<CancellationToken>()), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task OwinResponseMapper_MapAsync_BodyAsBytes()
|
public async Task OwinResponseMapper_MapAsync_BodyAsJson()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var json = new { t = "x", i = (string?)null };
|
||||||
|
var responseMessage = new ResponseMessage
|
||||||
{
|
{
|
||||||
// Arrange
|
Headers = new Dictionary<string, WireMockList<string>>(),
|
||||||
var bytes = new byte[] { 48, 49 };
|
BodyData = new BodyData { DetectedBodyType = BodyType.Json, BodyAsJson = json, BodyAsJsonIndented = false }
|
||||||
var responseMessage = new ResponseMessage
|
};
|
||||||
{
|
|
||||||
Headers = new Dictionary<string, WireMockList<string>>(),
|
|
||||||
BodyData = new BodyData { DetectedBodyType = BodyType.Bytes, BodyAsBytes = bytes }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_stream.Verify(s => s.WriteAsync(bytes, 0, bytes.Length, It.IsAny<CancellationToken>()), Times.Once);
|
_stream.Verify(s => s.WriteAsync(new byte[] { 123, 34, 116, 34, 58, 34, 120, 34, 125 }, 0, 9, It.IsAny<CancellationToken>()), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task OwinResponseMapper_MapAsync_BodyAsJson()
|
public async Task OwinResponseMapper_MapAsync_SetResponseHeaders()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var responseMessage = new ResponseMessage
|
||||||
{
|
{
|
||||||
// Arrange
|
Headers = new Dictionary<string, WireMockList<string>> { { "h", new WireMockList<string>("x", "y") } }
|
||||||
var json = new { t = "x", i = (string?)null };
|
};
|
||||||
var responseMessage = new ResponseMessage
|
|
||||||
{
|
|
||||||
Headers = new Dictionary<string, WireMockList<string>>(),
|
|
||||||
BodyData = new BodyData { DetectedBodyType = BodyType.Json, BodyAsJson = json, BodyAsJsonIndented = false }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_stream.Verify(s => s.WriteAsync(new byte[] { 123, 34, 116, 34, 58, 34, 120, 34, 125 }, 0, 9, It.IsAny<CancellationToken>()), Times.Once);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task OwinResponseMapper_MapAsync_SetResponseHeaders()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var responseMessage = new ResponseMessage
|
|
||||||
{
|
|
||||||
Headers = new Dictionary<string, WireMockList<string>> { { "h", new WireMockList<string>("x", "y") } }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
#if NET452
|
#if NET452
|
||||||
_headers.Verify(h => h.AppendValues("h", new string[] { "x", "y" }), Times.Once);
|
_headers.Verify(h => h.AppendValues("h", new string[] { "x", "y" }), Times.Once);
|
||||||
#else
|
#else
|
||||||
var v = new StringValues();
|
var v = new StringValues();
|
||||||
_headers.Verify(h => h.TryGetValue("h", out v), Times.Once);
|
_headers.Verify(h => h.TryGetValue("h", out v), Times.Once);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void OwinResponseMapper_MapAsync_BodyAsFile_ThrowsException()
|
public void OwinResponseMapper_MapAsync_BodyAsFile_ThrowsException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var responseMessage = new ResponseMessage
|
||||||
{
|
{
|
||||||
// Arrange
|
Headers = new Dictionary<string, WireMockList<string>>(),
|
||||||
var responseMessage = new ResponseMessage
|
BodyData = new BodyData { DetectedBodyType = BodyType.File, BodyAsFile = string.Empty }
|
||||||
{
|
};
|
||||||
Headers = new Dictionary<string, WireMockList<string>>(),
|
_fileSystemHandlerMock.Setup(f => f.ReadResponseBodyAsFile(It.IsAny<string>())).Throws<FileNotFoundException>();
|
||||||
BodyData = new BodyData { DetectedBodyType = BodyType.File, BodyAsFile = string.Empty }
|
|
||||||
};
|
|
||||||
_fileSystemHandlerMock.Setup(f => f.ReadResponseBodyAsFile(It.IsAny<string>())).Throws<FileNotFoundException>();
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
Func<Task> action = () => _sut.MapAsync(responseMessage, _responseMock.Object);
|
Func<Task> action = () => _sut.MapAsync(responseMessage, _responseMock.Object);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
action.Should().ThrowAsync<FileNotFoundException>();
|
action.Should().ThrowAsync<FileNotFoundException>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task OwinResponseMapper_MapAsync_WithFault_EMPTY_RESPONSE()
|
public async Task OwinResponseMapper_MapAsync_WithFault_EMPTY_RESPONSE()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
string body = "abc";
|
||||||
|
var responseMessage = new ResponseMessage
|
||||||
{
|
{
|
||||||
// Arrange
|
Headers = new Dictionary<string, WireMockList<string>>(),
|
||||||
string body = "abc";
|
BodyData = new BodyData { DetectedBodyType = BodyType.String, BodyAsString = body },
|
||||||
var responseMessage = new ResponseMessage
|
FaultType = FaultType.EMPTY_RESPONSE
|
||||||
{
|
};
|
||||||
Headers = new Dictionary<string, WireMockList<string>>(),
|
|
||||||
BodyData = new BodyData { DetectedBodyType = BodyType.String, BodyAsString = body },
|
|
||||||
FaultType = FaultType.EMPTY_RESPONSE
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_stream.Verify(s => s.WriteAsync(EmptyArray<byte>.Value, 0, 0, It.IsAny<CancellationToken>()), Times.Once);
|
_stream.Verify(s => s.WriteAsync(EmptyArray<byte>.Value, 0, 0, It.IsAny<CancellationToken>()), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("abcd", BodyType.String)]
|
[InlineData("abcd", BodyType.String)]
|
||||||
[InlineData("", BodyType.String)]
|
[InlineData("", BodyType.String)]
|
||||||
[InlineData(null, BodyType.None)]
|
[InlineData(null, BodyType.None)]
|
||||||
public async Task OwinResponseMapper_MapAsync_WithFault_MALFORMED_RESPONSE_CHUNK(string body, BodyType detected)
|
public async Task OwinResponseMapper_MapAsync_WithFault_MALFORMED_RESPONSE_CHUNK(string body, BodyType detected)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var responseMessage = new ResponseMessage
|
||||||
{
|
{
|
||||||
// Arrange
|
Headers = new Dictionary<string, WireMockList<string>>(),
|
||||||
var responseMessage = new ResponseMessage
|
BodyData = new BodyData { DetectedBodyType = detected, BodyAsString = body },
|
||||||
{
|
StatusCode = 100,
|
||||||
Headers = new Dictionary<string, WireMockList<string>>(),
|
FaultType = FaultType.MALFORMED_RESPONSE_CHUNK
|
||||||
BodyData = new BodyData { DetectedBodyType = detected, BodyAsString = body },
|
};
|
||||||
StatusCode = 100,
|
|
||||||
FaultType = FaultType.MALFORMED_RESPONSE_CHUNK
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_responseMock.VerifySet(r => r.StatusCode = 100, Times.Once);
|
_responseMock.VerifySet(r => r.StatusCode = 100, Times.Once);
|
||||||
_stream.Verify(s => s.WriteAsync(It.IsAny<byte[]>(), 0, It.Is<int>(count => count >= 0), It.IsAny<CancellationToken>()), Times.Once);
|
_stream.Verify(s => s.WriteAsync(It.IsAny<byte[]>(), 0, It.Is<int>(count => count >= 0), It.IsAny<CancellationToken>()), Times.Once);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,7 @@ using FluentAssertions;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NFluent;
|
using NFluent;
|
||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
|
using WireMock.Http;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Net.Tests.Serialization;
|
using WireMock.Net.Tests.Serialization;
|
||||||
using WireMock.Net.Xunit;
|
using WireMock.Net.Xunit;
|
||||||
@@ -351,7 +352,7 @@ public partial class WireMockServerTests
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task WireMockServer_Should_exclude_restrictedResponseHeader()
|
public async Task WireMockServer_Should_Exclude_RestrictedResponseHeader()
|
||||||
{
|
{
|
||||||
// Assign
|
// Assign
|
||||||
string path = $"/foo_{Guid.NewGuid()}";
|
string path = $"/foo_{Guid.NewGuid()}";
|
||||||
@@ -371,6 +372,26 @@ public partial class WireMockServerTests
|
|||||||
server.Stop();
|
server.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact] // #720
|
||||||
|
public async Task WireMockServer_Should_AllowResponseHeaderContentLength_For_HEAD()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
const string length = "42";
|
||||||
|
var path = $"/cl_{Guid.NewGuid()}";
|
||||||
|
using var server = WireMockServer.Start();
|
||||||
|
|
||||||
|
server
|
||||||
|
.Given(Request.Create().WithPath(path).UsingHead())
|
||||||
|
.RespondWith(Response.Create().WithHeader(HttpKnownHeaderNames.ContentLength, length));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Head, path);
|
||||||
|
var response = await server.CreateClient().SendAsync(httpRequestMessage).ConfigureAwait(false);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
response.Content.Headers.GetValues(HttpKnownHeaderNames.ContentLength).Should().Contain(length);
|
||||||
|
}
|
||||||
|
|
||||||
#if !NET452 && !NET461
|
#if !NET452 && !NET461
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("TRACE")]
|
[InlineData("TRACE")]
|
||||||
|
|||||||
Reference in New Issue
Block a user