Compare commits

...

7 Commits

Author SHA1 Message Date
Stef Heyenrath
15370a89ca 1.0.2.5 2017-10-24 18:12:39 +02:00
Stef Heyenrath
656f7f5432 HttpClientHelper : BodyAsBytes 2017-10-23 20:56:01 +02:00
deeptowncitizen
bcdc3d646a fix header (#55) 2017-10-23 20:25:06 +02:00
Stef Heyenrath
10350fac04 Merge branch 'appbuilder' 2017-10-18 20:19:03 +02:00
Stef Heyenrath
37244d5c2f PreWireMockMiddlewareInit / PostWireMockMiddlewareInit 2017-10-17 20:47:19 +02:00
Stef Heyenrath
07f03997c0 Fix issues with Bytes for Response 2017-10-14 10:48:58 +02:00
Stef Heyenrath
7c289d44a7 Update client interface for Scenarios 2017-10-10 18:21:22 +02:00
27 changed files with 924 additions and 530 deletions

View File

@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.13
VisualStudioVersion = 15.0.27004.2002
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EF242EDF-7133-4277-9A0C-18744DE08707}"
EndProject
@@ -21,11 +21,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net", "src\WireMoc
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Tests", "test\WireMock.Net.Tests\WireMock.Net.Tests.csproj", "{31DC2EF8-C3FE-467D-84BE-FB5D956E612E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Console.NETCoreApp", "examples\WireMock.Net.Console.NETCoreApp\WireMock.Net.Console.NETCoreApp.csproj", "{FE281639-B014-4C8A-96FA-141164A74713}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.NETCoreApp", "examples\WireMock.Net.Console.NETCoreApp\WireMock.Net.Console.NETCoreApp.csproj", "{FE281639-B014-4C8A-96FA-141164A74713}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.Record.NETCoreApp", "examples\WireMock.Net.Console.Record.NETCoreApp\WireMock.Net.Console.Record.NETCoreApp.csproj", "{1995E414-F197-4AB4-90C2-68D806B5AF59}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Client", "examples\WireMock.Net.Client\WireMock.Net.Client.csproj", "{058D4B6C-C03E-49D0-91DB-A535B058FA0D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Client", "examples\WireMock.Net.Client\WireMock.Net.Client.csproj", "{058D4B6C-C03E-49D0-91DB-A535B058FA0D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.StandAlone", "src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj", "{B6269AAC-170A-43D5-8B9A-579DED3D9A95}"
EndProject
@@ -36,6 +36,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.StandAlone.Net
{B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {B6269AAC-170A-43D5-8B9A-579DED3D9A95}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.ConsoleApplication", "examples\WireMock.Net.ConsoleApplication\WireMock.Net.ConsoleApplication.csproj", "{668F689E-57B4-422E-8846-C0FF643CA268}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -74,6 +76,10 @@ Global
{668F689E-57B4-422E-8846-C0FF643CA999}.Debug|Any CPU.Build.0 = Debug|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA999}.Release|Any CPU.ActiveCfg = Release|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA999}.Release|Any CPU.Build.0 = Release|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA268}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA268}.Debug|Any CPU.Build.0 = Debug|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA268}.Release|Any CPU.ActiveCfg = Release|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA268}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -87,5 +93,9 @@ Global
{B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {EF242EDF-7133-4277-9A0C-18744DE08707}
{10E16614-61CA-48D8-8BDD-664C13913DED} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{668F689E-57B4-422E-8846-C0FF643CA999} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{668F689E-57B4-422E-8846-C0FF643CA268} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BF428BCC-C837-433B-87D2-15C7014B73E9}
EndGlobalSection
EndGlobal

View File

@@ -1,5 +1,4 @@
using System;
using System.Linq;
using Newtonsoft.Json;
using WireMock.Matchers;
using WireMock.RequestBuilders;
@@ -21,7 +20,9 @@ namespace WireMock.Net.ConsoleApplication
{
Urls = new[] { url1, url2, url3 },
StartAdminInterface = true,
ReadStaticMappings = true
ReadStaticMappings = false,
PreWireMockMiddlewareInit = app => { System.Console.WriteLine($"PreWireMockMiddlewareInit : {app.GetType()}"); },
PostWireMockMiddlewareInit = app => { System.Console.WriteLine($"PostWireMockMiddlewareInit : {app.GetType()}"); }
});
System.Console.WriteLine("FluentMockServer listening at {0}", string.Join(" and ", server.Urls));
@@ -29,6 +30,21 @@ namespace WireMock.Net.ConsoleApplication
// server.AllowPartialMapping();
server
.Given(Request.Create().WithHeader("ProxyThis", "true")
.UsingGet())
.RespondWith(Response.Create()
.WithProxy("http://www.google.com")
);
server
.Given(Request.Create().WithPath("/bodyasbytes.png")
.UsingGet())
.RespondWith(Response.Create()
.WithHeader("Content-Type", "image/png")
.WithBody(Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTczbp9jAAAAJ0lEQVQoU2NgUPuPD6Hz0RCEAtJoiAxpCCBXGgmRIo0TofORkdp/AMiMdRVnV6O0AAAAAElFTkSuQmCC"))
);
server
.Given(Request.Create().WithPath("/oauth2/access").UsingPost().WithBody("grant_type=password;username=u;password=p"))
.RespondWith(Response.Create()

View File

@@ -47,9 +47,6 @@
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="WireMock.Net">
<HintPath>..\..\src\WireMock.Net\bin\$(Configuration)\net45\WireMock.Net.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="MainApp.cs" />
@@ -67,6 +64,16 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj">
<Project>{b6269aac-170a-43d5-8b9a-579ded3d9a95}</Project>
<Name>WireMock.Net.StandAlone</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj">
<Project>{d3804228-91f4-4502-9595-39584e5a01ad}</Project>
<Name>WireMock.Net</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -3,10 +3,9 @@
<PropertyGroup>
<Description>Lightweight StandAlone Http Mocking Server for .Net.</Description>
<AssemblyTitle>WireMock.Net.StandAlone</AssemblyTitle>
<Version>1.0.2.4</Version>
<Version>1.0.2.5</Version>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<!-- <TargetFrameworks>netstandard1.3;netstandard2.0</TargetFrameworks> -->
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.StandAlone</AssemblyName>
<PackageId>WireMock.Net.StandAlone</PackageId>

View File

@@ -15,6 +15,11 @@ namespace WireMock.Admin.Mappings
/// </value>
public int? StatusCode { get; set; }
/// <summary>
/// Gets or sets the body destination (SameAsSource, String or Bytes).
/// </summary>
public string BodyDestination { get; set; }
/// <summary>
/// Gets or sets the body.
/// </summary>
@@ -29,7 +34,7 @@ namespace WireMock.Admin.Mappings
/// <value>
/// The body.
/// </value>
public string BodyAsBase64 { get; set; }
public string BodyFromBase64 { get; set; }
/// <summary>
/// Gets or sets the body (as JSON object).
@@ -39,6 +44,14 @@ namespace WireMock.Admin.Mappings
/// </value>
public object BodyAsJson { get; set; }
/// <summary>
/// Gets or sets the body (as bytearray).
/// </summary>
/// <value>
/// The body.
/// </value>
public byte[] BodyAsBytes { get; set; }
/// <summary>
/// Gets or sets the body encoding.
/// </summary>

View File

@@ -18,11 +18,21 @@ namespace WireMock.Admin.Requests
/// </summary>
public IDictionary<string, string> Headers { get; set; }
/// <summary>
/// Gets or sets the body destination (SameAsSource, String or Bytes).
/// </summary>
public string BodyDestination { get; set; }
/// <summary>
/// Gets or sets the body.
/// </summary>
public string Body { get; set; }
/// <summary>
/// Gets or sets the body.
/// </summary>
public byte[] BodyAsBytes { get; set; }
/// <summary>
/// Gets or sets the original body.
/// </summary>

View File

@@ -138,5 +138,23 @@ namespace WireMock.Client
/// <param name="model">The RequestModel</param>
[Post("__admin/requests/find")]
Task<IList<LogRequestModel>> FindRequestsAsync([Body] RequestModel model);
/// <summary>
/// Get all scenarios
/// </summary>
[Get("__admin/scenarios")]
Task<string> GetScenariosAsync();
/// <summary>
/// Delete (reset) all scenarios
/// </summary>
[Delete("__admin/scenarios")]
Task<string> DeleteScenariosAsync();
/// <summary>
/// Delete (reset) all scenarios
/// </summary>
[Post("__admin/scenarios")]
Task<string> ResetScenariosAsync();
}
}

