merge netstandard into main (#26)

* #23

* #23 "Newtonsoft.Json" Version="10.0.2"

* owin

* AspNetCore

* Fix appveyor build

* fix start/stop in untitests
This commit is contained in:
Stef Heyenrath
2017-04-26 21:28:12 +02:00
committed by GitHub
parent 0f8f9c508f
commit 453cef90e5
106 changed files with 17753 additions and 24342 deletions

View File

@@ -0,0 +1,100 @@
#if !NET45
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using WireMock.Validation;
namespace WireMock.Owin
{
internal class AspNetCoreSelfHost : IOwinSelfHost
{
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private readonly WireMockMiddlewareOptions _options;
private readonly string[] _uriPrefixes;
public bool IsStarted { get; private set; }
public List<Uri> Urls { get; } = new List<Uri>();
public List<int> Ports { get; } = new List<int>();
public AspNetCoreSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
{
Check.NotNull(options, nameof(options));
Check.NotEmpty(uriPrefixes, nameof(uriPrefixes));
foreach (string uriPrefix in uriPrefixes)
{
var uri = new Uri(uriPrefix);
Urls.Add(uri);
Ports.Add(uri.Port);
}
_options = options;
_uriPrefixes = uriPrefixes;
}
public Task StartAsync()
{
return Task.Run(() =>
{
var host = new WebHostBuilder()
.ConfigureLogging(factory => factory.AddConsole(LogLevel.None))
.Configure(appBuilder =>
{
// appBuilder.UseExceptionHandler(builder => )
appBuilder.UseMiddleware<WireMockMiddleware>(_options);
})
.UseKestrel()
.UseUrls(_uriPrefixes)
.Build();
host.Run(_cts.Token);
IsStarted = true;
}, _cts.Token);
}
public Task StopAsync()
{
_cts.Cancel();
IsStarted = false;
return Task.FromResult(true);
}
}
internal class Startup
{
public Startup(IHostingEnvironment env)
{
//var builder = new ConfigurationBuilder()
// .SetBasePath(env.ContentRootPath)
// .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
// .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
// .AddEnvironmentVariables();
//Configuration = builder.Build();
}
// public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseMiddleware<WireMockMiddleware>();
}
}
}
#endif

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace WireMock.Owin
{
interface IOwinSelfHost
{
/// <summary>
/// Gets a value indicating whether this server is started.
/// </summary>
/// <value>
/// <c>true</c> if this server is started; otherwise, <c>false</c>.
/// </value>
bool IsStarted { get; }
/// <summary>
/// Gets the url.
/// </summary>
/// <value>
/// The urls.
/// </value>
List<Uri> Urls { get; }
/// <summary>
/// Gets the ports.
/// </summary>
/// <value>
/// The ports.
/// </value>
List<int> Ports { get; }
Task StartAsync();
Task StopAsync();
}
}

View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#if NET45
using Microsoft.Owin;
#else
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Http.Features;
#endif
namespace WireMock.Owin
{
/// <summary>
/// OwinRequestMapper
/// </summary>
public class OwinRequestMapper
{
/// <summary>
/// MapAsync IOwinRequest to RequestMessage
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<RequestMessage> MapAsync(
#if NET45
IOwinRequest request
#else
HttpRequest request
#endif
)
{
#if NET45
Uri url = request.Uri;
#else
Uri url = new Uri(request.GetEncodedUrl());
#endif
string verb = request.Method;
string bodyAsString = null;
byte[] body = null;
Encoding bodyEncoding = null;
if (request.Body != null)
{
using (var streamReader = new StreamReader(request.Body))
{
bodyAsString = await streamReader.ReadToEndAsync();
bodyEncoding = streamReader.CurrentEncoding;
}
body = bodyEncoding.GetBytes(bodyAsString);
}
var listenerHeaders = request.Headers;
var headers = new Dictionary<string, string>();
foreach (var header in listenerHeaders)
headers.Add(header.Key, header.Value.FirstOrDefault());
var cookies = new Dictionary<string, string>();
foreach (var cookie in request.Cookies)
cookies.Add(cookie.Key, cookie.Value);
return new RequestMessage(url, verb, body, bodyAsString, bodyEncoding, headers, cookies) { DateTime = DateTime.Now };
}
}
}

View File

@@ -0,0 +1,47 @@
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#if NET45
using Microsoft.Owin;
#else
using Microsoft.AspNetCore.Http;
#endif
namespace WireMock.Owin
{
/// <summary>
/// OwinResponseMapper
/// </summary>
public class OwinResponseMapper
{
private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
/// <summary>
/// MapAsync ResponseMessage to OwinResponse
/// </summary>
/// <param name="responseMessage"></param>
/// <param name="response"></param>
public async Task MapAsync(ResponseMessage responseMessage
#if NET45
, IOwinResponse response
#else
, HttpResponse response
#endif
)
{
response.StatusCode = responseMessage.StatusCode;
responseMessage.Headers.ToList().ForEach(pair => response.Headers.Append(pair.Key, pair.Value));
if (responseMessage.Body == null)
return;
Encoding encoding = responseMessage.BodyEncoding ?? _utf8NoBom;
using (var writer = new StreamWriter(response.Body, encoding))
{
await writer.WriteAsync(responseMessage.Body);
}
}
}
}

