mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-24 01:51:02 +01:00
Rewrite some unit-integration-tests to unit-tests (#206)
This commit is contained in:
91
src/WireMock.Net/IMapping.cs
Normal file
91
src/WireMock.Net/IMapping.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.ResponseProviders;
|
||||
|
||||
namespace WireMock
|
||||
{
|
||||
/// <summary>
|
||||
/// The IMapping interface.
|
||||
/// </summary>
|
||||
public interface IMapping
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the unique identifier.
|
||||
/// </summary>
|
||||
Guid Guid { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique title.
|
||||
/// </summary>
|
||||
string Title { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The full filename path for this mapping (only defined for static mappings).
|
||||
/// </summary>
|
||||
string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the priority.
|
||||
/// </summary>
|
||||
int Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Scenario.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
string Scenario { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Execution state condition for the current mapping.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
string ExecutionConditionState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The next state which will be signaled after the current mapping execution.
|
||||
/// In case the value is null, state will not be changed.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
string NextState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The Request matcher.
|
||||
/// </summary>
|
||||
IRequestMatcher RequestMatcher { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The Provider.
|
||||
/// </summary>
|
||||
IResponseProvider Provider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Is State started ?
|
||||
/// </summary>
|
||||
bool IsStartState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ResponseToAsync
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">The request message.</param>
|
||||
/// <returns>The <see cref="ResponseMessage"/>.</returns>
|
||||
Task<ResponseMessage> ResponseToAsync(RequestMessage requestMessage);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the RequestMatchResult based on the RequestMessage.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">The request message.</param>
|
||||
/// <param name="nextState">The Next State.</param>
|
||||
/// <returns>The <see cref="RequestMatchResult"/>.</returns>
|
||||
RequestMatchResult GetRequestMatchResult(RequestMessage requestMessage, [CanBeNull] string nextState);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this mapping is an Admin Interface.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this mapping is an Admin Interface; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
bool IsAdminInterface { get; }
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,9 @@ namespace WireMock
|
||||
/// <summary>
|
||||
/// The Mapping.
|
||||
/// </summary>
|
||||
public class Mapping
|
||||
public class Mapping : IMapping
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the unique identifier.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="IMapping.Guid" />
|
||||
public Guid Guid { get; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
/// The registration callback.
|
||||
/// </summary>
|
||||
/// <param name="mapping">The mapping.</param>
|
||||
public delegate void RegistrationCallback(Mapping mapping);
|
||||
public delegate void RegistrationCallback(IMapping mapping);
|
||||
}
|
||||
@@ -7,8 +7,10 @@ using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using WireMock.HttpsCertificate;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Owin.Mappers;
|
||||
using WireMock.Util;
|
||||
using WireMock.Validation;
|
||||
|
||||
@@ -17,7 +19,7 @@ namespace WireMock.Owin
|
||||
internal class AspNetCoreSelfHost : IOwinSelfHost
|
||||
{
|
||||
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
|
||||
private readonly WireMockMiddlewareOptions _options;
|
||||
private readonly IWireMockMiddlewareOptions _options;
|
||||
private readonly string[] _urls;
|
||||
private readonly IWireMockLogger _logger;
|
||||
private Exception _runningException;
|
||||
@@ -32,7 +34,7 @@ namespace WireMock.Owin
|
||||
|
||||
public Exception RunningException => _runningException;
|
||||
|
||||
public AspNetCoreSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
|
||||
public AspNetCoreSelfHost([NotNull] IWireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
|
||||
{
|
||||
Check.NotNull(options, nameof(options));
|
||||
Check.NotNullOrEmpty(uriPrefixes, nameof(uriPrefixes));
|
||||
@@ -54,13 +56,20 @@ namespace WireMock.Owin
|
||||
public Task StartAsync()
|
||||
{
|
||||
_host = new WebHostBuilder()
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddSingleton<IWireMockMiddlewareOptions>(_options);
|
||||
services.AddSingleton<IMappingMatcher, MappingMatcher>();
|
||||
services.AddSingleton<IOwinRequestMapper, OwinRequestMapper>();
|
||||
services.AddSingleton<IOwinResponseMapper, OwinResponseMapper>();
|
||||
})
|
||||
.Configure(appBuilder =>
|
||||
{
|
||||
appBuilder.UseMiddleware<GlobalExceptionMiddleware>(_options);
|
||||
appBuilder.UseMiddleware<GlobalExceptionMiddleware>();
|
||||
|
||||
_options.PreWireMockMiddlewareInit?.Invoke(appBuilder);
|
||||
|
||||
appBuilder.UseMiddleware<WireMockMiddleware>(_options);
|
||||
appBuilder.UseMiddleware<WireMockMiddleware>();
|
||||
|
||||
_options.PostWireMockMiddlewareInit?.Invoke(appBuilder);
|
||||
})
|
||||
@@ -104,7 +113,7 @@ namespace WireMock.Owin
|
||||
{
|
||||
try
|
||||
{
|
||||
var appLifetime = (IApplicationLifetime) _host.Services.GetService(typeof(IApplicationLifetime));
|
||||
var appLifetime = (IApplicationLifetime)_host.Services.GetService(typeof(IApplicationLifetime));
|
||||
appLifetime.ApplicationStarted.Register(() => IsStarted = true);
|
||||
|
||||
#if NETSTANDARD1_3
|
||||
|
||||
@@ -3,44 +3,59 @@ using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
#if !USE_ASPNETCORE
|
||||
using Microsoft.Owin;
|
||||
using IContext = Microsoft.Owin.IOwinContext;
|
||||
using OwinMiddleware = Microsoft.Owin.OwinMiddleware;
|
||||
using Next = Microsoft.Owin.OwinMiddleware;
|
||||
#else
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using OwinMiddleware = System.Object;
|
||||
using IContext = Microsoft.AspNetCore.Http.HttpContext;
|
||||
using Next = Microsoft.AspNetCore.Http.RequestDelegate;
|
||||
#endif
|
||||
using WireMock.Owin.Mappers;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Owin
|
||||
{
|
||||
#if !USE_ASPNETCORE
|
||||
internal class GlobalExceptionMiddleware : OwinMiddleware
|
||||
#else
|
||||
internal class GlobalExceptionMiddleware
|
||||
#endif
|
||||
{
|
||||
private readonly WireMockMiddlewareOptions _options;
|
||||
private readonly IWireMockMiddlewareOptions _options;
|
||||
private readonly IOwinResponseMapper _responseMapper;
|
||||
|
||||
#if !USE_ASPNETCORE
|
||||
public GlobalExceptionMiddleware(OwinMiddleware next, WireMockMiddlewareOptions options) : base(next)
|
||||
public GlobalExceptionMiddleware(Next next, IWireMockMiddlewareOptions options, IOwinResponseMapper responseMapper) : base(next)
|
||||
{
|
||||
Check.NotNull(options, nameof(options));
|
||||
Check.NotNull(responseMapper, nameof(responseMapper));
|
||||
|
||||
_options = options;
|
||||
_responseMapper = responseMapper;
|
||||
}
|
||||
#else
|
||||
public GlobalExceptionMiddleware(RequestDelegate next, WireMockMiddlewareOptions options)
|
||||
public GlobalExceptionMiddleware(Next next, IWireMockMiddlewareOptions options, IOwinResponseMapper responseMapper)
|
||||
{
|
||||
Check.NotNull(options, nameof(options));
|
||||
Check.NotNull(responseMapper, nameof(responseMapper));
|
||||
|
||||
Next = next;
|
||||
_options = options;
|
||||
_responseMapper = responseMapper;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
public RequestDelegate Next { get; }
|
||||
public Next Next { get; }
|
||||
#endif
|
||||
|
||||
private readonly OwinResponseMapper _responseMapper = new OwinResponseMapper();
|
||||
|
||||
#if !USE_ASPNETCORE
|
||||
public override async Task Invoke(IOwinContext ctx)
|
||||
public override Task Invoke(IContext ctx)
|
||||
#else
|
||||
public async Task Invoke(HttpContext ctx)
|
||||
public Task Invoke(IContext ctx)
|
||||
#endif
|
||||
{
|
||||
return InvokeInternal(ctx);
|
||||
}
|
||||
|
||||
private async Task InvokeInternal(IContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
9
src/WireMock.Net/Owin/IMappingMatcher.cs
Normal file
9
src/WireMock.Net/Owin/IMappingMatcher.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.Owin
|
||||
{
|
||||
internal interface IMappingMatcher
|
||||
{
|
||||
(IMapping Mapping, RequestMatchResult RequestMatchResult) Match(RequestMessage request);
|
||||
}
|
||||
}
|
||||
38
src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs
Normal file
38
src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.ObjectModel;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Matchers;
|
||||
#if !USE_ASPNETCORE
|
||||
using Owin;
|
||||
#else
|
||||
using IAppBuilder = Microsoft.AspNetCore.Builder.IApplicationBuilder;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Owin
|
||||
{
|
||||
internal interface IWireMockMiddlewareOptions
|
||||
{
|
||||
IWireMockLogger Logger { get; set; }
|
||||
|
||||
TimeSpan? RequestProcessingDelay { get; set; }
|
||||
|
||||
IStringMatcher AuthorizationMatcher { get; set; }
|
||||
|
||||
bool AllowPartialMapping { get; set; }
|
||||
|
||||
ConcurrentDictionary<Guid, IMapping> Mappings { get; }
|
||||
|
||||
ConcurrentDictionary<string, ScenarioState> Scenarios { get; }
|
||||
|
||||
ObservableCollection<LogEntry> LogEntries { get; }
|
||||
|
||||
int? RequestLogExpirationDuration { get; set; }
|
||||
|
||||
int? MaxRequestLogCount { get; set; }
|
||||
|
||||
Action<IAppBuilder> PreWireMockMiddlewareInit { get; set; }
|
||||
|
||||
Action<IAppBuilder> PostWireMockMiddlewareInit { get; set; }
|
||||
}
|
||||
}
|
||||
22
src/WireMock.Net/Owin/Mappers/IOwinRequestMapper.cs
Normal file
22
src/WireMock.Net/Owin/Mappers/IOwinRequestMapper.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System.Threading.Tasks;
|
||||
#if !USE_ASPNETCORE
|
||||
using IRequest = Microsoft.Owin.IOwinRequest;
|
||||
#else
|
||||
using IRequest = Microsoft.AspNetCore.Http.HttpRequest;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Owin.Mappers
|
||||
{
|
||||
/// <summary>
|
||||
/// IOwinRequestMapper
|
||||
/// </summary>
|
||||
internal interface IOwinRequestMapper
|
||||
{
|
||||
/// <summary>
|
||||
/// MapAsync IRequest to RequestMessage
|
||||
/// </summary>
|
||||
/// <param name="request">The OwinRequest/HttpRequest</param>
|
||||
/// <returns>RequestMessage</returns>
|
||||
Task<RequestMessage> MapAsync(IRequest request);
|
||||
}
|
||||
}
|
||||
22
src/WireMock.Net/Owin/Mappers/IOwinResponseMapper.cs
Normal file
22
src/WireMock.Net/Owin/Mappers/IOwinResponseMapper.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System.Threading.Tasks;
|
||||
#if !USE_ASPNETCORE
|
||||
using IResponse = Microsoft.Owin.IOwinResponse;
|
||||
#else
|
||||
using IResponse = Microsoft.AspNetCore.Http.HttpResponse;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Owin.Mappers
|
||||
{
|
||||
/// <summary>
|
||||
/// IOwinResponseMapper
|
||||
/// </summary>
|
||||
internal interface IOwinResponseMapper
|
||||
{
|
||||
/// <summary>
|
||||
/// Map ResponseMessage to IResponse.
|
||||
/// </summary>
|
||||
/// <param name="responseMessage">The ResponseMessage</param>
|
||||
/// <param name="response">The OwinResponse/HttpResponse</param>
|
||||
Task MapAsync(ResponseMessage responseMessage, IResponse response);
|
||||
}
|
||||
}
|
||||
@@ -1,90 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using WireMock.Util;
|
||||
#if !USE_ASPNETCORE
|
||||
using Microsoft.Owin;
|
||||
#else
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Owin
|
||||
{
|
||||
/// <summary>
|
||||
/// OwinRequestMapper
|
||||
/// </summary>
|
||||
internal class OwinRequestMapper
|
||||
{
|
||||
/// <summary>
|
||||
/// MapAsync IOwinRequest to RequestMessage
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<RequestMessage> MapAsync(
|
||||
#if !USE_ASPNETCORE
|
||||
IOwinRequest request
|
||||
#else
|
||||
HttpRequest request
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if !USE_ASPNETCORE
|
||||
var urldetails = UrlUtils.Parse(request.Uri, request.PathBase);
|
||||
string clientIP = request.RemoteIpAddress;
|
||||
#else
|
||||
var urldetails = UrlUtils.Parse(new Uri(request.GetEncodedUrl()), request.PathBase);
|
||||
var connection = request.HttpContext.Connection;
|
||||
string clientIP = connection.RemoteIpAddress.IsIPv4MappedToIPv6
|
||||
? connection.RemoteIpAddress.MapToIPv4().ToString()
|
||||
: connection.RemoteIpAddress.ToString();
|
||||
#endif
|
||||
string method = request.Method;
|
||||
|
||||
Dictionary<string, string[]> headers = null;
|
||||
if (request.Headers.Any())
|
||||
{
|
||||
headers = new Dictionary<string, string[]>();
|
||||
foreach (var header in request.Headers)
|
||||
{
|
||||
headers.Add(header.Key, header.Value);
|
||||
}
|
||||
}
|
||||
|
||||
IDictionary<string, string> cookies = null;
|
||||
if (request.Cookies.Any())
|
||||
{
|
||||
cookies = new Dictionary<string, string>();
|
||||
foreach (var cookie in request.Cookies)
|
||||
{
|
||||
cookies.Add(cookie.Key, cookie.Value);
|
||||
}
|
||||
}
|
||||
|
||||
BodyData body = null;
|
||||
if (request.Body != null && ShouldParseBody(method))
|
||||
{
|
||||
body = await BodyParser.Parse(request.Body, request.ContentType);
|
||||
}
|
||||
|
||||
return new RequestMessage(urldetails, method, clientIP, body, headers, cookies) { DateTime = DateTime.Now };
|
||||
}
|
||||
|
||||
private bool ShouldParseBody(string method)
|
||||
{
|
||||
/*
|
||||
HEAD - No defined body semantics.
|
||||
GET - No defined body semantics.
|
||||
PUT - Body supported.
|
||||
POST - Body supported.
|
||||
DELETE - No defined body semantics.
|
||||
TRACE - Body not supported.
|
||||
OPTIONS - Body supported but no semantics on usage (maybe in the future).
|
||||
CONNECT - No defined body semantics
|
||||
PATCH - Body supported.
|
||||
*/
|
||||
return new[] { "PUT", "POST", "OPTIONS", "PATCH" }.Contains(method.ToUpper());
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using WireMock.Models;
|
||||
using WireMock.Util;
|
||||
#if !USE_ASPNETCORE
|
||||
using IRequest = Microsoft.Owin.IOwinRequest;
|
||||
#else
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using IRequest = Microsoft.AspNetCore.Http.HttpRequest;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Owin.Mappers
|
||||
{
|
||||
/// <summary>
|
||||
/// OwinRequestMapper
|
||||
/// </summary>
|
||||
internal class OwinRequestMapper : IOwinRequestMapper
|
||||
{
|
||||
/// <inheritdoc cref="IOwinRequestMapper.MapAsync"/>
|
||||
public async Task<RequestMessage> MapAsync(IRequest request)
|
||||
{
|
||||
(UrlDetails urldetails, string clientIP) = ParseRequest(request);
|
||||
|
||||
string method = request.Method;
|
||||
|
||||
Dictionary<string, string[]> headers = null;
|
||||
if (request.Headers.Any())
|
||||
{
|
||||
headers = new Dictionary<string, string[]>();
|
||||
foreach (var header in request.Headers)
|
||||
{
|
||||
headers.Add(header.Key, header.Value);
|
||||
}
|
||||
}
|
||||
|
||||
IDictionary<string, string> cookies = null;
|
||||
if (request.Cookies.Any())
|
||||
{
|
||||
cookies = new Dictionary<string, string>();
|
||||
foreach (var cookie in request.Cookies)
|
||||
{
|
||||
cookies.Add(cookie.Key, cookie.Value);
|
||||
}
|
||||
}
|
||||
|
||||
BodyData body = null;
|
||||
if (request.Body != null && ShouldParseBody(method))
|
||||
{
|
||||
body = await BodyParser.Parse(request.Body, request.ContentType);
|
||||
}
|
||||
|
||||
return new RequestMessage(urldetails, method, clientIP, body, headers, cookies) { DateTime = DateTime.UtcNow };
|
||||
}
|
||||
|
||||
private (UrlDetails UrlDetails, string ClientIP) ParseRequest(IRequest request)
|
||||
{
|
||||
#if !USE_ASPNETCORE
|
||||
var urldetails = UrlUtils.Parse(request.Uri, request.PathBase);
|
||||
string clientIP = request.RemoteIpAddress;
|
||||
#else
|
||||
var urldetails = UrlUtils.Parse(new Uri(request.GetEncodedUrl()), request.PathBase);
|
||||
var connection = request.HttpContext.Connection;
|
||||
string clientIP = connection.RemoteIpAddress.IsIPv4MappedToIPv6
|
||||
? connection.RemoteIpAddress.MapToIPv4().ToString()
|
||||
: connection.RemoteIpAddress.ToString();
|
||||
#endif
|
||||
return (urldetails, clientIP);
|
||||
}
|
||||
|
||||
private bool ShouldParseBody(string method)
|
||||
{
|
||||
/*
|
||||
HEAD - No defined body semantics.
|
||||
GET - No defined body semantics.
|
||||
PUT - Body supported.
|
||||
POST - Body supported.
|
||||
DELETE - No defined body semantics.
|
||||
TRACE - Body not supported.
|
||||
OPTIONS - Body supported but no semantics on usage (maybe in the future).
|
||||
CONNECT - No defined body semantics
|
||||
PATCH - Body supported.
|
||||
*/
|
||||
return new[] { "PUT", "POST", "OPTIONS", "PATCH" }.Contains(method.ToUpper());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,79 +2,40 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using WireMock.Http;
|
||||
using WireMock.Util;
|
||||
#if !USE_ASPNETCORE
|
||||
using System.Net;
|
||||
using Microsoft.Owin;
|
||||
using IResponse = Microsoft.Owin.IOwinResponse;
|
||||
#else
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using IResponse = Microsoft.AspNetCore.Http.HttpResponse;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Owin
|
||||
namespace WireMock.Owin.Mappers
|
||||
{
|
||||
/// <summary>
|
||||
/// OwinResponseMapper
|
||||
/// </summary>
|
||||
public class OwinResponseMapper
|
||||
public class OwinResponseMapper : IOwinResponseMapper
|
||||
{
|
||||
private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/78h415ay(v=vs.110).aspx
|
||||
#if !USE_ASPNETCORE
|
||||
private static readonly IDictionary<string, Action<IOwinResponse, WireMockList<string>>> ResponseHeadersToFix = new Dictionary<string, Action<IOwinResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
|
||||
private static readonly IDictionary<string, Action<IResponse, WireMockList<string>>> ResponseHeadersToFix = new Dictionary<string, Action<IResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
|
||||
#else
|
||||
private static readonly IDictionary<string, Action<HttpResponse, WireMockList<string>>> ResponseHeadersToFix = new Dictionary<string, Action<HttpResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
|
||||
private static readonly IDictionary<string, Action<IResponse, WireMockList<string>>> ResponseHeadersToFix = new Dictionary<string, Action<IResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
|
||||
#endif
|
||||
{ HttpKnownHeaderNames.ContentType, (r, v) => r.ContentType = v.FirstOrDefault() }
|
||||
};
|
||||
|
||||
private void SetResponseHeaders(ResponseMessage responseMessage
|
||||
#if !USE_ASPNETCORE
|
||||
, IOwinResponse response
|
||||
#else
|
||||
, HttpResponse response
|
||||
#endif
|
||||
)
|
||||
{
|
||||
// Set headers
|
||||
foreach (var pair in responseMessage.Headers)
|
||||
{
|
||||
if (ResponseHeadersToFix.ContainsKey(pair.Key))
|
||||
{
|
||||
ResponseHeadersToFix[pair.Key]?.Invoke(response, pair.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if !USE_ASPNETCORE
|
||||
// For non-NETSTANDARD, check if this response header can be added (#148)
|
||||
if (!WebHeaderCollection.IsRestricted(pair.Key, true))
|
||||
{
|
||||
response.Headers.AppendValues(pair.Key, pair.Value.ToArray());
|
||||
}
|
||||
#else
|
||||
// NETSTANDARD can add any header (or so it seems)
|
||||
response.Headers.Append(pair.Key, pair.Value.ToArray());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Map ResponseMessage to OwinResponse/HttpResponse
|
||||
/// </summary>
|
||||
/// <param name="responseMessage"></param>
|
||||
/// <param name="response"></param>
|
||||
public async Task MapAsync(ResponseMessage responseMessage
|
||||
#if !USE_ASPNETCORE
|
||||
, IOwinResponse response
|
||||
#else
|
||||
, HttpResponse response
|
||||
#endif
|
||||
)
|
||||
/// <inheritdoc cref="IOwinResponseMapper.MapAsync"/>
|
||||
public async Task MapAsync(ResponseMessage responseMessage, IResponse response)
|
||||
{
|
||||
if (responseMessage == null)
|
||||
{
|
||||
@@ -110,5 +71,30 @@ namespace WireMock.Owin
|
||||
await response.Body.WriteAsync(bytes, 0, bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetResponseHeaders(ResponseMessage responseMessage, IResponse response)
|
||||
{
|
||||
// Set headers
|
||||
foreach (var pair in responseMessage.Headers)
|
||||
{
|
||||
if (ResponseHeadersToFix.ContainsKey(pair.Key))
|
||||
{
|
||||
ResponseHeadersToFix[pair.Key]?.Invoke(response, pair.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if !USE_ASPNETCORE
|
||||
// For non-NETSTANDARD, check if this response header can be added (#148)
|
||||
if (!WebHeaderCollection.IsRestricted(pair.Key, true))
|
||||
{
|
||||
response.Headers.AppendValues(pair.Key, pair.Value.ToArray());
|
||||
}
|
||||
#else
|
||||
// NETSTANDARD can add any header (or so it seems)
|
||||
response.Headers.Append(pair.Key, pair.Value.ToArray());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/WireMock.Net/Owin/MappingMatcher.cs
Normal file
50
src/WireMock.Net/Owin/MappingMatcher.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.Linq;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Owin
|
||||
{
|
||||
internal class MappingMatcher : IMappingMatcher
|
||||
{
|
||||
private readonly IWireMockMiddlewareOptions _options;
|
||||
|
||||
public MappingMatcher(IWireMockMiddlewareOptions options)
|
||||
{
|
||||
Check.NotNull(options, nameof(options));
|
||||
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public (IMapping Mapping, RequestMatchResult RequestMatchResult) Match(RequestMessage request)
|
||||
{
|
||||
var mappings = _options.Mappings.Values
|
||||
.Select(m => new
|
||||
{
|
||||
Mapping = m,
|
||||
MatchResult = m.GetRequestMatchResult(request, m.Scenario != null && _options.Scenarios.ContainsKey(m.Scenario) ? _options.Scenarios[m.Scenario].NextState : null)
|
||||
})
|
||||
.ToList();
|
||||
|
||||
if (_options.AllowPartialMapping)
|
||||
{
|
||||
var partialMappings = mappings
|
||||
.Where(pm => (pm.Mapping.IsAdminInterface && pm.MatchResult.IsPerfectMatch) || !pm.Mapping.IsAdminInterface)
|
||||
.OrderBy(m => m.MatchResult)
|
||||
.ThenBy(m => m.Mapping.Priority)
|
||||
.ToList();
|
||||
|
||||
var bestPartialMatch = partialMappings.FirstOrDefault(pm => pm.MatchResult.AverageTotalScore > 0.0);
|
||||
|
||||
return (bestPartialMatch?.Mapping, bestPartialMatch?.MatchResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
var perfectMatch = mappings
|
||||
.OrderBy(m => m.Mapping.Priority)
|
||||
.FirstOrDefault(m => m.MatchResult.IsPerfectMatch);
|
||||
|
||||
return (perfectMatch?.Mapping, perfectMatch?.MatchResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using WireMock.Http;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Owin.Mappers;
|
||||
using WireMock.Util;
|
||||
using WireMock.Validation;
|
||||
|
||||
@@ -15,12 +15,12 @@ namespace WireMock.Owin
|
||||
{
|
||||
internal class OwinSelfHost : IOwinSelfHost
|
||||
{
|
||||
private readonly WireMockMiddlewareOptions _options;
|
||||
private readonly IWireMockMiddlewareOptions _options;
|
||||
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
|
||||
private readonly IWireMockLogger _logger;
|
||||
private Exception _runningException;
|
||||
|
||||
public OwinSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
|
||||
public OwinSelfHost([NotNull] IWireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
|
||||
{
|
||||
Check.NotNull(options, nameof(options));
|
||||
Check.NotNullOrEmpty(uriPrefixes, nameof(uriPrefixes));
|
||||
@@ -74,11 +74,15 @@ namespace WireMock.Owin
|
||||
|
||||
try
|
||||
{
|
||||
var requestMapper = new OwinRequestMapper();
|
||||
var responseMapper = new OwinResponseMapper();
|
||||
var matcher = new MappingMatcher(_options);
|
||||
|
||||
Action<IAppBuilder> startup = app =>
|
||||
{
|
||||
app.Use<GlobalExceptionMiddleware>(_options);
|
||||
app.Use<GlobalExceptionMiddleware>(_options, responseMapper);
|
||||
_options.PreWireMockMiddlewareInit?.Invoke(app);
|
||||
app.Use<WireMockMiddleware>(_options);
|
||||
app.Use<WireMockMiddleware>(_options, requestMapper, responseMapper, matcher);
|
||||
_options.PostWireMockMiddlewareInit?.Invoke(app);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Matchers.Request;
|
||||
@@ -8,51 +7,73 @@ using WireMock.Matchers;
|
||||
using WireMock.Util;
|
||||
using Newtonsoft.Json;
|
||||
using WireMock.Http;
|
||||
using WireMock.Owin.Mappers;
|
||||
using WireMock.Serialization;
|
||||
using WireMock.Validation;
|
||||
#if !USE_ASPNETCORE
|
||||
using Microsoft.Owin;
|
||||
using IContext = Microsoft.Owin.IOwinContext;
|
||||
using OwinMiddleware = Microsoft.Owin.OwinMiddleware;
|
||||
using Next = Microsoft.Owin.OwinMiddleware;
|
||||
#else
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using OwinMiddleware = System.Object;
|
||||
using IContext = Microsoft.AspNetCore.Http.HttpContext;
|
||||
using Next = Microsoft.AspNetCore.Http.RequestDelegate;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Owin
|
||||
{
|
||||
#if !USE_ASPNETCORE
|
||||
internal class WireMockMiddleware : OwinMiddleware
|
||||
#else
|
||||
internal class WireMockMiddleware
|
||||
#endif
|
||||
{
|
||||
private static readonly Task CompletedTask = Task.FromResult(false);
|
||||
private readonly WireMockMiddlewareOptions _options;
|
||||
|
||||
private readonly OwinRequestMapper _requestMapper = new OwinRequestMapper();
|
||||
private readonly OwinResponseMapper _responseMapper = new OwinResponseMapper();
|
||||
private readonly IWireMockMiddlewareOptions _options;
|
||||
private readonly IOwinRequestMapper _requestMapper;
|
||||
private readonly IOwinResponseMapper _responseMapper;
|
||||
private readonly IMappingMatcher _mappingMatcher;
|
||||
|
||||
#if !USE_ASPNETCORE
|
||||
public WireMockMiddleware(OwinMiddleware next, WireMockMiddlewareOptions options) : base(next)
|
||||
public WireMockMiddleware(Next next, IWireMockMiddlewareOptions options, IOwinRequestMapper requestMapper, IOwinResponseMapper responseMapper, IMappingMatcher mappingMatcher) : base(next)
|
||||
{
|
||||
Check.NotNull(options, nameof(options));
|
||||
Check.NotNull(requestMapper, nameof(requestMapper));
|
||||
Check.NotNull(responseMapper, nameof(responseMapper));
|
||||
Check.NotNull(mappingMatcher, nameof(mappingMatcher));
|
||||
|
||||
_options = options;
|
||||
_requestMapper = requestMapper;
|
||||
_responseMapper = responseMapper;
|
||||
_mappingMatcher = mappingMatcher;
|
||||
}
|
||||
#else
|
||||
public WireMockMiddleware(RequestDelegate next, WireMockMiddlewareOptions options)
|
||||
public WireMockMiddleware(Next next, IWireMockMiddlewareOptions options, IOwinRequestMapper requestMapper, IOwinResponseMapper responseMapper, IMappingMatcher mappingMatcher)
|
||||
{
|
||||
Check.NotNull(options, nameof(options));
|
||||
Check.NotNull(requestMapper, nameof(requestMapper));
|
||||
Check.NotNull(responseMapper, nameof(responseMapper));
|
||||
|
||||
_options = options;
|
||||
_requestMapper = requestMapper;
|
||||
_responseMapper = responseMapper;
|
||||
_mappingMatcher = mappingMatcher;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !USE_ASPNETCORE
|
||||
public override async Task Invoke(IOwinContext ctx)
|
||||
public override Task Invoke(IContext ctx)
|
||||
#else
|
||||
public async Task Invoke(HttpContext ctx)
|
||||
public Task Invoke(IContext ctx)
|
||||
#endif
|
||||
{
|
||||
return InvokeInternal(ctx);
|
||||
}
|
||||
|
||||
private async Task InvokeInternal(IContext ctx)
|
||||
{
|
||||
var request = await _requestMapper.MapAsync(ctx.Request);
|
||||
|
||||
bool logRequest = false;
|
||||
ResponseMessage response = null;
|
||||
Mapping targetMapping = null;
|
||||
RequestMatchResult requestMatchResult = null;
|
||||
(IMapping TargetMapping, RequestMatchResult RequestMatchResult) result = (null, null);
|
||||
try
|
||||
{
|
||||
foreach (var mapping in _options.Mappings.Values.Where(m => m?.Scenario != null))
|
||||
@@ -67,36 +88,8 @@ namespace WireMock.Owin
|
||||
}
|
||||
}
|
||||
|
||||
var mappings = _options.Mappings.Values
|
||||
.Select(m => new
|
||||
{
|
||||
Mapping = m,
|
||||
MatchResult = m.GetRequestMatchResult(request, m.Scenario != null && _options.Scenarios.ContainsKey(m.Scenario) ? _options.Scenarios[m.Scenario].NextState : null)
|
||||
})
|
||||
.ToList();
|
||||
|
||||
if (_options.AllowPartialMapping)
|
||||
{
|
||||
var partialMappings = mappings
|
||||
.Where(pm => pm.Mapping.IsAdminInterface && pm.MatchResult.IsPerfectMatch || !pm.Mapping.IsAdminInterface)
|
||||
.OrderBy(m => m.MatchResult)
|
||||
.ThenBy(m => m.Mapping.Priority)
|
||||
.ToList();
|
||||
|
||||
var bestPartialMatch = partialMappings.FirstOrDefault(pm => pm.MatchResult.AverageTotalScore > 0.0);
|
||||
|
||||
targetMapping = bestPartialMatch?.Mapping;
|
||||
requestMatchResult = bestPartialMatch?.MatchResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
var perfectMatch = mappings
|
||||
.OrderBy(m => m.Mapping.Priority)
|
||||
.FirstOrDefault(m => m.MatchResult.IsPerfectMatch);
|
||||
|
||||
targetMapping = perfectMatch?.Mapping;
|
||||
requestMatchResult = perfectMatch?.MatchResult;
|
||||
}
|
||||
result = _mappingMatcher.Match(request);
|
||||
var targetMapping = result.TargetMapping;
|
||||
|
||||
if (targetMapping == null)
|
||||
{
|
||||
@@ -145,9 +138,9 @@ namespace WireMock.Owin
|
||||
Guid = Guid.NewGuid(),
|
||||
RequestMessage = request,
|
||||
ResponseMessage = response,
|
||||
MappingGuid = targetMapping?.Guid,
|
||||
MappingTitle = targetMapping?.Title,
|
||||
RequestMatchResult = requestMatchResult
|
||||
MappingGuid = result.TargetMapping?.Guid,
|
||||
MappingTitle = result.TargetMapping?.Title,
|
||||
RequestMatchResult = result.RequestMatchResult
|
||||
};
|
||||
|
||||
LogRequest(log, logRequest);
|
||||
|
||||
@@ -7,12 +7,12 @@ using WireMock.Util;
|
||||
#if !USE_ASPNETCORE
|
||||
using Owin;
|
||||
#else
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using IAppBuilder = Microsoft.AspNetCore.Builder.IApplicationBuilder;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Owin
|
||||
{
|
||||
internal class WireMockMiddlewareOptions
|
||||
internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions
|
||||
{
|
||||
public IWireMockLogger Logger { get; set; }
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace WireMock.Owin
|
||||
|
||||
public bool AllowPartialMapping { get; set; }
|
||||
|
||||
public ConcurrentDictionary<Guid, Mapping> Mappings { get; } = new ConcurrentDictionary<Guid, Mapping>();
|
||||
public ConcurrentDictionary<Guid, IMapping> Mappings { get; } = new ConcurrentDictionary<Guid, IMapping>();
|
||||
|
||||
public ConcurrentDictionary<string, ScenarioState> Scenarios { get; } = new ConcurrentDictionary<string, ScenarioState>();
|
||||
|
||||
@@ -32,14 +32,8 @@ namespace WireMock.Owin
|
||||
|
||||
public int? MaxRequestLogCount { get; set; }
|
||||
|
||||
#if !USE_ASPNETCORE
|
||||
public Action<IAppBuilder> PreWireMockMiddlewareInit { get; set; }
|
||||
|
||||
public Action<IAppBuilder> PostWireMockMiddlewareInit { get; set; }
|
||||
#else
|
||||
public Action<IApplicationBuilder> PreWireMockMiddlewareInit { get; set; }
|
||||
|
||||
public Action<IApplicationBuilder> PostWireMockMiddlewareInit { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("WireMock.Net.StandAlone")]
|
||||
[assembly: InternalsVisibleTo("WireMock.Net.Tests")]
|
||||
[assembly: InternalsVisibleTo("WireMock.Net.Tests")]
|
||||
|
||||
// Needed for Moq in the UnitTest project
|
||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
||||
@@ -49,10 +49,15 @@ namespace WireMock.ResponseBuilders
|
||||
public ResponseMessage ResponseMessage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A delegate to execute to generate the response
|
||||
/// A delegate to execute to generate the response.
|
||||
/// </summary>
|
||||
public Func<RequestMessage, ResponseMessage> Callback { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the method WithCallback(...) is used.
|
||||
/// </summary>
|
||||
public bool WithCallbackUsed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates this instance.
|
||||
/// </summary>
|
||||
@@ -171,7 +176,7 @@ namespace WireMock.ResponseBuilders
|
||||
{
|
||||
Check.NotNull(bodyFactory, nameof(bodyFactory));
|
||||
|
||||
return WithCallback(req => new ResponseMessage
|
||||
return WithCallbackInternal(false, req => new ResponseMessage
|
||||
{
|
||||
Body = bodyFactory(req),
|
||||
BodyDestination = destination,
|
||||
@@ -341,6 +346,15 @@ namespace WireMock.ResponseBuilders
|
||||
{
|
||||
Check.NotNull(callbackHandler, nameof(callbackHandler));
|
||||
|
||||
return WithCallbackInternal(true, callbackHandler);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ICallbackResponseBuilder.WithCallback"/>
|
||||
private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func<RequestMessage, ResponseMessage> callbackHandler)
|
||||
{
|
||||
Check.NotNull(callbackHandler, nameof(callbackHandler));
|
||||
|
||||
WithCallbackUsed = withCallbackUsed;
|
||||
Callback = callbackHandler;
|
||||
|
||||
return this;
|
||||
@@ -364,13 +378,16 @@ namespace WireMock.ResponseBuilders
|
||||
{
|
||||
var callbackResponseMessage = Callback(requestMessage);
|
||||
|
||||
// Copy StatusCode from ResponseMessage
|
||||
callbackResponseMessage.StatusCode = ResponseMessage.StatusCode;
|
||||
|
||||
// Copy Headers from ResponseMessage (if defined)
|
||||
if (ResponseMessage.Headers != null)
|
||||
if (!WithCallbackUsed)
|
||||
{
|
||||
callbackResponseMessage.Headers = ResponseMessage.Headers;
|
||||
// Copy StatusCode from ResponseMessage
|
||||
callbackResponseMessage.StatusCode = ResponseMessage.StatusCode;
|
||||
|
||||
// Copy Headers from ResponseMessage (if defined)
|
||||
if (ResponseMessage.Headers != null)
|
||||
{
|
||||
callbackResponseMessage.Headers = ResponseMessage.Headers;
|
||||
}
|
||||
}
|
||||
|
||||
return callbackResponseMessage;
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace WireMock.Serialization
|
||||
{
|
||||
internal static class MappingConverter
|
||||
{
|
||||
public static MappingModel ToMappingModel(Mapping mapping)
|
||||
public static MappingModel ToMappingModel(IMapping mapping)
|
||||
{
|
||||
var request = (Request)mapping.RequestMatcher;
|
||||
var response = (Response)mapping.Provider;
|
||||
|
||||
@@ -256,7 +256,7 @@ namespace WireMock.Server
|
||||
return responseMessage;
|
||||
}
|
||||
|
||||
private Mapping ToMapping(RequestMessage requestMessage, ResponseMessage responseMessage, string[] blacklistedHeaders)
|
||||
private IMapping ToMapping(RequestMessage requestMessage, ResponseMessage responseMessage, string[] blacklistedHeaders)
|
||||
{
|
||||
var request = Request.Create();
|
||||
request.WithPath(requestMessage.Path);
|
||||
@@ -371,7 +371,7 @@ namespace WireMock.Server
|
||||
return ResponseMessageBuilder.Create("Mappings saved to disk");
|
||||
}
|
||||
|
||||
private void SaveMappingToFile(Mapping mapping, string folder = null)
|
||||
private void SaveMappingToFile(IMapping mapping, string folder = null)
|
||||
{
|
||||
if (folder == null)
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace WireMock.Server
|
||||
|
||||
private const int ServerStartDelay = 100;
|
||||
private readonly IOwinSelfHost _httpServer;
|
||||
private readonly WireMockMiddlewareOptions _options = new WireMockMiddlewareOptions();
|
||||
private readonly IWireMockMiddlewareOptions _options = new WireMockMiddlewareOptions();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this server is started.
|
||||
@@ -53,7 +53,7 @@ namespace WireMock.Server
|
||||
/// Gets the mappings.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public IEnumerable<Mapping> Mappings => _options.Mappings.Values.ToArray();
|
||||
public IEnumerable<IMapping> Mappings => _options.Mappings.Values.ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scenarios.
|
||||
@@ -265,6 +265,11 @@ namespace WireMock.Server
|
||||
InitProxyAndRecord(settings);
|
||||
}
|
||||
|
||||
if (settings.RequestLogExpirationDuration != null)
|
||||
{
|
||||
SetRequestLogExpirationDuration(settings.RequestLogExpirationDuration);
|
||||
}
|
||||
|
||||
if (settings.MaxRequestLogCount != null)
|
||||
{
|
||||
SetMaxRequestLogCount(settings.MaxRequestLogCount);
|
||||
@@ -424,7 +429,7 @@ namespace WireMock.Server
|
||||
return new RespondWithAProvider(RegisterMapping, requestMatcher);
|
||||
}
|
||||
|
||||
private void RegisterMapping(Mapping mapping)
|
||||
private void RegisterMapping(IMapping mapping)
|
||||
{
|
||||
// Check a mapping exists with the same Guid, if so, replace it.
|
||||
if (_options.Mappings.ContainsKey(mapping.Guid))
|
||||
|
||||
Reference in New Issue
Block a user