View File

@@ -2,15 +2,12 @@
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
namespace WireMock.Http
{
internal static class HttpClientHelper
{
private static HttpClient CreateHttpClient(string clientX509Certificate2ThumbprintOrSubjectName = null)
{
if (!string.IsNullOrEmpty(clientX509Certificate2ThumbprintOrSubjectName))
@@ -25,8 +22,6 @@ namespace WireMock.Http
var x509Certificate2 = CertificateUtil.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName);
handler.ClientCertificates.Add(x509Certificate2);
#else
var handler = new WebRequestHandler
{
@@ -58,7 +53,7 @@ namespace WireMock.Http
{
foreach (var headerName in requestMessage.Headers.Keys.Where(k => k.ToUpper() != "HOST"))
{
httpRequestMessage.Headers.Add(headerName, new[] { requestMessage.Headers[headerName] });
httpRequestMessage.Headers.TryAddWithoutValidation(headerName, new[] { requestMessage.Headers[headerName] });
}
}
@@ -71,11 +66,12 @@ namespace WireMock.Http
// Call the URL
var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead);
// Transform response
var responseMessage = new ResponseMessage
{
StatusCode = (int)httpResponseMessage.StatusCode,
BodyAsBytes = await httpResponseMessage.Content.ReadAsByteArrayAsync(),
Body = await httpResponseMessage.Content.ReadAsStringAsync()
};

View File

@@ -0,0 +1,96 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace WireMock.Http
{
/// <summary>
/// Copied from https://raw.githubusercontent.com/dotnet/corefx/master/src/Common/src/System/Net/HttpKnownHeaderNames.cs
/// </summary>
internal static class HttpKnownHeaderNames
{
public const string Accept = "Accept";
public const string AcceptCharset = "Accept-Charset";
public const string AcceptEncoding = "Accept-Encoding";
public const string AcceptLanguage = "Accept-Language";
public const string AcceptPatch = "Accept-Patch";
public const string AcceptRanges = "Accept-Ranges";
public const string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";
public const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
public const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
public const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
public const string AccessControlExposeHeaders = "Access-Control-Expose-Headers";
public const string AccessControlMaxAge = "Access-Control-Max-Age";
public const string Age = "Age";
public const string Allow = "Allow";
public const string AltSvc = "Alt-Svc";
public const string Authorization = "Authorization";
public const string CacheControl = "Cache-Control";
public const string Connection = "Connection";
public const string ContentDisposition = "Content-Disposition";
public const string ContentEncoding = "Content-Encoding";
public const string ContentLanguage = "Content-Language";
public const string ContentLength = "Content-Length";
public const string ContentLocation = "Content-Location";
public const string ContentMD5 = "Content-MD5";
public const string ContentRange = "Content-Range";
public const string ContentSecurityPolicy = "Content-Security-Policy";
public const string ContentType = "Content-Type";
public const string Cookie = "Cookie";
public const string Cookie2 = "Cookie2";
public const string Date = "Date";
public const string ETag = "ETag";
public const string Expect = "Expect";
public const string Expires = "Expires";
public const string From = "From";
public const string Host = "Host";
public const string IfMatch = "If-Match";
public const string IfModifiedSince = "If-Modified-Since";
public const string IfNoneMatch = "If-None-Match";
public const string IfRange = "If-Range";
public const string IfUnmodifiedSince = "If-Unmodified-Since";
public const string KeepAlive = "Keep-Alive";
public const string LastModified = "Last-Modified";
public const string Link = "Link";
public const string Location = "Location";
public const string MaxForwards = "Max-Forwards";
public const string Origin = "Origin";
public const string P3P = "P3P";
public const string Pragma = "Pragma";
public const string ProxyAuthenticate = "Proxy-Authenticate";
public const string ProxyAuthorization = "Proxy-Authorization";
public const string ProxyConnection = "Proxy-Connection";
public const string PublicKeyPins = "Public-Key-Pins";
public const string Range = "Range";
public const string Referer = "Referer"; // NB: The spelling-mistake "Referer" for "Referrer" must be matched.
public const string RetryAfter = "Retry-After";
public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions";
public const string SecWebSocketKey = "Sec-WebSocket-Key";
public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
public const string SecWebSocketVersion = "Sec-WebSocket-Version";
public const string Server = "Server";
public const string SetCookie = "Set-Cookie";
public const string SetCookie2 = "Set-Cookie2";
public const string StrictTransportSecurity = "Strict-Transport-Security";
public const string TE = "TE";
public const string TSV = "TSV";
public const string Trailer = "Trailer";
public const string TransferEncoding = "Transfer-Encoding";
public const string Upgrade = "Upgrade";
public const string UpgradeInsecureRequests = "Upgrade-Insecure-Requests";
public const string UserAgent = "User-Agent";
public const string Vary = "Vary";
public const string Via = "Via";
public const string WWWAuthenticate = "WWW-Authenticate";
public const string Warning = "Warning";
public const string XAspNetVersion = "X-AspNet-Version";
public const string XContentDuration = "X-Content-Duration";
public const string XContentTypeOptions = "X-Content-Type-Options";
public const string XFrameOptions = "X-Frame-Options";
public const string XMSEdgeRef = "X-MSEdge-Ref";
public const string XPoweredBy = "X-Powered-By";
public const string XRequestID = "X-Request-ID";
public const string XUACompatible = "X-UA-Compatible";
}
}

View File

@@ -46,7 +46,9 @@ namespace WireMock.Owin
_host = new WebHostBuilder()
.Configure(appBuilder =>
{
_options.PreWireMockMiddlewareInit?.Invoke(appBuilder);
appBuilder.UseMiddleware<WireMockMiddleware>(_options);
_options.PostWireMockMiddlewareInit?.Invoke(appBuilder);
})
.UseKestrel()
.UseUrls(_uriPrefixes)

View File

@@ -46,7 +46,7 @@ namespace WireMock.Owin
string bodyAsString = null;
byte[] body = null;
Encoding bodyEncoding = null;
if (request.Body != null)
if (ParseBody(method) && request.Body != null)
{
using (var streamReader = new StreamReader(request.Body))
{
@@ -57,18 +57,42 @@ namespace WireMock.Owin
body = bodyEncoding.GetBytes(bodyAsString);
}
var listenerHeaders = request.Headers;
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.FirstOrDefault());
}
}
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);
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);
}
}
return new RequestMessage(url, method, clientIP, body, bodyAsString, bodyEncoding, headers, cookies) { DateTime = DateTime.Now };
}
private bool ParseBody(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
*/
return new[] { "PUT", "POST", "OPTIONS" }.Contains(method.ToUpper());
}
}
}

