mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-28 03:07:01 +02:00
Merge branch 'master' into SystemTextJsonMatcher
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using JsonConverter.Abstractions;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using WireMock.Handlers;
|
||||
@@ -99,4 +100,12 @@ internal interface IWireMockMiddlewareOptions
|
||||
/// WebSocket settings.
|
||||
/// </summary>
|
||||
WebSocketSettings? WebSocketSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default JSON converter used for serialization.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Set this property to customize how objects are serialized to and deserialized from JSON during mapping.
|
||||
/// </remarks>
|
||||
IJsonConverter DefaultJsonSerializer { get; set; }
|
||||
}
|
||||
@@ -3,249 +3,242 @@
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using JsonConverter.Abstractions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Newtonsoft.Json;
|
||||
using RandomDataGenerator.FieldOptions;
|
||||
using RandomDataGenerator.Randomizers;
|
||||
using Stef.Validation;
|
||||
using WireMock.Http;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.ResponseProviders;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Owin.Mappers
|
||||
namespace WireMock.Owin.Mappers;
|
||||
|
||||
/// <summary>
|
||||
/// OwinResponseMapper
|
||||
/// </summary>
|
||||
internal class OwinResponseMapper(IWireMockMiddlewareOptions options) : IOwinResponseMapper
|
||||
{
|
||||
/// <summary>
|
||||
/// OwinResponseMapper
|
||||
/// </summary>
|
||||
internal class OwinResponseMapper : IOwinResponseMapper
|
||||
private readonly IRandomizerNumber<double> _randomizerDouble = RandomizerFactory.GetRandomizer(new FieldOptionsDouble { Min = 0, Max = 1 });
|
||||
private readonly IRandomizerBytes _randomizerBytes = RandomizerFactory.GetRandomizer(new FieldOptionsBytes { Min = 100, Max = 200 });
|
||||
private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/78h415ay(v=vs.110).aspx
|
||||
private static readonly IDictionary<string, Action<HttpResponse, bool, WireMockList<string>>> ResponseHeadersToFix =
|
||||
new Dictionary<string, Action<HttpResponse, bool, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ HttpKnownHeaderNames.ContentType, (r, _, v) => r.ContentType = v.FirstOrDefault() },
|
||||
{ HttpKnownHeaderNames.ContentLength, (r, hasBody, v) =>
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task MapAsync(IResponseMessage? responseMessage, HttpResponse response)
|
||||
{
|
||||
private readonly IRandomizerNumber<double> _randomizerDouble = RandomizerFactory.GetRandomizer(new FieldOptionsDouble { Min = 0, Max = 1 });
|
||||
private readonly IRandomizerBytes _randomizerBytes = RandomizerFactory.GetRandomizer(new FieldOptionsBytes { Min = 100, Max = 200 });
|
||||
private readonly IWireMockMiddlewareOptions _options;
|
||||
private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/78h415ay(v=vs.110).aspx
|
||||
private static readonly IDictionary<string, Action<HttpResponse, bool, WireMockList<string>>> ResponseHeadersToFix =
|
||||
new Dictionary<string, Action<HttpResponse, bool, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ HttpKnownHeaderNames.ContentType, (r, _, v) => r.ContentType = v.FirstOrDefault() },
|
||||
{ HttpKnownHeaderNames.ContentLength, (r, hasBody, v) =>
|
||||
{
|
||||
// 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>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="options">The IWireMockMiddlewareOptions.</param>
|
||||
public OwinResponseMapper(IWireMockMiddlewareOptions options)
|
||||
if (responseMessage == null || responseMessage is WebSocketHandledResponse)
|
||||
{
|
||||
_options = Guard.NotNull(options);
|
||||
return;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task MapAsync(IResponseMessage? responseMessage, HttpResponse response)
|
||||
var bodyData = responseMessage.BodyData;
|
||||
if (bodyData?.GetDetectedBodyType() == BodyType.SseString)
|
||||
{
|
||||
if (responseMessage == null || responseMessage is WebSocketHandledResponse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await HandleSseStringAsync(responseMessage, response, bodyData);
|
||||
return;
|
||||
}
|
||||
|
||||
var bodyData = responseMessage.BodyData;
|
||||
if (bodyData?.GetDetectedBodyType() == BodyType.SseString)
|
||||
{
|
||||
await HandleSseStringAsync(responseMessage, response, bodyData);
|
||||
return;
|
||||
}
|
||||
byte[]? bytes;
|
||||
switch (responseMessage.FaultType)
|
||||
{
|
||||
case FaultType.EMPTY_RESPONSE:
|
||||
bytes = IsFault(responseMessage) ? [] : await GetNormalBodyAsync(responseMessage).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
byte[]? bytes;
|
||||
switch (responseMessage.FaultType)
|
||||
{
|
||||
case FaultType.EMPTY_RESPONSE:
|
||||
bytes = IsFault(responseMessage) ? [] : await GetNormalBodyAsync(responseMessage).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
case FaultType.MALFORMED_RESPONSE_CHUNK:
|
||||
bytes = await GetNormalBodyAsync(responseMessage).ConfigureAwait(false) ?? [];
|
||||
if (IsFault(responseMessage))
|
||||
{
|
||||
bytes = bytes.Take(bytes.Length / 2).Union(_randomizerBytes.Generate()).ToArray();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
bytes = await GetNormalBodyAsync(responseMessage).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (responseMessage.StatusCode is HttpStatusCode or int)
|
||||
{
|
||||
response.StatusCode = MapStatusCode((int) responseMessage.StatusCode);
|
||||
}
|
||||
else if (responseMessage.StatusCode is string statusCodeAsString)
|
||||
{
|
||||
// Note: this case will also match on null
|
||||
_ = int.TryParse(statusCodeAsString, out var statusCodeTypeAsInt);
|
||||
response.StatusCode = MapStatusCode(statusCodeTypeAsInt);
|
||||
}
|
||||
|
||||
SetResponseHeaders(responseMessage, bytes != null, response);
|
||||
|
||||
if (bytes != null)
|
||||
{
|
||||
try
|
||||
case FaultType.MALFORMED_RESPONSE_CHUNK:
|
||||
bytes = await GetNormalBodyAsync(responseMessage).ConfigureAwait(false) ?? [];
|
||||
if (IsFault(responseMessage))
|
||||
{
|
||||
await response.Body.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
|
||||
bytes = bytes.Take(bytes.Length / 2).Union(_randomizerBytes.Generate()).ToArray();
|
||||
}
|
||||
catch (Exception ex)
|
||||
break;
|
||||
|
||||
default:
|
||||
bytes = await GetNormalBodyAsync(responseMessage).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (responseMessage.StatusCode is HttpStatusCode or int)
|
||||
{
|
||||
response.StatusCode = MapStatusCode((int)responseMessage.StatusCode);
|
||||
}
|
||||
else if (responseMessage.StatusCode is string statusCodeAsString)
|
||||
{
|
||||
// Note: this case will also match on null
|
||||
_ = int.TryParse(statusCodeAsString, out var statusCodeTypeAsInt);
|
||||
response.StatusCode = MapStatusCode(statusCodeTypeAsInt);
|
||||
}
|
||||
|
||||
SetResponseHeaders(responseMessage, bytes != null, response);
|
||||
|
||||
if (bytes != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await response.Body.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
options.Logger.Warn("Error writing response body. Exception : {0}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
SetResponseTrailingHeaders(responseMessage, response);
|
||||
}
|
||||
|
||||
private static async Task HandleSseStringAsync(IResponseMessage responseMessage, HttpResponse response, IBodyData bodyData)
|
||||
{
|
||||
if (bodyData.SseStringQueue == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetResponseHeaders(responseMessage, true, response);
|
||||
|
||||
string? text;
|
||||
do
|
||||
{
|
||||
if (bodyData.SseStringQueue.TryRead(out text))
|
||||
{
|
||||
await response.WriteAsync(text);
|
||||
await response.Body.FlushAsync();
|
||||
}
|
||||
} while (text != null);
|
||||
}
|
||||
|
||||
private int MapStatusCode(int code)
|
||||
{
|
||||
if (options.AllowOnlyDefinedHttpStatusCodeInResponse == true && !Enum.IsDefined(typeof(HttpStatusCode), code))
|
||||
{
|
||||
return (int)HttpStatusCode.OK;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
private bool IsFault(IResponseMessage responseMessage)
|
||||
{
|
||||
return responseMessage.FaultPercentage == null || _randomizerDouble.Generate() <= responseMessage.FaultPercentage;
|
||||
}
|
||||
|
||||
private async Task<byte[]?> GetNormalBodyAsync(IResponseMessage responseMessage)
|
||||
{
|
||||
var bodyData = responseMessage.BodyData;
|
||||
switch (bodyData?.GetDetectedBodyType())
|
||||
{
|
||||
case BodyType.String:
|
||||
case BodyType.FormUrlEncoded:
|
||||
return (bodyData.Encoding ?? _utf8NoBom).GetBytes(bodyData.BodyAsString!);
|
||||
|
||||
case BodyType.Json:
|
||||
var jsonConverterOptions = new JsonConverterOptions
|
||||
{
|
||||
_options.Logger.Warn("Error writing response body. Exception : {0}", ex);
|
||||
}
|
||||
}
|
||||
WriteIndented = bodyData.BodyAsJsonIndented == true,
|
||||
IgnoreNullValues = true
|
||||
};
|
||||
|
||||
SetResponseTrailingHeaders(responseMessage, response);
|
||||
}
|
||||
var jsonBody = options.DefaultJsonSerializer.Serialize(bodyData.BodyAsJson!, jsonConverterOptions);
|
||||
return (bodyData.Encoding ?? _utf8NoBom).GetBytes(jsonBody);
|
||||
|
||||
private static async Task HandleSseStringAsync(IResponseMessage responseMessage, HttpResponse response, IBodyData bodyData)
|
||||
{
|
||||
if (bodyData.SseStringQueue == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetResponseHeaders(responseMessage, true, response);
|
||||
|
||||
string? text;
|
||||
do
|
||||
{
|
||||
if (bodyData.SseStringQueue.TryRead(out text))
|
||||
case BodyType.ProtoBuf:
|
||||
if (TypeLoader.TryLoadStaticInstance<IProtoBufUtils>(out var protoBufUtils))
|
||||
{
|
||||
await response.WriteAsync(text);
|
||||
await response.Body.FlushAsync();
|
||||
var protoDefinitions = bodyData.ProtoDefinition?.Invoke().Texts;
|
||||
return await protoBufUtils.GetProtoBufMessageWithHeaderAsync(protoDefinitions, bodyData.ProtoBufMessageType, bodyData.BodyAsJson).ConfigureAwait(false);
|
||||
}
|
||||
} while (text != null);
|
||||
break;
|
||||
|
||||
case BodyType.Bytes:
|
||||
return bodyData.BodyAsBytes;
|
||||
|
||||
case BodyType.File:
|
||||
return options.FileSystemHandler?.ReadResponseBodyAsFile(bodyData.BodyAsFile!);
|
||||
|
||||
case BodyType.MultiPart:
|
||||
options.Logger.Warn("MultiPart body type is not handled!");
|
||||
break;
|
||||
|
||||
case BodyType.None:
|
||||
break;
|
||||
}
|
||||
|
||||
private int MapStatusCode(int code)
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void SetResponseHeaders(IResponseMessage responseMessage, bool hasBody, HttpResponse response)
|
||||
{
|
||||
// Force setting the Date header (#577)
|
||||
AppendResponseHeader(
|
||||
response,
|
||||
HttpKnownHeaderNames.Date,
|
||||
[DateTime.UtcNow.ToString(CultureInfo.InvariantCulture.DateTimeFormat.RFC1123Pattern, CultureInfo.InvariantCulture)]
|
||||
);
|
||||
|
||||
// Set other headers
|
||||
foreach (var item in responseMessage.Headers!)
|
||||
{
|
||||
if (_options.AllowOnlyDefinedHttpStatusCodeInResponse == true && !Enum.IsDefined(typeof(HttpStatusCode), code))
|
||||
var headerName = item.Key;
|
||||
var value = item.Value;
|
||||
if (ResponseHeadersToFix.TryGetValue(headerName, out var action))
|
||||
{
|
||||
return (int)HttpStatusCode.OK;
|
||||
action.Invoke(response, hasBody, value);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
private bool IsFault(IResponseMessage responseMessage)
|
||||
{
|
||||
return responseMessage.FaultPercentage == null || _randomizerDouble.Generate() <= responseMessage.FaultPercentage;
|
||||
}
|
||||
|
||||
private async Task<byte[]?> GetNormalBodyAsync(IResponseMessage responseMessage)
|
||||
{
|
||||
var bodyData = responseMessage.BodyData;
|
||||
switch (bodyData?.GetDetectedBodyType())
|
||||
else
|
||||
{
|
||||
case BodyType.String:
|
||||
case BodyType.FormUrlEncoded:
|
||||
return (bodyData.Encoding ?? _utf8NoBom).GetBytes(bodyData.BodyAsString!);
|
||||
|
||||
case BodyType.Json:
|
||||
var formatting = bodyData.BodyAsJsonIndented == true ? Formatting.Indented : Formatting.None;
|
||||
var jsonBody = JsonConvert.SerializeObject(bodyData.BodyAsJson, new JsonSerializerSettings { Formatting = formatting, NullValueHandling = NullValueHandling.Ignore });
|
||||
return (bodyData.Encoding ?? _utf8NoBom).GetBytes(jsonBody);
|
||||
|
||||
case BodyType.ProtoBuf:
|
||||
if (TypeLoader.TryLoadStaticInstance<IProtoBufUtils>(out var protoBufUtils))
|
||||
{
|
||||
var protoDefinitions = bodyData.ProtoDefinition?.Invoke().Texts;
|
||||
return await protoBufUtils.GetProtoBufMessageWithHeaderAsync(protoDefinitions, bodyData.ProtoBufMessageType, bodyData.BodyAsJson).ConfigureAwait(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case BodyType.Bytes:
|
||||
return bodyData.BodyAsBytes;
|
||||
|
||||
case BodyType.File:
|
||||
return _options.FileSystemHandler?.ReadResponseBodyAsFile(bodyData.BodyAsFile!);
|
||||
|
||||
case BodyType.MultiPart:
|
||||
_options.Logger.Warn("MultiPart body type is not handled!");
|
||||
break;
|
||||
|
||||
case BodyType.None:
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void SetResponseHeaders(IResponseMessage responseMessage, bool hasBody, HttpResponse response)
|
||||
{
|
||||
// Force setting the Date header (#577)
|
||||
AppendResponseHeader(
|
||||
response,
|
||||
HttpKnownHeaderNames.Date,
|
||||
[DateTime.UtcNow.ToString(CultureInfo.InvariantCulture.DateTimeFormat.RFC1123Pattern, CultureInfo.InvariantCulture)]
|
||||
);
|
||||
|
||||
// Set other headers
|
||||
foreach (var item in responseMessage.Headers!)
|
||||
{
|
||||
var headerName = item.Key;
|
||||
var value = item.Value;
|
||||
if (ResponseHeadersToFix.TryGetValue(headerName, out var action))
|
||||
// Check if this response header can be added (#148, #227 and #720)
|
||||
if (!HttpKnownHeaderNames.IsRestrictedResponseHeader(headerName))
|
||||
{
|
||||
action.Invoke(response, hasBody, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if this response header can be added (#148, #227 and #720)
|
||||
if (!HttpKnownHeaderNames.IsRestrictedResponseHeader(headerName))
|
||||
{
|
||||
AppendResponseHeader(response, headerName, value.ToArray());
|
||||
}
|
||||
AppendResponseHeader(response, headerName, value.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetResponseTrailingHeaders(IResponseMessage responseMessage, HttpResponse response)
|
||||
{
|
||||
if (responseMessage.TrailingHeaders == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if TRAILINGHEADERS
|
||||
foreach (var (headerName, value) in responseMessage.TrailingHeaders)
|
||||
{
|
||||
if (ResponseHeadersToFix.TryGetValue(headerName, out var action))
|
||||
{
|
||||
action.Invoke(response, false, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if this trailing header can be added to the response
|
||||
if (response.SupportsTrailers() && !HttpKnownHeaderNames.IsRestrictedResponseHeader(headerName))
|
||||
{
|
||||
response.AppendTrailer(headerName, new Microsoft.Extensions.Primitives.StringValues(value.ToArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void AppendResponseHeader(HttpResponse response, string headerName, string[] values)
|
||||
{
|
||||
response.Headers.Append(headerName, values);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetResponseTrailingHeaders(IResponseMessage responseMessage, HttpResponse response)
|
||||
{
|
||||
if (responseMessage.TrailingHeaders == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if TRAILINGHEADERS
|
||||
foreach (var (headerName, value) in responseMessage.TrailingHeaders)
|
||||
{
|
||||
if (ResponseHeadersToFix.TryGetValue(headerName, out var action))
|
||||
{
|
||||
action.Invoke(response, false, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if this trailing header can be added to the response
|
||||
if (response.SupportsTrailers() && !HttpKnownHeaderNames.IsRestrictedResponseHeader(headerName))
|
||||
{
|
||||
response.AppendTrailer(headerName, new Microsoft.Extensions.Primitives.StringValues(value.ToArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void AppendResponseHeader(HttpResponse response, string headerName, string[] values)
|
||||
{
|
||||
response.Headers.Append(headerName, values);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using JsonConverter.Abstractions;
|
||||
using JsonConverter.Newtonsoft.Json;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using WireMock.Handlers;
|
||||
@@ -108,5 +110,9 @@ internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions
|
||||
/// <inheritdoc />
|
||||
public ConcurrentDictionary<Guid, WebSocketConnectionRegistry> WebSocketRegistries { get; } = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public WebSocketSettings? WebSocketSettings { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IJsonConverter DefaultJsonSerializer { get; set; } = new NewtonsoftJsonConverter();
|
||||
}
|
||||
@@ -414,6 +414,7 @@ public partial class WireMockServer : IWireMockServer
|
||||
_options.CorsPolicyOptions = _settings.CorsPolicyOptions;
|
||||
_options.ClientCertificateMode = (Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode)_settings.ClientCertificateMode;
|
||||
_options.AcceptAnyClientCertificate = _settings.AcceptAnyClientCertificate;
|
||||
_options.DefaultJsonSerializer = _settings.DefaultJsonSerializer;
|
||||
|
||||
_httpServer = new AspNetCoreSelfHost(_options, urlOptions);
|
||||
var startTask = _httpServer.StartAsync();
|
||||
|
||||
@@ -9,6 +9,8 @@ using WireMock.Util;
|
||||
using WireMock.Owin;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using JsonConverter.Newtonsoft.Json;
|
||||
using JsonConverter.System.Text.Json;
|
||||
|
||||
namespace WireMock.Net.Tests.Owin.Mappers;
|
||||
|
||||
@@ -34,6 +36,7 @@ public class OwinResponseMapperTests
|
||||
_optionsMock = new Mock<IWireMockMiddlewareOptions>();
|
||||
_optionsMock.SetupAllProperties();
|
||||
_optionsMock.SetupGet(o => o.FileSystemHandler).Returns(_fileSystemHandlerMock.Object);
|
||||
_optionsMock.SetupGet(o => o.DefaultJsonSerializer).Returns(new NewtonsoftJsonConverter());
|
||||
|
||||
_headers = new Mock<IHeaderDictionary>();
|
||||
_headers.SetupAllProperties();
|
||||
@@ -186,7 +189,7 @@ public class OwinResponseMapperTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OwinResponseMapper_MapAsync_BodyAsJson()
|
||||
public async Task OwinResponseMapper_MapAsync_BodyAsJson_UsingNewtonsoftJson()
|
||||
{
|
||||
// Arrange
|
||||
var json = new { t = "x", i = (string?)null };
|
||||
@@ -203,6 +206,25 @@ public class OwinResponseMapperTests
|
||||
_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_BodyAsJson_UsingSystemTextJson()
|
||||
{
|
||||
// Arrange
|
||||
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 }
|
||||
};
|
||||
_optionsMock.SetupGet(o => o.DefaultJsonSerializer).Returns(new SystemTextJsonConverter());
|
||||
|
||||
// Act
|
||||
await _sut.MapAsync(responseMessage, _responseMock.Object);
|
||||
|
||||
// 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()
|
||||
{
|
||||
|
||||
@@ -4,10 +4,13 @@ using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using JsonConverter.System.Text.Json;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.RequestBuilders;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.Server;
|
||||
using WireMock.Settings;
|
||||
|
||||
namespace WireMock.Net.Tests;
|
||||
|
||||
@@ -18,11 +21,41 @@ public partial class WireMockServerTests
|
||||
public string? Hi { get; set; }
|
||||
}
|
||||
|
||||
public class Person
|
||||
{
|
||||
[JsonPropertyName("first_name")]
|
||||
public string FirstName { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("last_name")]
|
||||
public string LastName { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WireMockServer_WithBodyAsJson_UsingWireMockServerSettings_SystemTextJsonConverter_ShouldReturnCorrectResponse()
|
||||
{
|
||||
// Arange
|
||||
var person = new Person { FirstName = "John", LastName = "Smith" };
|
||||
|
||||
using var server = WireMockServer.Start(new WireMockServerSettings
|
||||
{
|
||||
DefaultJsonSerializer = new SystemTextJsonConverter()
|
||||
});
|
||||
|
||||
// Act
|
||||
server
|
||||
.Given(Request.Create().UsingAnyMethod())
|
||||
.RespondWith(Response.Create().WithBodyAsJson(person));
|
||||
|
||||
var response = await server.CreateClient().GetStringAsync("/", _ct);
|
||||
|
||||
// Assert
|
||||
response.Should().BeEquivalentTo("{\"first_name\":\"John\",\"last_name\":\"Smith\"}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WireMockServer_WithBodyAsJson_Using_PostAsJsonAsync_And_MultipleJmesPathMatchers_ShouldMatch()
|
||||
{
|
||||
// Arrange
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
using var server = WireMockServer.Start();
|
||||
server.Given(
|
||||
Request.Create()
|
||||
@@ -56,7 +89,7 @@ public partial class WireMockServerTests
|
||||
var requestUri = new Uri($"http://localhost:{server.Port}/a");
|
||||
|
||||
var json = new { requestId = "1", value = "A" };
|
||||
var response = await server.CreateClient().PostAsJsonAsync(requestUri, json, cancellationToken);
|
||||
var response = await server.CreateClient().PostAsJsonAsync(requestUri, json, _ct);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
@@ -68,7 +101,6 @@ public partial class WireMockServerTests
|
||||
public async Task WireMockServer_WithBodyAsJson_Using_PostAsJsonAsync_And_MultipleJmesPathMatchers_ShouldMatch_BestMatching()
|
||||
{
|
||||
// Arrange
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
using var server = WireMockServer.Start();
|
||||
server.Given(
|
||||
Request.Create()
|
||||
@@ -105,7 +137,7 @@ public partial class WireMockServerTests
|
||||
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, cancellationToken);
|
||||
var response = await server.CreateClient().PostAsJsonAsync(requestUri, json, _ct);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
@@ -117,7 +149,6 @@ public partial class WireMockServerTests
|
||||
public async Task WireMockServer_WithBodyAsJson_Using_PostAsJsonAsync_And_WildcardMatcher_ShouldMatch()
|
||||
{
|
||||
// Arrange
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
using var server = WireMockServer.Start();
|
||||
server.Given(
|
||||
Request.Create().UsingPost().WithPath("/foo").WithBody(new WildcardMatcher("*Hello*"))
|
||||
@@ -132,7 +163,7 @@ public partial class WireMockServerTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var response = await new HttpClient().PostAsJsonAsync("http://localhost:" + server.Ports[0] + "/foo", jsonObject, cancellationToken);
|
||||
var response = await new HttpClient().PostAsJsonAsync("http://localhost:" + server.Ports[0] + "/foo", jsonObject, _ct);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
@@ -144,7 +175,6 @@ public partial class WireMockServerTests
|
||||
public async Task WireMockServer_WithBodyAsJson_Using_PostAsync_And_WildcardMatcher_ShouldMatch()
|
||||
{
|
||||
// Arrange
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
using var server = WireMockServer.Start();
|
||||
server.Given(
|
||||
Request.Create().UsingPost().WithPath("/foo").WithBody(new WildcardMatcher("*Hello*"))
|
||||
@@ -154,7 +184,7 @@ public partial class WireMockServerTests
|
||||
);
|
||||
|
||||
// Act
|
||||
var response = await new HttpClient().PostAsync("http://localhost:" + server.Ports[0] + "/foo", new StringContent("{ Hi = \"Hello World\" }"), cancellationToken);
|
||||
var response = await new HttpClient().PostAsync("http://localhost:" + server.Ports[0] + "/foo", new StringContent("{ Hi = \"Hello World\" }"), _ct);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
@@ -166,7 +196,6 @@ public partial class WireMockServerTests
|
||||
public async Task WireMockServer_WithBodyAsJson_Using_PostAsync_And_JsonPartialWildcardMatcher_ShouldMatch()
|
||||
{
|
||||
// Arrange
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
using var server = WireMockServer.Start();
|
||||
|
||||
var matcher = new JsonPartialWildcardMatcher(new { method = "initialize", id = "^[a-f0-9]{32}-[0-9]$" }, ignoreCase: true, regex: true);
|
||||
@@ -188,13 +217,13 @@ public partial class WireMockServerTests
|
||||
// Act
|
||||
var content = "{\"jsonrpc\":\"2.0\",\"id\":\"ec475f56d4694b48bc737500ba575b35-1\",\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"GitHub Test\",\"version\":\"1.0.0\"}}}";
|
||||
var response = await new HttpClient()
|
||||
.PostAsync($"{server.Url}/foo", new StringContent(content, Encoding.UTF8, "application/json"), cancellationToken)
|
||||
.PostAsync($"{server.Url}/foo", new StringContent(content, Encoding.UTF8, "application/json"), _ct)
|
||||
;
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var responseText = await response.Content.ReadAsStringAsync(cancellationToken);
|
||||
var responseText = await response.Content.ReadAsStringAsync(_ct);
|
||||
responseText.Should().Contain("ec475f56d4694b48bc737500ba575b35-1");
|
||||
}
|
||||
|
||||
@@ -203,8 +232,7 @@ public partial class WireMockServerTests
|
||||
public async Task WireMockServer_WithBodyAsJson_Using_PostAsync_And_JsonPartialWildcardMatcher_And_SystemTextJson_ShouldMatch()
|
||||
{
|
||||
// Arrange
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
using var server = WireMockServer.Start(x => x.DefaultJsonSerializer = new JsonConverter.System.Text.Json.SystemTextJsonConverter() );
|
||||
using var server = WireMockServer.Start(x => x.DefaultJsonSerializer = new SystemTextJsonConverter());
|
||||
|
||||
var matcher = new JsonPartialWildcardMatcher(new { id = "^[a-f0-9]{32}-[0-9]$" }, ignoreCase: true, regex: true);
|
||||
server.Given(Request.Create()
|
||||
@@ -220,12 +248,12 @@ public partial class WireMockServerTests
|
||||
// Act
|
||||
var content = """{"id":"ec475f56d4694b48bc737500ba575b35-1"}""";
|
||||
using var httpClient = new HttpClient();
|
||||
var response = await httpClient.PostAsync($"{server.Url}/system-text-json", new StringContent(content, Encoding.UTF8, "application/json"), cancellationToken);
|
||||
var response = await httpClient.PostAsync($"{server.Url}/system-text-json", new StringContent(content, Encoding.UTF8, "application/json"), _ct);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var responseText = await response.Content.ReadAsStringAsync(cancellationToken);
|
||||
var responseText = await response.Content.ReadAsStringAsync(_ct);
|
||||
responseText.Should().Contain("OK");
|
||||
}
|
||||
#endif
|
||||
@@ -234,7 +262,6 @@ public partial class WireMockServerTests
|
||||
public async Task WireMockServer_WithBodyAsFormUrlEncoded_Using_PostAsync_And_WithFunc()
|
||||
{
|
||||
// Arrange
|
||||
var cancelationToken = TestContext.Current.CancellationToken;
|
||||
using var server = WireMockServer.Start();
|
||||
server.Given(
|
||||
Request.Create()
|
||||
@@ -249,7 +276,7 @@ public partial class WireMockServerTests
|
||||
// Act
|
||||
var content = new FormUrlEncodedContent([new KeyValuePair<string, string>("key1", "value1")]);
|
||||
var response = await new HttpClient()
|
||||
.PostAsync($"{server.Url}/foo", content, cancelationToken);
|
||||
.PostAsync($"{server.Url}/foo", content, _ct);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
@@ -261,7 +288,6 @@ public partial class WireMockServerTests
|
||||
public async Task WireMockServer_WithBodyAsFormUrlEncoded_Using_PostAsync_And_WithExactMatcher()
|
||||
{
|
||||
// Arrange
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
using var server = WireMockServer.Start();
|
||||
server.Given(
|
||||
Request.Create()
|
||||
@@ -282,7 +308,7 @@ public partial class WireMockServerTests
|
||||
new KeyValuePair<string, string>("email", "johndoe@example.com")
|
||||
]);
|
||||
using var httpClient = new HttpClient();
|
||||
var response = await httpClient.PostAsync($"{server.Url}/foo", content, cancellationToken)
|
||||
var response = await httpClient.PostAsync($"{server.Url}/foo", content, _ct)
|
||||
;
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
@@ -294,7 +320,6 @@ public partial class WireMockServerTests
|
||||
public async Task WireMockServer_WithBodyAsFormUrlEncoded_Using_PostAsync_And_WithFormUrlEncodedMatcher()
|
||||
{
|
||||
// Arrange
|
||||
var cancelationToken = TestContext.Current.CancellationToken;
|
||||
var matcher = new FormUrlEncodedMatcher(["email=johndoe@example.com", "name=John Doe"]);
|
||||
using var server = WireMockServer.Start();
|
||||
server.Given(
|
||||
@@ -326,7 +351,7 @@ public partial class WireMockServerTests
|
||||
new KeyValuePair<string, string>("email", "johndoe@example.com")
|
||||
]);
|
||||
var responseOrdered = await new HttpClient()
|
||||
.PostAsync($"{server.Url}/foo", contentOrdered, cancelationToken)
|
||||
.PostAsync($"{server.Url}/foo", contentOrdered, _ct)
|
||||
;
|
||||
|
||||
// Assert 1
|
||||
@@ -340,7 +365,7 @@ public partial class WireMockServerTests
|
||||
new KeyValuePair<string, string>("name", "John Doe"),
|
||||
]);
|
||||
var responseUnordered = await new HttpClient()
|
||||
.PostAsync($"{server.Url}/bar", contentUnordered, cancelationToken)
|
||||
.PostAsync($"{server.Url}/bar", contentUnordered, _ct)
|
||||
;
|
||||
|
||||
// Assert 2
|
||||
@@ -353,7 +378,6 @@ public partial class WireMockServerTests
|
||||
public async Task WireMockServer_WithSseBody()
|
||||
{
|
||||
// Arrange
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
using var server = WireMockServer.Start();
|
||||
server
|
||||
.WhenRequest(r => r
|
||||
@@ -387,9 +411,8 @@ public partial class WireMockServerTests
|
||||
using var client = new HttpClient();
|
||||
|
||||
// Act 1
|
||||
var normal = await client.GetAsync(server.Url, cancellationToken)
|
||||
;
|
||||
(await normal.Content.ReadAsStringAsync(cancellationToken)).Should().Be("normal");
|
||||
var normal = await client.GetAsync(server.Url, _ct);
|
||||
(await normal.Content.ReadAsStringAsync(_ct)).Should().Be("normal");
|
||||
|
||||
// Act 2
|
||||
using var response = await client.GetStreamAsync($"{server.Url}/sse", _ct);
|
||||
|
||||
Reference in New Issue
Block a user