View File

@@ -0,0 +1,116 @@
#if NET45
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Validation;
using Owin;
using Microsoft.Owin.Hosting;
namespace WireMock.Owin
{
internal class OwinSelfHost : IOwinSelfHost
{
private readonly WireMockMiddlewareOptions _options;
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private System.Threading.Thread _internalThread;
public OwinSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
{
Check.NotNull(options, nameof(options));
Check.NotEmpty(uriPrefixes, nameof(uriPrefixes));
foreach (string uriPrefix in uriPrefixes)
{
var uri = new Uri(uriPrefix);
Urls.Add(uri);
Ports.Add(uri.Port);
}
_options = options;
}
public bool IsStarted { get; private set; }
public List<Uri> Urls { get; } = new List<Uri>();
public List<int> Ports { get; } = new List<int>();
[PublicAPI]
public Task StartAsync()
{
return Task.Run(() =>
{
StartServers();
}, _cts.Token);
//if (_internalThread != null)
// throw new InvalidOperationException("Cannot start a multiple threads.");
//_internalThread = new Thread(ThreadWorkInternal);
//_internalThread.Start();
}
[PublicAPI]
public Task StopAsync()
{
_cts.Cancel();
var tcs = new TaskCompletionSource<bool>();
var timer = new System.Timers.Timer(999);
timer.Elapsed += (sender, e) =>
{
if (_internalThread == null)
{
timer.Stop();
tcs.SetResult(true);
}
};
timer.Start();
return tcs.Task;
}
private void ThreadWorkInternal()
{
try
{
StartServers();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
_internalThread = null;
}
}
private void StartServers()
{
Action<IAppBuilder> startup = app =>
{
app.Use<WireMockMiddleware>(_options);
};
var servers = new List<IDisposable>();
foreach (var url in Urls)
{
servers.Add(WebApp.Start(url.ToString(), startup));
}
IsStarted = true;
while (!_cts.IsCancellationRequested)
Thread.Sleep(1000);
IsStarted = false;
foreach (var server in servers)
server.Dispose();
}
}
}
#endif

View File

@@ -0,0 +1,144 @@
using System;
using System.Collections;
using System.Threading.Tasks;
using WireMock.Logging;
using WireMock.Matchers.Request;
using System.Linq;
#if NET45
using Microsoft.Owin;
#else
using Microsoft.AspNetCore.Http;
#endif
namespace WireMock.Owin
{
#if NET45
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();
#if NET45
public WireMockMiddleware(OwinMiddleware next, WireMockMiddlewareOptions options) : base(next)
{
_options = options;
}
#else
public WireMockMiddleware(RequestDelegate next, WireMockMiddlewareOptions options)
{
_options = options;
}
#endif
#if NET45
public override async Task Invoke(IOwinContext ctx)
#else
public async Task Invoke(HttpContext ctx)
#endif
{
if (_options.RequestProcessingDelay > TimeSpan.Zero)
{
await Task.Delay(_options.RequestProcessingDelay.Value);
// Thread.Sleep(_options.RequestProcessingDelay.Value);
}
var request = await _requestMapper.MapAsync(ctx.Request);
ResponseMessage response = null;
Mapping targetMapping = null;
RequestMatchResult requestMatchResult = null;
try
{
var mappings = _options.Mappings
.Select(m => new
{
Mapping = m,
MatchResult = m.IsRequestHandled(request)
})
.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;
}
if (targetMapping == null)
{
response = new ResponseMessage { StatusCode = 404, Body = "No matching mapping found" };
return;
}
if (targetMapping.IsAdminInterface && _options.AuthorizationMatcher != null)
{
string authorization;
bool present = request.Headers.TryGetValue("Authorization", out authorization);
if (!present || _options.AuthorizationMatcher.IsMatch(authorization) < 1.0)
{
response = new ResponseMessage { StatusCode = 401 };
return;
}
}
response = await targetMapping.ResponseTo(request);
}
catch (Exception ex)
{
response = new ResponseMessage { StatusCode = 500, Body = ex.ToString() };
}
finally
{
var log = new LogEntry
{
Guid = Guid.NewGuid(),
RequestMessage = request,
ResponseMessage = response,
MappingGuid = targetMapping?.Guid,
MappingTitle = targetMapping?.Title,
RequestMatchResult = requestMatchResult
};
LogRequest(log);
await _responseMapper.MapAsync(response, ctx.Response);
}
await CompletedTask;
}
/// <summary>
/// The log request.
/// </summary>
/// <param name="entry">The request.</param>
private void LogRequest(LogEntry entry)
{
lock (((ICollection)_options.LogEntries).SyncRoot)
{
_options.LogEntries.Add(entry);
}
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using WireMock.Logging;
using WireMock.Matchers;
namespace WireMock.Owin
{
internal class WireMockMiddlewareOptions
{
public TimeSpan? RequestProcessingDelay { get; set; }
public IMatcher AuthorizationMatcher { get; set; }
public bool AllowPartialMapping { get; set; }
public IList<Mapping> Mappings { get; set; }
public IList<LogEntry> LogEntries { get; set; }
public WireMockMiddlewareOptions()
{
Mappings = new List<Mapping>();
LogEntries = new List<LogEntry>();
}
}
}