View File

@@ -2,6 +2,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WireMock.Http;
#if !NETSTANDARD
using Microsoft.Owin;
#else
@@ -32,15 +33,28 @@ namespace WireMock.Owin
{
response.StatusCode = responseMessage.StatusCode;
responseMessage.Headers.ToList().ForEach(pair => response.Headers.Append(pair.Key, pair.Value));
if (responseMessage.Headers.ContainsKey(HttpKnownHeaderNames.ContentType))
{
response.ContentType = responseMessage.Headers[HttpKnownHeaderNames.ContentType];
}
responseMessage.Headers.Where(h => h.Key != HttpKnownHeaderNames.ContentType).ToList().ForEach(pair => response.Headers.Append(pair.Key, pair.Value));
if (responseMessage.Body == null)
if (responseMessage.Body == null && responseMessage.BodyAsBytes == null)
{
return;
}
if (responseMessage.BodyAsBytes != null)
{
await response.Body.WriteAsync(responseMessage.BodyAsBytes, 0, responseMessage.BodyAsBytes.Length);
return;
}
Encoding encoding = responseMessage.BodyEncoding ?? _utf8NoBom;
using (var writer = new StreamWriter(response.Body, encoding))
{
await writer.WriteAsync(responseMessage.Body);
// TODO : response.ContentLength = responseMessage.Body.Length;
}
}
}

View File

@@ -57,11 +57,13 @@ namespace WireMock.Owin
private void StartServers()
{
System.Console.WriteLine("WireMock.Net server using .net 4.5.x or .net 4.6.x");
Console.WriteLine("WireMock.Net server using .net 4.5.x or .net 4.6.x");
Action<IAppBuilder> startup = app =>
{
_options.PreWireMockMiddlewareInit?.Invoke(app);
app.Use<WireMockMiddleware>(_options);
_options.PostWireMockMiddlewareInit?.Invoke(app);
};
var servers = new List<IDisposable>();

View File

@@ -50,7 +50,7 @@ namespace WireMock.Owin
RequestMatchResult requestMatchResult = null;
try
{
foreach (var mapping in _options.Mappings.Where(m => m.Scenario != null))
foreach (var mapping in _options.Mappings.Where(m => m?.Scenario != null))
{
// Set start
if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState)

View File

@@ -4,6 +4,11 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using WireMock.Logging;
using WireMock.Matchers;
#if !NETSTANDARD
using Owin;
#else
using Microsoft.AspNetCore.Builder;
#endif
namespace WireMock.Owin
{
@@ -24,5 +29,15 @@ namespace WireMock.Owin
public int? MaxRequestLogCount { get; set; }
public IDictionary<string, object> Scenarios { get; } = new ConcurrentDictionary<string, object>();
#if !NETSTANDARD
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

@@ -51,7 +51,7 @@ namespace WireMock
/// <summary>
/// Gets the query.
/// </summary>
public IDictionary<string, WireMockList<string>> Query { get; } = new Dictionary<string, WireMockList<string>>();
public IDictionary<string, WireMockList<string>> Query { get; }
/// <summary>
/// Gets the bodyAsBytes.
@@ -94,34 +94,38 @@ namespace WireMock
BodyEncoding = bodyEncoding;
Headers = headers;
Cookies = cookies;
Query = ParseQuery(url.Query);
}
string query = url.Query;
if (!string.IsNullOrEmpty(query))
private IDictionary<string, WireMockList<string>> ParseQuery(string queryString)
{
if (string.IsNullOrEmpty(queryString))
{
if (query.StartsWith("?"))
{
query = query.Substring(1);
}
Query = query.Split('&').Aggregate(
new Dictionary<string, WireMockList<string>>(),
(dict, term) =>
{
var parts = term.Split('=');
string key = parts[0];
if (!dict.ContainsKey(key))
{
dict.Add(key, new WireMockList<string>());
}
if (parts.Length == 2)
{
dict[key].Add(parts[1]);
}
return dict;
});
return null;
}
if (queryString.StartsWith("?"))
{
queryString = queryString.Substring(1);
}
return queryString.Split('&').Aggregate(new Dictionary<string, WireMockList<string>>(),
(dict, term) =>
{
var parts = term.Split('=');
string key = parts[0];
if (!dict.ContainsKey(key))
{
dict.Add(key, new WireMockList<string>());
}
if (parts.Length == 2)
{
dict[key].Add(parts[1]);
}
return dict;
});
}
/// <summary>
@@ -131,6 +135,11 @@ namespace WireMock
/// <returns>The query parameter.</returns>
public List<string> GetParameter(string key)
{
if (Query == null)
{
return null;
}
return Query.ContainsKey(key) ? Query[key] : null;
}
}

View File

@@ -0,0 +1,23 @@
namespace WireMock.ResponseBuilders
{
/// <summary>
/// Defines the BodyDestinationFormat
/// </summary>
public static class BodyDestinationFormat
{
/// <summary>
/// Same as source (no conversion)
/// </summary>
public const string SameAsSource = "SameAsSource";
/// <summary>
/// Convert to string
/// </summary>
public const string String = "String";
/// <summary>
/// Convert to bytes
/// </summary>
public const string Bytes = "Bytes";
}
}

View File

@@ -1,4 +1,5 @@
using System.Text;
using System;
using System.Text;
using JetBrains.Annotations;
namespace WireMock.ResponseBuilders
@@ -8,16 +9,34 @@ namespace WireMock.ResponseBuilders
/// </summary>
public interface IBodyResponseBuilder : ITransformResponseBuilder
{
/// <summary>
/// The with body.
/// </summary>
/// <param name="body">The body.</param>
/// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBody([NotNull] string body, [CanBeNull] Encoding encoding = null);
///// <summary>
///// WithBody : Create a string response based on a string.
///// </summary>
///// <param name="body">The body.</param>
///// <param name="encoding">The body encoding.</param>
///// <returns>A <see cref="IResponseBuilder"/>.</returns>
//// IResponseBuilder WithBody([NotNull] string body, [CanBeNull] Encoding encoding = null);
/// <summary>
/// The with body as Json.
/// WithBody : Create a ... response based on a string.
/// </summary>
/// <param name="body">The body.</param>
/// <param name="destination">The Body Destination format (SameAsSource, String or Bytes).</param>
/// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBody([NotNull] string body, [CanBeNull] string destination = BodyDestinationFormat.SameAsSource, [CanBeNull] Encoding encoding = null);
/// <summary>
/// WithBody : Create a ... response based on a bytearray.
/// </summary>
/// <param name="body">The body.</param>
/// <param name="destination">The Body Destination format (SameAsSource, String or Bytes).</param>
/// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBody([NotNull] byte[] body, [CanBeNull] string destination = BodyDestinationFormat.SameAsSource, [CanBeNull] Encoding encoding = null);
/// <summary>
/// WithBody : Create a string response based on a object (which will be converted to a JSON string).
/// </summary>
/// <param name="body">The body.</param>
/// <param name="encoding">The body encoding.</param>
@@ -25,11 +44,12 @@ namespace WireMock.ResponseBuilders
IResponseBuilder WithBodyAsJson([NotNull] object body, [CanBeNull] Encoding encoding = null);
/// <summary>
/// The with body as base64.
/// WithBody : Create a string response based on a Base64 string (which will be decoded to a normal string).
/// </summary>
/// <param name="bodyAsbase64">The body asbase64.</param>
/// <param name="bodyAsbase64">The body.</param>
/// <param name="encoding">The Encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBodyAsBase64([NotNull] string bodyAsbase64, [CanBeNull] Encoding encoding = null);
[Obsolete]
IResponseBuilder WithBodyFromBase64([NotNull] string bodyAsbase64, [CanBeNull] Encoding encoding = null);
}
}

