Rewrite some unit-integration-tests to unit-tests (#206 #207)

Rewrite some unit-integration-tests to unit-tests (#206)
This commit is contained in:
Stef Heyenrath
2018-09-26 17:43:26 +02:00
committed by GitHub
parent 713e59bbf9
commit ada50d893f
134 changed files with 9159 additions and 8434 deletions

View 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; }
}
}

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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
{

View File

@@ -0,0 +1,9 @@
using WireMock.Matchers.Request;
namespace WireMock.Owin
{
internal interface IMappingMatcher
{
(IMapping Mapping, RequestMatchResult RequestMatchResult) Match(RequestMessage request);
}
}

View 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; }
}
}

View 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);
}
}

View 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);
}
}

View File

@@ -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());
}
}
}

View File

@@ -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
}
}
}
}
}

View 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);
}
}
}
}

View File

@@ -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);
};

View File

@@ -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);

View File

@@ -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
}
}

View File

@@ -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")]

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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))