View File

@@ -150,28 +150,59 @@ namespace WireMock.ResponseBuilders
return this;
}
/// <summary>
/// The with body.
/// </summary>
/// <param name="body">The body.</param>
/// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
public IResponseBuilder WithBody(string body, Encoding encoding = null)
/// <inheritdoc cref="IBodyResponseBuilder.WithBody(byte[], string, Encoding)"/>
public IResponseBuilder WithBody(byte[] body, string destination, Encoding encoding = null)
{
Check.NotNull(body, nameof(body));
ResponseMessage.Body = body;
ResponseMessage.BodyEncoding = encoding ?? Encoding.UTF8;
ResponseMessage.BodyDestination = destination;
switch (destination)
{
case BodyDestinationFormat.String:
var enc = encoding ?? Encoding.UTF8;
ResponseMessage.BodyAsBytes = null;
ResponseMessage.Body = enc.GetString(body);
ResponseMessage.BodyEncoding = enc;
break;
default:
ResponseMessage.BodyAsBytes = body;
ResponseMessage.BodyEncoding = null;
break;
}
return this;
}
/// <summary>
/// The with body (AsJson object).
/// </summary>
/// <param name="body">The body.</param>
/// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
/// <inheritdoc cref="IBodyResponseBuilder.WithBody(string, string, Encoding)"/>
public IResponseBuilder WithBody(string body, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null)
{
Check.NotNull(body, nameof(body));
encoding = encoding ?? Encoding.UTF8;
ResponseMessage.BodyDestination = destination;
switch (destination)
{
case BodyDestinationFormat.Bytes:
ResponseMessage.Body = null;
ResponseMessage.BodyAsBytes = encoding.GetBytes(body);
ResponseMessage.BodyEncoding = encoding;
break;
default:
ResponseMessage.Body = body;
ResponseMessage.BodyAsBytes = null;
ResponseMessage.BodyEncoding = encoding;
break;
}
return this;
}
/// <inheritdoc cref="IBodyResponseBuilder.WithBodyAsJson"/>
public IResponseBuilder WithBodyAsJson(object body, Encoding encoding = null)
{
Check.NotNull(body, nameof(body));
@@ -184,23 +215,20 @@ namespace WireMock.ResponseBuilders
ResponseMessage.BodyEncoding = encoding;
}
ResponseMessage.BodyDestination = null;
ResponseMessage.Body = jsonBody;
return this;
}
/// <summary>
/// The with body as base64.
/// </summary>
/// <param name="bodyAsbase64">The body asbase64.</param>
/// <param name="encoding">The Encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
public IResponseBuilder WithBodyAsBase64(string bodyAsbase64, Encoding encoding = null)
/// <inheritdoc cref="IBodyResponseBuilder.WithBodyFromBase64"/>
public IResponseBuilder WithBodyFromBase64(string bodyAsbase64, Encoding encoding = null)
{
Check.NotNull(bodyAsbase64, nameof(bodyAsbase64));
encoding = encoding ?? Encoding.UTF8;
ResponseMessage.BodyDestination = null;
ResponseMessage.Body = encoding.GetString(Convert.FromBase64String(bodyAsbase64));
ResponseMessage.BodyEncoding = encoding;

View File

@@ -24,11 +24,21 @@ namespace WireMock
/// </summary>
public string BodyOriginal { get; set; }
/// <summary>
/// Gets or sets the body destination (SameAsSource, String or Bytes).
/// </summary>
public string BodyDestination { get; set; }
/// <summary>
/// Gets or sets the body.
/// </summary>
public string Body { get; set; }
/// <summary>
/// Gets or sets the body.
/// </summary>
public byte[] BodyAsBytes { get; set; }
/// <summary>
/// Gets or sets the body encoding.
/// </summary>

View File

@@ -95,16 +95,20 @@ namespace WireMock.Serialization
{
mappingModel.Response.StatusCode = null;
mappingModel.Response.Headers = null;
mappingModel.Response.BodyDestination = null;
mappingModel.Response.Body = null;
mappingModel.Response.BodyAsBytes = null;
mappingModel.Response.UseTransformer = false;
mappingModel.Response.BodyEncoding = null;
mappingModel.Response.ProxyUrl = response.ProxyUrl;
}
else
{
mappingModel.Response.BodyDestination = response.ResponseMessage.BodyDestination;
mappingModel.Response.StatusCode = response.ResponseMessage.StatusCode;
mappingModel.Response.Headers = response.ResponseMessage.Headers;
mappingModel.Response.Body = response.ResponseMessage.Body;
mappingModel.Response.BodyAsBytes = response.ResponseMessage.BodyAsBytes;
mappingModel.Response.UseTransformer = response.UseTransformer;
mappingModel.Response.BodyEncoding = response.ResponseMessage.BodyEncoding != null
? new EncodingModel

View File

@@ -412,7 +412,9 @@ namespace WireMock.Server
Response = new LogResponseModel
{
StatusCode = logEntry.ResponseMessage.StatusCode,
BodyDestination = logEntry.ResponseMessage.BodyDestination,
Body = logEntry.ResponseMessage.Body,
BodyAsBytes = logEntry.ResponseMessage.BodyAsBytes,
BodyOriginal = logEntry.ResponseMessage.BodyOriginal,
Headers = logEntry.ResponseMessage.Headers,
BodyEncoding = logEntry.ResponseMessage.BodyEncoding != null ? new EncodingModel
@@ -612,17 +614,21 @@ namespace WireMock.Server
}
}
if (responseModel.Body != null)
if (responseModel.BodyAsBytes != null)
{
responseBuilder = responseBuilder.WithBody(responseModel.Body, ToEncoding(responseModel.BodyEncoding));
responseBuilder = responseBuilder.WithBody(responseModel.BodyAsBytes, responseModel.BodyDestination, ToEncoding(responseModel.BodyEncoding));
}
else if (responseModel.Body != null)
{
responseBuilder = responseBuilder.WithBody(responseModel.Body, responseModel.BodyDestination, ToEncoding(responseModel.BodyEncoding));
}
else if (responseModel.BodyAsJson != null)
{
responseBuilder = responseBuilder.WithBodyAsJson(responseModel.BodyAsJson, ToEncoding(responseModel.BodyEncoding));
}
else if (responseModel.BodyAsBase64 != null)
else if (responseModel.BodyFromBase64 != null)
{
responseBuilder = responseBuilder.WithBodyAsBase64(responseModel.BodyAsBase64, ToEncoding(responseModel.BodyEncoding));
responseBuilder = responseBuilder.WithBodyFromBase64(responseModel.BodyFromBase64, ToEncoding(responseModel.BodyEncoding));
}
if (responseModel.UseTransformer)

View File

@@ -162,6 +162,9 @@ namespace WireMock.Server
Urls = new[] { (settings.UseSSL == true ? "https" : "http") + "://localhost:" + port + "/" };
}
_options.PreWireMockMiddlewareInit = settings.PreWireMockMiddlewareInit;
_options.PostWireMockMiddlewareInit = settings.PostWireMockMiddlewareInit;
#if NETSTANDARD
_httpServer = new AspNetCoreSelfHost(_options, Urls);
#else

View File

@@ -1,4 +1,7 @@
namespace WireMock.Settings
using System;
using JetBrains.Annotations;
namespace WireMock.Settings
{
/// <summary>
/// FluentMockServerSettings
@@ -8,76 +11,87 @@
/// <summary>
/// Gets or sets the port.
/// </summary>
/// <value>
/// The port.
/// </value>
[PublicAPI]
public int? Port { get; set; }
/// <summary>
/// Gets or sets the use SSL.
/// </summary>
/// <value>
/// The use SSL.
/// </value>
// ReSharper disable once InconsistentNaming
[PublicAPI]
public bool? UseSSL { get; set; }
/// <summary>
/// Gets or sets the start admin interface.
/// Gets or sets wether to start admin interface.
/// </summary>
/// <value>
/// The start admin interface.
/// </value>
[PublicAPI]
public bool? StartAdminInterface { get; set; }
/// <summary>
/// Gets or sets if the static mappings should be read at startup.
/// </summary>
/// <value>true/false</value>
[PublicAPI]
public bool? ReadStaticMappings { get; set; }
/// <summary>
/// Gets or sets if the server should record and save requests and responses.
/// </summary>
/// <value>true/false</value>
[PublicAPI]
public ProxyAndRecordSettings ProxyAndRecordSettings { get; set; }
/// <summary>
/// Gets or sets the urls.
/// </summary>
/// <value>
/// The urls.
/// </value>
[PublicAPI]
public string[] Urls { get; set; }
/// <summary>
/// StartTimeout
/// </summary>
[PublicAPI]
public int StartTimeout { get; set; } = 10000;
/// <summary>
/// Allow Partial Mapping (default set to false).
/// </summary>
[PublicAPI]
public bool? AllowPartialMapping { get; set; }
/// <summary>
/// The username needed for __admin access.
/// </summary>
[PublicAPI]
public string AdminUsername { get; set; }
/// <summary>
/// The password needed for __admin access.
/// </summary>
[PublicAPI]
public string AdminPassword { get; set; }
/// <summary>
/// The RequestLog expiration in hours (optional).
/// </summary>
[PublicAPI]
public int? RequestLogExpirationDuration { get; set; }
/// <summary>
/// The MaxRequestLog count (optional).
/// </summary>
[PublicAPI]
public int? MaxRequestLogCount { get; set; }
/// <summary>
/// Action which is called (with the IAppBuilder or IApplicationBuilder) before the internal WireMockMiddleware is initialized. [Optional]
/// </summary>
[PublicAPI]
public Action<object> PreWireMockMiddlewareInit { get; set; }
/// <summary>
/// Action which is called (with the IAppBuilder or IApplicationBuilder) after the internal WireMockMiddleware is initialized. [Optional]
/// </summary>
[PublicAPI]
public Action<object> PostWireMockMiddlewareInit { get; set; }
}
}

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<Description>Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.</Description>
<AssemblyTitle>WireMock.Net</AssemblyTitle>
<Version>1.0.2.4</Version>
<Version>1.0.2.5</Version>
<Authors>Alexandre Victoor;Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

View File

@@ -1,417 +1,434 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using NFluent;
using Xunit;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
namespace WireMock.Net.Tests
{
//[TestFixture]
//[Timeout(5000)]
public class FluentMockServerTests : IDisposable
{
private FluentMockServer _server;
// For for AppVeyor + OpenCover
private string GetCurrentFolder()
{
string current = Directory.GetCurrentDirectory();
//if (!current.EndsWith("WireMock.Net.Tests"))
// return Path.Combine(current, "test", "WireMock.Net.Tests");
return current;
}
[Fact]
public void FluentMockServer_StartStop()
{
var server1 = FluentMockServer.Start("http://localhost:9091/");
server1.Stop();
var server2 = FluentMockServer.Start("http://localhost:9091/");
server2.Stop();
}
[Fact]
public void FluentMockServer_ReadStaticMapping_WithNonGuidFilename()
{
var guid = Guid.Parse("04ee4872-9efd-4770-90d3-88d445265d0d");
string title = "documentdb_root_title";
_server = FluentMockServer.Start();
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings", "documentdb_root.json");
_server.ReadStaticMapping(folder);
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(1);
Check.That(mappings.First().RequestMatcher).IsNotNull();
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(guid);
Check.That(mappings.First().Title).Equals(title);
}
[Fact]
public void FluentMockServer_ReadStaticMapping_WithGuidFilename()
{
string guid = "00000002-ee28-4f29-ae63-1ac9b0802d86";
_server = FluentMockServer.Start();
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings", guid + ".json");
_server.ReadStaticMapping(folder);
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(1);
Check.That(mappings.First().RequestMatcher).IsNotNull();
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(Guid.Parse(guid));
Check.That(mappings.First().Title).IsNullOrEmpty();
}
[Fact]
public void FluentMockServer_ReadStaticMappings()
{
_server = FluentMockServer.Start();
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings");
_server.ReadStaticMappings(folder);
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
}
[Fact]
public void FluentMockServer_Admin_Mappings_Get()
{
var guid = Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05");
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/foo1").UsingGet())
.WithGuid(guid)
.RespondWith(Response.Create().WithStatusCode(201).WithBody("1"));
_server.Given(Request.Create().WithPath("/foo2").UsingGet())
.RespondWith(Response.Create().WithStatusCode(202).WithBody("2"));
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
Check.That(mappings.First().RequestMatcher).IsNotNull();
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(guid);
Check.That(mappings[1].Guid).Not.Equals(guid);
}
[Fact]
public void FluentMockServer_Admin_Mappings_Add_SameGuid()
{
var guid = Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05");
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/1").UsingGet())
.WithGuid(guid)
.RespondWith(Response.Create().WithStatusCode(500));
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(1);
Check.That(mappings.First().Guid).Equals(guid);
_server.Given(Request.Create().WithPath("/2").UsingGet())
.WithGuid(guid)
.RespondWith(Response.Create().WithStatusCode(500));
Check.That(mappings).HasSize(1);
Check.That(mappings.First().Guid).Equals(guid);
}
[Fact]
public async Task FluentMockServer_Admin_Mappings_AtPriority()
{
_server = FluentMockServer.Start();
// given
_server.Given(Request.Create().WithPath("/1").UsingGet())
.AtPriority(2)
.RespondWith(Response.Create().WithStatusCode(200));
_server.Given(Request.Create().WithPath("/1").UsingGet())
.AtPriority(1)
.RespondWith(Response.Create().WithStatusCode(400));
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
Check.That(mappings[0].Priority).Equals(2);
Check.That(mappings[1].Priority).Equals(1);
// when
var response = await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/1");
// then
Check.That((int)response.StatusCode).IsEqualTo(400);
}
[Fact]
public async Task FluentMockServer_Admin_Requests_Get()
{
// given
_server = FluentMockServer.Start();
// when
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(_server.LogEntries).HasSize(1);
var requestLogged = _server.LogEntries.First();
Check.That(requestLogged.RequestMessage.Method).IsEqualTo("get");
Check.That(requestLogged.RequestMessage.BodyAsBytes).IsEmpty();
}
[Fact]
public async Task Should_respond_to_request()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/foo")
.UsingGet())
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithBody(@"{ msg: ""Hello world!""}"));
// when
var response = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response).IsEqualTo(@"{ msg: ""Hello world!""}");
}
[Fact]
public async Task Should_respond_to_request_bodyAsBase64()
{
// given
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/foo").UsingGet()).RespondWith(Response.Create().WithBodyAsBase64("SGVsbG8gV29ybGQ/"));
// when
var response = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response).IsEqualTo("Hello World?");
}
[Fact]
public async Task Should_respond_404_for_unexpected_request()
{
// given
_server = FluentMockServer.Start();
// when
var response = await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response.StatusCode).IsEqualTo(HttpStatusCode.NotFound);
Check.That((int)response.StatusCode).IsEqualTo(404);
}
[Fact]
public async Task Should_find_a_request_satisfying_a_request_spec()
{
// given
_server = FluentMockServer.Start();
// when
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/bar");
// then
var result = _server.FindLogEntries(Request.Create().WithPath(new RegexMatcher("^/b.*"))).ToList();
Check.That(result).HasSize(1);
var requestLogged = result.First();
Check.That(requestLogged.RequestMessage.Path).IsEqualTo("/bar");
Check.That(requestLogged.RequestMessage.Url).IsEqualTo("http://localhost:" + _server.Ports[0] + "/bar");
}
[Fact]
public async Task Should_reset_requestlogs()
{
// given
_server = FluentMockServer.Start();
// when
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
_server.ResetLogEntries();
// then
Check.That(_server.LogEntries).IsEmpty();
}
[Fact]
public void Should_reset_mappings()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/foo")
.UsingGet())
.RespondWith(Response.Create()
.WithBody(@"{ msg: ""Hello world!""}"));
// when
_server.ResetMappings();
// then
Check.That(_server.Mappings).IsEmpty();
Check.ThatAsyncCode(() => new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo"))
.ThrowsAny();
}
[Fact]
public async Task Should_respond_a_redirect_without_body()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/foo")
.UsingGet())
.RespondWith(Response.Create()
.WithStatusCode(307)
.WithHeader("Location", "/bar"));
_server
.Given(Request.Create()
.WithPath("/bar")
.UsingGet())
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithBody("REDIRECT SUCCESSFUL"));
// when
var response = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response).IsEqualTo("REDIRECT SUCCESSFUL");
}
[Fact]
public async Task Should_delay_responses_for_a_given_route()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/*"))
.RespondWith(Response.Create()
.WithBody(@"{ msg: ""Hello world!""}")
.WithDelay(TimeSpan.FromMilliseconds(200)));
// when
var watch = new Stopwatch();
watch.Start();
await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
watch.Stop();
// then
Check.That(watch.ElapsedMilliseconds).IsStrictlyGreaterThan(200);
}
[Fact]
public async Task Should_delay_responses()
{
// given
_server = FluentMockServer.Start();
_server.AddGlobalProcessingDelay(TimeSpan.FromMilliseconds(200));
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithBody(@"{ msg: ""Hello world!""}"));
// when
var watch = new Stopwatch();
watch.Start();
await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
watch.Stop();
// then
Check.That(watch.ElapsedMilliseconds).IsStrictlyGreaterThan(200);
}
[Fact]
public async Task Should_proxy_responses()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy("http://www.google.com"));
// when
var result = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/search?q=test");
// then
Check.That(result).Contains("google");
}
//Leaving commented as this requires an actual certificate with password, along with a service that expects a client certificate
//[Fact]
//public async Task Should_proxy_responses_with_client_certificate()
//{
// // given
// _server = FluentMockServer.Start();
// _server
// .Given(Request.Create().WithPath("/*"))
// .RespondWith(Response.Create().WithProxy("https://server-that-expects-a-client-certificate", @"\\yourclientcertificatecontainingprivatekey.pfx", "yourclientcertificatepassword"));
// // when
// var result = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/someurl?someQuery=someValue");
// // then
// Check.That(result).Contains("google");
//}
[Fact]
public async Task FluentMockServer_Logging_SetMaxRequestLogCount()
{
// Assign
var client = new HttpClient();
// Act
_server = FluentMockServer.Start();
_server.SetMaxRequestLogCount(2);
await client.GetAsync("http://localhost:" + _server.Ports[0] + "/foo1");
await client.GetAsync("http://localhost:" + _server.Ports[0] + "/foo2");
await client.GetAsync("http://localhost:" + _server.Ports[0] + "/foo3");
// Assert
Check.That(_server.LogEntries).HasSize(2);
var requestLoggedA = _server.LogEntries.First();
Check.That(requestLoggedA.RequestMessage.Path).EndsWith("/foo2");
var requestLoggedB = _server.LogEntries.Last();
Check.That(requestLoggedB.RequestMessage.Path).EndsWith("/foo3");
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using NFluent;
using Xunit;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
namespace WireMock.Net.Tests
{
//[TestFixture]
//[Timeout(5000)]
public class FluentMockServerTests : IDisposable
{
private FluentMockServer _server;
// For for AppVeyor + OpenCover
private string GetCurrentFolder()
{
string current = Directory.GetCurrentDirectory();
//if (!current.EndsWith("WireMock.Net.Tests"))
// return Path.Combine(current, "test", "WireMock.Net.Tests");
return current;
}
public void Dispose()
{
_server?.Stop();
}
}
[Fact]
public void FluentMockServer_StartStop()
{
var server1 = FluentMockServer.Start("http://localhost:9091/");
server1.Stop();
var server2 = FluentMockServer.Start("http://localhost:9091/");
server2.Stop();
}
[Fact]
public void FluentMockServer_ReadStaticMapping_WithNonGuidFilename()
{
var guid = Guid.Parse("04ee4872-9efd-4770-90d3-88d445265d0d");
string title = "documentdb_root_title";
_server = FluentMockServer.Start();
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings", "documentdb_root.json");
_server.ReadStaticMapping(folder);
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(1);
Check.That(mappings.First().RequestMatcher).IsNotNull();
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(guid);
Check.That(mappings.First().Title).Equals(title);
}
[Fact]
public void FluentMockServer_ReadStaticMapping_WithGuidFilename()
{
string guid = "00000002-ee28-4f29-ae63-1ac9b0802d86";
_server = FluentMockServer.Start();
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings", guid + ".json");
_server.ReadStaticMapping(folder);
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(1);
Check.That(mappings.First().RequestMatcher).IsNotNull();
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(Guid.Parse(guid));
Check.That(mappings.First().Title).IsNullOrEmpty();
}
[Fact]
public void FluentMockServer_ReadStaticMappings()
{
_server = FluentMockServer.Start();
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings");
_server.ReadStaticMappings(folder);
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
}
[Fact]
public void FluentMockServer_Admin_Mappings_Get()
{
var guid = Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05");
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/foo1").UsingGet())
.WithGuid(guid)
.RespondWith(Response.Create().WithStatusCode(201).WithBody("1"));
_server.Given(Request.Create().WithPath("/foo2").UsingGet())
.RespondWith(Response.Create().WithStatusCode(202).WithBody("2"));
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
Check.That(mappings.First().RequestMatcher).IsNotNull();
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(guid);
Check.That(mappings[1].Guid).Not.Equals(guid);
}
[Fact]
public void FluentMockServer_Admin_Mappings_Add_SameGuid()
{
var guid = Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05");
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/1").UsingGet())
.WithGuid(guid)
.RespondWith(Response.Create().WithStatusCode(500));
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(1);
Check.That(mappings.First().Guid).Equals(guid);
_server.Given(Request.Create().WithPath("/2").UsingGet())
.WithGuid(guid)
.RespondWith(Response.Create().WithStatusCode(500));
Check.That(mappings).HasSize(1);
Check.That(mappings.First().Guid).Equals(guid);
}
[Fact]
public async Task FluentMockServer_Admin_Mappings_AtPriority()
{
_server = FluentMockServer.Start();
// given
_server.Given(Request.Create().WithPath("/1").UsingGet())
.AtPriority(2)
.RespondWith(Response.Create().WithStatusCode(200));
_server.Given(Request.Create().WithPath("/1").UsingGet())
.AtPriority(1)
.RespondWith(Response.Create().WithStatusCode(400));
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
Check.That(mappings[0].Priority).Equals(2);
Check.That(mappings[1].Priority).Equals(1);
// when
var response = await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/1");
// then
Check.That((int)response.StatusCode).IsEqualTo(400);
}
[Fact]
public async Task FluentMockServer_Admin_Requests_Get()
{
// given
_server = FluentMockServer.Start();
// when
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(_server.LogEntries).HasSize(1);
var requestLogged = _server.LogEntries.First();
Check.That(requestLogged.RequestMessage.Method).IsEqualTo("get");
Check.That(requestLogged.RequestMessage.BodyAsBytes).IsNull();
}
[Fact]
public async Task Should_respond_to_request_bodyAsString()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/foo")
.UsingGet())
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithBody("Hello world!"));
// when
var response = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response).IsEqualTo("Hello world!");
}
[Fact]
public async Task Should_respond_to_request_bodyAsBase64()
{
// given
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/foo").UsingGet()).RespondWith(Response.Create().WithBodyFromBase64("SGVsbG8gV29ybGQ/"));
// when
var response = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response).IsEqualTo("Hello World?");
}
[Fact]
public async Task Should_respond_to_request_bodyAsBytes()
{
// given
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/foo").UsingGet()).RespondWith(Response.Create().WithBody(new byte[] { 48, 49 }));
// when
var responseAsString = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
var responseAsBytes = await new HttpClient().GetByteArrayAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(responseAsString).IsEqualTo("01");
Check.That(responseAsBytes).ContainsExactly(new byte[] { 48, 49 });
}
[Fact]
public async Task Should_respond_404_for_unexpected_request()
{
// given
_server = FluentMockServer.Start();
// when
var response = await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response.StatusCode).IsEqualTo(HttpStatusCode.NotFound);
Check.That((int)response.StatusCode).IsEqualTo(404);
}
[Fact]
public async Task Should_find_a_request_satisfying_a_request_spec()
{
// given
_server = FluentMockServer.Start();
// when
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/bar");
// then
var result = _server.FindLogEntries(Request.Create().WithPath(new RegexMatcher("^/b.*"))).ToList();
Check.That(result).HasSize(1);
var requestLogged = result.First();
Check.That(requestLogged.RequestMessage.Path).IsEqualTo("/bar");
Check.That(requestLogged.RequestMessage.Url).IsEqualTo("http://localhost:" + _server.Ports[0] + "/bar");
}
[Fact]
public async Task Should_reset_requestlogs()
{
// given
_server = FluentMockServer.Start();
// when
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
_server.ResetLogEntries();
// then
Check.That(_server.LogEntries).IsEmpty();
}
[Fact]
public void Should_reset_mappings()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/foo")
.UsingGet())
.RespondWith(Response.Create()
.WithBody(@"{ msg: ""Hello world!""}"));
// when
_server.ResetMappings();
// then
Check.That(_server.Mappings).IsEmpty();
Check.ThatAsyncCode(() => new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo"))
.ThrowsAny();
}
[Fact]
public async Task Should_respond_a_redirect_without_body()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/foo")
.UsingGet())
.RespondWith(Response.Create()
.WithStatusCode(307)
.WithHeader("Location", "/bar"));
_server
.Given(Request.Create()
.WithPath("/bar")
.UsingGet())
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithBody("REDIRECT SUCCESSFUL"));
// when
var response = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response).IsEqualTo("REDIRECT SUCCESSFUL");
}
[Fact]
public async Task Should_delay_responses_for_a_given_route()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/*"))
.RespondWith(Response.Create()
.WithBody(@"{ msg: ""Hello world!""}")
.WithDelay(TimeSpan.FromMilliseconds(200)));
// when
var watch = new Stopwatch();
watch.Start();
await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
watch.Stop();
// then
Check.That(watch.ElapsedMilliseconds).IsStrictlyGreaterThan(200);
}
[Fact]
public async Task Should_delay_responses()
{
// given
_server = FluentMockServer.Start();
_server.AddGlobalProcessingDelay(TimeSpan.FromMilliseconds(200));
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithBody(@"{ msg: ""Hello world!""}"));
// when
var watch = new Stopwatch();
watch.Start();
await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
watch.Stop();
// then
Check.That(watch.ElapsedMilliseconds).IsStrictlyGreaterThan(200);
}
[Fact]
public async Task Should_proxy_responses()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy("http://www.google.com"));
// when
var result = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/search?q=test");
// then
Check.That(result).Contains("google");
}
//Leaving commented as this requires an actual certificate with password, along with a service that expects a client certificate
//[Fact]
//public async Task Should_proxy_responses_with_client_certificate()
//{
// // given
// _server = FluentMockServer.Start();
// _server
// .Given(Request.Create().WithPath("/*"))
// .RespondWith(Response.Create().WithProxy("https://server-that-expects-a-client-certificate", @"\\yourclientcertificatecontainingprivatekey.pfx", "yourclientcertificatepassword"));
// // when
// var result = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/someurl?someQuery=someValue");
// // then
// Check.That(result).Contains("google");
//}
[Fact]
public async Task FluentMockServer_Logging_SetMaxRequestLogCount()
{
// Assign
var client = new HttpClient();
// Act
_server = FluentMockServer.Start();
_server.SetMaxRequestLogCount(2);
await client.GetAsync("http://localhost:" + _server.Ports[0] + "/foo1");
await client.GetAsync("http://localhost:" + _server.Ports[0] + "/foo2");
await client.GetAsync("http://localhost:" + _server.Ports[0] + "/foo3");
// Assert
Check.That(_server.LogEntries).HasSize(2);
var requestLoggedA = _server.LogEntries.First();
Check.That(requestLoggedA.RequestMessage.Path).EndsWith("/foo2");
var requestLoggedB = _server.LogEntries.Last();
Check.That(requestLoggedB.RequestMessage.Path).EndsWith("/foo3");
}
public void Dispose()
{
_server?.Stop();
}
}
}

View File

@@ -70,14 +70,52 @@ namespace WireMock.Net.Tests
}
[Fact]
public async Task Response_ProvideResponse_Encoding_Body()
public async Task Response_ProvideResponse_WithBody_Bytes_Encoding_Destination_String()
{
// given
string bodyAsString = "abc";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", clientIP, body, bodyAsString, Encoding.UTF8);
var response = Response.Create().WithBody("test", Encoding.ASCII);
var response = Response.Create().WithBody(new byte[] { 48, 49 }, BodyDestinationFormat.String, Encoding.ASCII);
// act
var responseMessage = await response.ProvideResponseAsync(request);
// then
Check.That(responseMessage.Body).Equals("01");
Check.That(responseMessage.BodyAsBytes).IsNull();
Check.That(responseMessage.BodyEncoding).Equals(Encoding.ASCII);
}
[Fact]
public async Task Response_ProvideResponse_WithBody_Bytes_Encoding_Destination_Bytes()
{
// given
string bodyAsString = "abc";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", clientIP, body, bodyAsString, Encoding.UTF8);
var response = Response.Create().WithBody(new byte[] { 48, 49 }, BodyDestinationFormat.SameAsSource, Encoding.ASCII);
// act
var responseMessage = await response.ProvideResponseAsync(request);
// then
Check.That(responseMessage.BodyAsBytes).ContainsExactly(new byte[] { 48, 49 });
Check.That(responseMessage.Body).IsNull();
Check.That(responseMessage.BodyEncoding).IsNull();
}
[Fact]
public async Task Response_ProvideResponse_WithBody_String_Encoding()
{
// given
string bodyAsString = "abc";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", clientIP, body, bodyAsString, Encoding.UTF8);
var response = Response.Create().WithBody("test", null, Encoding.ASCII);
// act
var responseMessage = await response.ProvideResponseAsync(request);
@@ -88,7 +126,7 @@ namespace WireMock.Net.Tests
}
[Fact]
public async Task Response_ProvideResponse_Encoding_JsonBody()
public async Task Response_ProvideResponse_WithBody_Object_Encoding()
{
// given
string bodyAsString = "abc";