Compare commits

...

7 Commits

Author SHA1 Message Date
Stef Heyenrath
ad6c59e3b5 1.0.3.3 2018-02-24 09:04:21 +01:00
Stef Heyenrath
0c25b2e9f2 Json fixes (#91) (#92)
* Fixes for JsonPath

* More tests

* Fixes + added tests
2018-02-23 12:29:43 +00:00
Stef Heyenrath
1ffd56701c fix unit-test 2018-02-14 20:38:19 +01:00
Stef Heyenrath
4f87146622 1.0.3.2 2018-02-14 19:35:51 +01:00
Stef Heyenrath
693778659e Concurrent issue (#88) (#90)
* concurrent

* uni tests
2018-02-14 18:30:06 +00:00
Stef Heyenrath
51070dab63 1.0.3.1 releasenotes 2018-02-14 17:17:05 +01:00
Stef Heyenrath
e21582aacf Add log4net logging (#89)
* logging + fixed proxy isses

* Add more logging

* comments

* 1.0.3.1
2018-02-14 16:13:05 +00:00
63 changed files with 958 additions and 454 deletions

View File

@@ -1,3 +1,21 @@
# 1.0.3.2 (14 February 2018)
- [#90](https://github.com/WireMock-Net/WireMock.Net/pull/90) - Concurrent issue (#88) contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#89](https://github.com/WireMock-Net/WireMock.Net/pull/89) - Add log4net logging contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#88](https://github.com/WireMock-Net/WireMock.Net/issues/88) - Bug: Standalone server throws 500 error when receiving concurrent requests +fix
- [#87](https://github.com/WireMock-Net/WireMock.Net/issues/87) - Feature: Add logging
Commits: 51070dab63...693778659e
# 1.0.3.1 (14 February 2018)
- [#89](https://github.com/WireMock-Net/WireMock.Net/pull/89) - Add log4net logging contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#87](https://github.com/WireMock-Net/WireMock.Net/issues/87) - Feature: Add logging
Commits: ...
# 1.0.3 (04 February 2018)
- [#86](https://github.com/WireMock-Net/WireMock.Net/issues/86) - Feature : Add FileSystemWatcher logic for watching static mapping files +feature

View File

@@ -1,5 +1,5 @@
https://github.com/GitTools/GitReleaseNotes
GitReleaseNotes.exe . /OutputFile CHANGELOG.md /Version 1.0.3
GitReleaseNotes.exe . /OutputFile CHANGELOG.md /Version 1.0.3.2
GitReleaseNotes.exe . /OutputFile CHANGELOG.md /allTags

View File

@@ -1,11 +1,21 @@
using WireMock.Net.ConsoleApplication;
using System.IO;
using System.Reflection;
using log4net;
using log4net.Config;
using log4net.Repository;
using WireMock.Net.ConsoleApplication;
namespace WireMock.Net.Console.NETCoreApp
{
static class Program
{
private static readonly ILoggerRepository LogRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
static void Main(params string[] args)
{
XmlConfigurator.Configure(LogRepository, new FileInfo("log4net.config"));
MainApp.Run();
}
}

View File

@@ -22,10 +22,17 @@
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
<PackageReference Include="log4net" Version="2.0.8" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<None Update="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="nlog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\791a3f31-6946-4ce7-8e6f-0237c7443275.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
</configSections>
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger{1} - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
</configuration>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="info"
internalLogFile="c:\temp\wiremock-internal-nlog.log">
<targets>
<!-- write logs to file -->
<target xsi:type="File" name="all" fileName="c:\temp\wiremock-${shortdate}.log"
layout="${longdate}|${event-properties:item=EventId.Id}|${uppercase:${level}}|${logger}|${message} ${exception}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="*" minlevel="Debug" writeTo="all" />
</rules>
</nlog>

View File

@@ -41,6 +41,15 @@ namespace WireMock.Net.ConsoleApplication
// .RespondWith(Response.Create()
// .WithProxy("http://restcountries.eu"));
server
.Given(Request
.Create()
.WithPath("/jsonthings")
.WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]"))
.UsingPut())
.RespondWith(Response.Create()
.WithBody(@"{ ""result"": ""JsonPathMatcher !!!""}"));
server
.Given(Request
.Create()
@@ -54,8 +63,9 @@ namespace WireMock.Net.ConsoleApplication
.Given(Request.Create().WithPath("/headers", "/headers_test").UsingPost().WithHeader("Content-Type", "application/json*"))
.RespondWith(Response.Create()
.WithStatusCode(201)
.WithHeader("MyHeader", "application/json", "application/json2")
.WithBody(@"{ ""result"": ""data posted with 201""}"));
//.WithHeader("MyHeader", "application/json", "application/json2")
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson(new { result = "data:headers posted with 201" }));
server
.Given(Request.Create().WithPath("/file").UsingGet())
@@ -117,7 +127,7 @@ namespace WireMock.Net.ConsoleApplication
.RespondWith(Response.Create()
.WithStatusCode(201)
.WithHeader("Content-Type", "application/json")
.WithBody(@"{ ""result"": ""data posted with FUNC 201""}"));
.WithBodyAsJson(new { result = "data posted with FUNC 201" }));
server
.Given(Request.Create().WithPath("/json").UsingPost().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]")))

View File

@@ -1,9 +1,14 @@
namespace WireMock.Net.ConsoleApplication
using System.IO;
using log4net.Config;
namespace WireMock.Net.ConsoleApplication
{
static class Program
{
static void Main(params string[] args)
{
XmlConfigurator.Configure(new FileInfo("log4net.config"));
MainApp.Run();
}
}

View File

@@ -36,17 +36,22 @@
<ApplicationIcon>..\..\WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\..\packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Owin.Host.HttpListener, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Owin.Host.HttpListener.3.1.0\lib\net45\Microsoft.Owin.Host.HttpListener.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SimMetrics.Net, Version=1.0.3.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\SimMetrics.Net.1.0.3\lib\net45\SimMetrics.Net.dll</HintPath>
<Reference Include="SimMetrics.Net, Version=1.0.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\SimMetrics.Net.1.0.4\lib\net45\SimMetrics.Net.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.XML" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainApp.cs" />
@@ -57,6 +62,9 @@
<None Include="App.config">
<SubType>Designer</SubType>
</None>
<None Include="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="packages.config">
<SubType>Designer</SubType>
</None>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
</configSections>
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger{1} - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
</configuration>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.8" targetFramework="net452" />
<package id="Microsoft.Owin.Host.HttpListener" version="3.1.0" targetFramework="net452" />
<package id="Newtonsoft.Json" version="10.0.2" targetFramework="net452" />
<package id="SimMetrics.Net" version="1.0.3" targetFramework="net452" />
<package id="SimMetrics.Net" version="1.0.4" targetFramework="net452" />
</packages>

View File

@@ -1,16 +1,26 @@
using System;
using System.IO;
using System.Reflection;
using System.Threading;
using log4net;
using log4net.Config;
using log4net.Repository;
using WireMock.Server;
namespace WireMock.Net.StandAlone.NETCoreApp
{
class Program
static class Program
{
private static readonly ILoggerRepository LogRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
// private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
private static int sleepTime = 30000;
private static FluentMockServer _server;
static void Main(string[] args)
{
XmlConfigurator.Configure(LogRepository, new FileInfo("log4net.config"));
_server = StandAloneApp.Start(args);
Console.WriteLine($"{DateTime.UtcNow} Press Ctrl+C to shut down");

View File

@@ -6,8 +6,18 @@
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="log4net" Version="2.0.8" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
</configSections>
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger{1} - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
</configuration>

View File

@@ -1,4 +1,6 @@
using System;
using System.IO;
using log4net.Config;
namespace WireMock.Net.StandAlone.Net452
{
@@ -6,6 +8,8 @@ namespace WireMock.Net.StandAlone.Net452
{
static void Main(params string[] args)
{
XmlConfigurator.Configure(new FileInfo("log4net.config"));
StandAloneApp.Start(args);
Console.WriteLine("Press any key to stop the server");

View File

@@ -39,6 +39,9 @@
<StartupObject>WireMock.Net.StandAlone.Net452.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\..\packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Numerics" />
@@ -50,6 +53,9 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
</configSections>
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger{1} - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
</configuration>

View File

@@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.8" targetFramework="net452" />
</packages>

View File

@@ -1,10 +1,9 @@
using System;
using System.Linq;
using System.Linq;
using WireMock.Server;
using WireMock.Settings;
using WireMock.Validation;
using JetBrains.Annotations;
using Newtonsoft.Json;
using log4net;
namespace WireMock.Net.StandAlone
{
@@ -13,8 +12,10 @@ namespace WireMock.Net.StandAlone
/// </summary>
public static class StandAloneApp
{
private static readonly ILog Log = LogManager.GetLogger(typeof(StandAloneApp));
/// <summary>
/// Start WireMock.Net standalone based on the FluentMockServerSettings.
/// Start WireMock.Net standalone Server based on the FluentMockServerSettings.
/// </summary>
/// <param name="settings">The FluentMockServerSettings</param>
[PublicAPI]
@@ -26,7 +27,7 @@ namespace WireMock.Net.StandAlone
}
/// <summary>
/// Start WireMock.Net standalone based on the commandline arguments.
/// Start WireMock.Net standalone Server based on the commandline arguments.
/// </summary>
/// <param name="args">The commandline arguments</param>
[PublicAPI]
@@ -34,7 +35,7 @@ namespace WireMock.Net.StandAlone
{
Check.NotNull(args, nameof(args));
Console.WriteLine("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
Log.DebugFormat("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
var parser = new SimpleCommandLineParser();
parser.Parse(args);
@@ -73,11 +74,9 @@ namespace WireMock.Net.StandAlone
};
}
Console.WriteLine("WireMock.Net server settings {0}", JsonConvert.SerializeObject(settings, Formatting.Indented));
FluentMockServer server = Start(settings);
Console.WriteLine("WireMock.Net server listening at {0}", string.Join(",", server.Urls));
Log.InfoFormat("WireMock.Net server listening at {0}", string.Join(",", server.Urls));
return server;
}

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<Description>Lightweight StandAlone Http Mocking Server for .Net.</Description>
<AssemblyTitle>WireMock.Net.StandAlone</AssemblyTitle>
<Version>1.0.3</Version>
<Version>1.0.3.3</Version>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -36,10 +36,7 @@
<PackageReference Include="JetBrains.Annotations" Version="10.4.0">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<!-- <PackageReference Include="CommandLineArgumentsParser" Version="3.0.16" /> -->
<!-- <PackageReference Include="Marsonsoft.CommandLineParser" Version="1.0.34" /> -->
<!-- <PackageReference Include="BurnSystems.CommandLine" Version="1.1.0" /> -->
<!-- <ProjectReference Include="..\..\..\CommandLineParser\src\CommandLineArgumentsParser\CommandLineArgumentsParser.csproj" /> -->
<PackageReference Include="log4net" Version="2.0.8" />
</ItemGroup>
<ItemGroup>

View File

@@ -8,51 +8,33 @@ namespace WireMock.Admin.Requests
public class LogEntryModel
{
/// <summary>
/// Gets or sets the unique identifier.
/// </summary>
/// <value>
/// The unique identifier.
/// </value>
/// </summary>
public Guid Guid { get; set; }
/// <summary>
/// Gets or sets the request.
/// </summary>
/// <value>
/// The request.
/// </value>
/// </summary>
public LogRequestModel Request { get; set; }
/// <summary>
/// Gets or sets the response.
/// </summary>
/// <value>
/// The response.
/// </value>
/// </summary>
public LogResponseModel Response { get; set; }
/// <summary>
/// Gets or sets the mapping unique identifier.
/// </summary>
/// <value>
/// The mapping unique identifier.
/// </value>
/// </summary>
public Guid? MappingGuid { get; set; }
/// <summary>
/// Gets or sets the mapping unique title.
/// </summary>
/// <value>
/// The mapping unique title.
/// </value>
/// </summary>
public string MappingTitle { get; set; }
/// <summary>
/// Gets or sets the request match result.
/// </summary>
/// <value>
/// The request match result.
/// </value>
/// </summary>
public LogRequestMatchModel RequestMatchResult { get; set; }
}
}

View File

@@ -11,52 +11,62 @@ namespace WireMock.Admin.Requests
public class LogRequestModel
{
/// <summary>
/// Gets the Client IP Address.
/// The Client IP Address.
/// </summary>
public string ClientIP { get; set; }
/// <summary>
/// Gets the DateTime.
/// The DateTime.
/// </summary>
public DateTime DateTime { get; set; }
/// <summary>
/// Gets or sets the Path.
/// The Path.
/// </summary>
public string Path { get; set; }
/// <summary>
/// Gets or sets the absolete URL.
///The absolete URL.
/// </summary>
public string AbsoluteUrl { get; set; }
/// <summary>
/// Gets the query.
/// The query.
/// </summary>
public IDictionary<string, WireMockList<string>> Query { get; set; }
/// <summary>
/// Gets or sets the method.
/// The method.
/// </summary>
public string Method { get; set; }
/// <summary>
/// Gets or sets the Headers.
/// The Headers.
/// </summary>
public IDictionary<string, WireMockList<string>> Headers { get; set; }
/// <summary>
/// Gets or sets the Cookies.
/// Tthe Cookies.
/// </summary>
public IDictionary<string, string> Cookies { get; set; }
/// <summary>
/// Gets or sets the body.
/// The body (as string).
/// </summary>
public string Body { get; set; }
/// <summary>
/// Gets or sets the body encoding.
/// The body (as JSON object).
/// </summary>
public object BodyAsJson { get; set; }
/// <summary>
/// The body (as bytearray).
/// </summary>
public byte[] BodyAsBytes { get; set; }
/// <summary>
/// The body encoding.
/// </summary>
public EncodingModel BodyEncoding { get; set; }
}

View File

@@ -25,12 +25,17 @@ namespace WireMock.Admin.Requests
public string BodyDestination { get; set; }
/// <summary>
/// Gets or sets the body.
/// The body (as string).
/// </summary>
public string Body { get; set; }
/// <summary>
/// Gets or sets the body as bytes.
/// The body (as JSON object).
/// </summary>
public object BodyAsJson { get; set; }
/// <summary>
/// The body (as bytearray).
/// </summary>
public byte[] BodyAsBytes { get; set; }

View File

@@ -4,8 +4,10 @@ using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
using WireMock.HttpsCertificate;
using WireMock.Util;
using WireMock.Validation;
namespace WireMock.Http
@@ -51,20 +53,36 @@ namespace WireMock.Http
return client;
}
public static async Task<ResponseMessage> SendAsync(HttpClient client, RequestMessage requestMessage, string url)
public static async Task<ResponseMessage> SendAsync([NotNull] HttpClient client, [NotNull] RequestMessage requestMessage, string url)
{
Check.NotNull(client, nameof(client));
Check.NotNull(requestMessage, nameof(requestMessage));
var originalUri = new Uri(requestMessage.Url);
var requiredUri = new Uri(url);
var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url);
WireMockList<string> contentTypeHeader = null;
bool contentTypeHeaderPresent = requestMessage.Headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase));
if (contentTypeHeaderPresent)
{
contentTypeHeader = requestMessage.Headers[HttpKnownHeaderNames.ContentType];
}
// Set Body if present
if (requestMessage.BodyAsBytes != null)
{
httpRequestMessage.Content = new ByteArrayContent(requestMessage.BodyAsBytes);
}
else if (requestMessage.BodyAsJson != null)
{
httpRequestMessage.Content = new StringContent(JsonConvert.SerializeObject(requestMessage.BodyAsJson), requestMessage.BodyEncoding);
}
else if (requestMessage.Body != null)
{
httpRequestMessage.Content = new StringContent(requestMessage.Body, requestMessage.BodyEncoding);
}
// Overwrite the host header
httpRequestMessage.Headers.Host = requiredUri.Authority;
@@ -90,10 +108,13 @@ namespace WireMock.Http
// Set both content and response headers, replacing URLs in values
var headers = (httpResponseMessage.Content?.Headers.Union(httpResponseMessage.Headers) ?? Enumerable.Empty<KeyValuePair<string, IEnumerable<string>>>()).ToArray();
var contentTypeHeader = headers.FirstOrDefault(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase));
if (httpResponseMessage.Content != null)
{
SetBody(httpResponseMessage.Content, contentTypeHeader, responseMessage);
var stream = await httpResponseMessage.Content.ReadAsStreamAsync();
var body = await BodyParser.Parse(stream, contentTypeHeader?.FirstOrDefault());
responseMessage.Body = body.BodyAsString;
responseMessage.BodyAsJson = body.BodyAsJson;
responseMessage.BodyAsBytes = body.BodyAsBytes;
}
foreach (var header in headers)
@@ -115,41 +136,5 @@ namespace WireMock.Http
return responseMessage;
}
private static async void SetBody(HttpContent content, KeyValuePair<string, IEnumerable<string>> contentTypeHeader, ResponseMessage responseMessage)
{
bool contentTypeIsDefault = contentTypeHeader.Equals(default(KeyValuePair<string, IEnumerable<string>>));
string[] textContentTypes = { "text/", "application/xml", "application/javascript", "application/typescript", "application/xhtml+xml" };
if (!contentTypeIsDefault && contentTypeHeader.Value.Any(value => textContentTypes.Any(t => value != null && value.StartsWith(t, StringComparison.OrdinalIgnoreCase))))
{
try
{
responseMessage.Body = await content.ReadAsStringAsync();
}
catch
{
// Reading as string failed, just get the ByteArray.
responseMessage.BodyAsBytes = await content.ReadAsByteArrayAsync();
}
}
else if (!contentTypeIsDefault && contentTypeHeader.Value.Any(value => value != null && value.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)))
{
string stringContent = await content.ReadAsStringAsync();
try
{
responseMessage.BodyAsJson = JsonConvert.DeserializeObject(stringContent, new JsonSerializerSettings { Formatting = Formatting.Indented });
}
catch
{
// JsonConvert failed, just set the Body as string.
responseMessage.Body = stringContent;
}
}
else
{
responseMessage.BodyAsBytes = await content.ReadAsByteArrayAsync();
}
}
}
}

View File

@@ -7,8 +7,8 @@ namespace WireMock.Matchers
/// <summary>
/// ExactMatcher
/// </summary>
/// <seealso cref="IMatcher" />
public class ExactMatcher : IMatcher
/// <seealso cref="IStringMatcher" />
public class ExactMatcher : IStringMatcher
{
private readonly string[] _values;
@@ -23,29 +23,19 @@ namespace WireMock.Matchers
_values = values;
}
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
{
return MatchScores.ToScore(_values.Select(value => value.Equals(input)));
}
/// <summary>
/// Gets the value.
/// </summary>
/// <returns>Patterns</returns>
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public string[] GetPatterns()
{
return _values;
}
/// <summary>
/// Gets the name.
/// </summary>
/// <returns>Name</returns>
/// <inheritdoc cref="IMatcher.GetName"/>
public string GetName()
{
return "ExactMatcher";

View File

@@ -0,0 +1,46 @@
using System.Linq;
using JetBrains.Annotations;
namespace WireMock.Matchers
{
/// <summary>
/// ExactMatcher
/// </summary>
/// <seealso cref="IObjectMatcher" />
public class ExactObjectMatcher : IObjectMatcher
{
private readonly object _object;
private readonly byte[] _bytes;
/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher([NotNull] object value)
{
_object = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher([NotNull] byte[] value)
{
_bytes = value;
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input)
{
bool equals = _object != null ? Equals(_object, input) : _bytes.SequenceEqual((byte[])input);
return MatchScores.ToScore(equals);
}
/// <inheritdoc cref="IMatcher.GetName"/>
public string GetName()
{
return "ExactObjectMatcher";
}
}
}

View File

@@ -5,19 +5,6 @@
/// </summary>
public interface IMatcher
{
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
double IsMatch(string input);
/// <summary>
/// Gets the patterns.
/// </summary>
/// <returns>Patterns</returns>
string[] GetPatterns();
/// <summary>
/// Gets the name.
/// </summary>

View File

@@ -0,0 +1,15 @@
namespace WireMock.Matchers
{
/// <summary>
/// IObjectMatcher
/// </summary>
public interface IObjectMatcher : IMatcher
{
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
double IsMatch(object input);
}
}

View File

@@ -0,0 +1,21 @@
namespace WireMock.Matchers
{
/// <summary>
/// IStringMatcher
/// </summary>
public interface IStringMatcher : IMatcher
{
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
double IsMatch(string input);
/// <summary>
/// Gets the patterns.
/// </summary>
/// <returns>Patterns</returns>
string[] GetPatterns();
}
}

View File

@@ -10,8 +10,9 @@ namespace WireMock.Matchers
/// JSONPathMatcher
/// </summary>
/// <seealso cref="IMatcher" />
public class JsonPathMatcher : IMatcher
public class JsonPathMatcher : IStringMatcher, IObjectMatcher
{
// private readonly object _jsonPattern;
private readonly string[] _patterns;
/// <summary>
@@ -25,15 +26,20 @@ namespace WireMock.Matchers
_patterns = patterns;
}
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input string</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
//public JsonPathMatcher([NotNull] object jsonPattern)
//{
// Check.NotNull(jsonPattern, nameof(jsonPattern));
// _jsonPattern = jsonPattern;
//}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
{
if (input == null)
{
return MatchScores.Mismatch;
}
try
{
@@ -47,19 +53,33 @@ namespace WireMock.Matchers
}
}
/// <summary>
/// Gets the patterns.
/// </summary>
/// <returns>Pattern</returns>
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input)
{
if (input == null)
{
return MatchScores.Mismatch;
}
try
{
var o = input as JObject ?? JObject.FromObject(input);
return MatchScores.ToScore(_patterns.Select(p => o.SelectToken(p) != null));
}
catch (Exception)
{
return MatchScores.Mismatch;
}
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public string[] GetPatterns()
{
return _patterns;
}
/// <summary>
/// Gets the name.
/// </summary>
/// <returns>Name</returns>
/// <inheritdoc cref="IMatcher.GetName"/>
public string GetName()
{
return "JsonPathMatcher";

View File

@@ -9,8 +9,8 @@ namespace WireMock.Matchers
/// <summary>
/// Regular Expression Matcher
/// </summary>
/// <seealso cref="IMatcher" />
public class RegexMatcher : IMatcher
/// <seealso cref="IStringMatcher" />
public class RegexMatcher : IStringMatcher
{
private readonly string[] _patterns;
private readonly Regex[] _expressions;
@@ -37,20 +37,20 @@ namespace WireMock.Matchers
RegexOptions options = RegexOptions.Compiled;
if (ignoreCase)
{
options |= RegexOptions.IgnoreCase;
}
_expressions = patterns.Select(p => new Regex(p, options)).ToArray();
}
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input string</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
{
if (input == null)
{
return MatchScores.Mismatch;
}
try
{
@@ -62,21 +62,13 @@ namespace WireMock.Matchers
}
}
/// <summary>
/// Gets the patterns.
/// </summary>
/// <returns>Pattern</returns>
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public virtual string[] GetPatterns()
{
return _patterns;
}
/// <summary>
/// Gets the name.
/// </summary>
/// <returns>
/// Name
/// </returns>
/// <inheritdoc cref="IMatcher.GetName"/>
public virtual string GetName()
{
return "RegexMatcher";

View File

@@ -9,21 +9,21 @@ namespace WireMock.Matchers.Request
/// </summary>
public class RequestMessageBodyMatcher : IRequestMatcher
{
/// <summary>
/// The body as byte[].
/// </summary>
private readonly byte[] _bodyData;
/// <summary>
/// The body function
/// </summary>
public Func<string, bool> Func { get; }
/// <summary>
/// The body data function
/// The body data function for byte[]
/// </summary>
public Func<byte[], bool> DataFunc { get; }
/// <summary>
/// The body data function for json
/// </summary>
public Func<object, bool> JsonFunc { get; }
/// <summary>
/// The matcher.
/// </summary>
@@ -32,9 +32,7 @@ namespace WireMock.Matchers.Request
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="body">
/// The body Regex pattern.
/// </param>
/// <param name="body">The body.</param>
public RequestMessageBodyMatcher([NotNull] string body) : this(new SimMetricsMatcher(body))
{
}
@@ -42,21 +40,23 @@ namespace WireMock.Matchers.Request
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="body">
/// The body Regex pattern.
/// </param>
public RequestMessageBodyMatcher([NotNull] byte[] body)
/// <param name="body">The body.</param>
public RequestMessageBodyMatcher([NotNull] byte[] body) : this(new ExactObjectMatcher(body))
{
Check.NotNull(body, nameof(body));
_bodyData = body;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">
/// The body func.
/// </param>
/// <param name="body">The body.</param>
public RequestMessageBodyMatcher([NotNull] object body) : this(new ExactObjectMatcher(body))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher([NotNull] Func<string, bool> func)
{
Check.NotNull(func, nameof(func));
@@ -66,9 +66,7 @@ namespace WireMock.Matchers.Request
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">
/// The body func.
/// </param>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher([NotNull] Func<byte[], bool> func)
{
Check.NotNull(func, nameof(func));
@@ -78,23 +76,24 @@ namespace WireMock.Matchers.Request
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="matcher">
/// The body matcher.
/// </param>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher([NotNull] Func<object, bool> func)
{
Check.NotNull(func, nameof(func));
JsonFunc = func;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="matcher">The matcher.</param>
public RequestMessageBodyMatcher([NotNull] IMatcher matcher)
{
Check.NotNull(matcher, nameof(matcher));
Matcher = matcher;
}
/// <summary>
/// Determines whether the specified RequestMessage is match.
/// </summary>
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
/// <see cref="IRequestMatcher.GetMatchingScore"/>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
@@ -103,17 +102,43 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage)
{
if (Matcher != null)
return Matcher.IsMatch(requestMessage.Body);
if (requestMessage.Body != null)
{
var stringMatcher = Matcher as IStringMatcher;
if (stringMatcher != null)
{
return stringMatcher.IsMatch(requestMessage.Body);
}
}
if (_bodyData != null)
return MatchScores.ToScore(requestMessage.BodyAsBytes == _bodyData);
var objectMatcher = Matcher as IObjectMatcher;
if (objectMatcher != null)
{
if (requestMessage.BodyAsJson != null)
{
return objectMatcher.IsMatch(requestMessage.BodyAsJson);
}
if (requestMessage.BodyAsBytes != null)
{
return objectMatcher.IsMatch(requestMessage.BodyAsBytes);
}
}
if (Func != null)
{
return MatchScores.ToScore(requestMessage.Body != null && Func(requestMessage.Body));
}
if (DataFunc != null && requestMessage.BodyAsBytes != null)
if (DataFunc != null)
{
return MatchScores.ToScore(requestMessage.BodyAsBytes != null && DataFunc(requestMessage.BodyAsBytes));
}
if (JsonFunc != null)
{
return MatchScores.ToScore(requestMessage.BodyAsJson != null && JsonFunc(requestMessage.BodyAsJson));
}
return MatchScores.Mismatch;
}

View File

@@ -14,7 +14,7 @@ namespace WireMock.Matchers.Request
/// <summary>
/// The matchers.
/// </summary>
public IReadOnlyList<IMatcher> Matchers { get; }
public IReadOnlyList<IStringMatcher> Matchers { get; }
/// <summary>
/// The ClientIP functions.
@@ -25,7 +25,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class.
/// </summary>
/// <param name="clientIPs">The clientIPs.</param>
public RequestMessageClientIPMatcher([NotNull] params string[] clientIPs) : this(clientIPs.Select(ip => new WildcardMatcher(ip)).Cast<IMatcher>().ToArray())
public RequestMessageClientIPMatcher([NotNull] params string[] clientIPs) : this(clientIPs.Select(ip => new WildcardMatcher(ip)).Cast<IStringMatcher>().ToArray())
{
}
@@ -33,7 +33,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class.
/// </summary>
/// <param name="matchers">The matchers.</param>
public RequestMessageClientIPMatcher([NotNull] params IMatcher[] matchers)
public RequestMessageClientIPMatcher([NotNull] params IStringMatcher[] matchers)
{
Check.NotNull(matchers, nameof(matchers));
Matchers = matchers;
@@ -59,10 +59,14 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage)
{
if (Matchers != null)
{
return Matchers.Max(matcher => matcher.IsMatch(requestMessage.ClientIP));
}
if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.ClientIP != null && Funcs.Any(func => func(requestMessage.ClientIP)));
}
return MatchScores.Mismatch;
}

View File

@@ -24,7 +24,7 @@ namespace WireMock.Matchers.Request
/// <value>
/// The matchers.
/// </value>
public IMatcher[] Matchers { get; }
public IStringMatcher[] Matchers { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
@@ -38,7 +38,7 @@ namespace WireMock.Matchers.Request
Check.NotNull(pattern, nameof(pattern));
Name = name;
Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) };
Matchers = new IStringMatcher[] { new WildcardMatcher(pattern, ignoreCase) };
}
/// <summary>
@@ -46,7 +46,7 @@ namespace WireMock.Matchers.Request
/// </summary>
/// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param>
public RequestMessageCookieMatcher([NotNull] string name, [NotNull] params IMatcher[] matchers)
public RequestMessageCookieMatcher([NotNull] string name, [NotNull] params IStringMatcher[] matchers)
{
Check.NotNull(name, nameof(name));
Check.NotNull(matchers, nameof(matchers));
@@ -83,16 +83,24 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage)
{
if (requestMessage.Cookies == null)
{
return MatchScores.Mismatch;
}
if (Funcs != null)
{
return MatchScores.ToScore(Funcs.Any(f => f(requestMessage.Cookies)));
}
if (Matchers == null)
{
return MatchScores.Mismatch;
}
if (!requestMessage.Cookies.ContainsKey(Name))
{
return MatchScores.Mismatch;
}
string value = requestMessage.Cookies[Name];
return Matchers.Max(m => m.IsMatch(value));

View File

@@ -26,7 +26,7 @@ namespace WireMock.Matchers.Request
/// <value>
/// The matchers.
/// </value>
public IMatcher[] Matchers { get; }
public IStringMatcher[] Matchers { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
@@ -40,7 +40,7 @@ namespace WireMock.Matchers.Request
Check.NotNull(pattern, nameof(pattern));
Name = name;
Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) };
Matchers = new IStringMatcher[] { new WildcardMatcher(pattern, ignoreCase) };
}
/// <summary>
@@ -55,7 +55,7 @@ namespace WireMock.Matchers.Request
Check.NotNull(patterns, nameof(patterns));
Name = name;
Matchers = patterns.Select(pattern => new WildcardMatcher(pattern, ignoreCase)).Cast<IMatcher>().ToArray();
Matchers = patterns.Select(pattern => new WildcardMatcher(pattern, ignoreCase)).Cast<IStringMatcher>().ToArray();
}
/// <summary>
@@ -63,7 +63,7 @@ namespace WireMock.Matchers.Request
/// </summary>
/// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param>
public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] params IMatcher[] matchers)
public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] params IStringMatcher[] matchers)
{
Check.NotNull(name, nameof(name));
Check.NotNull(matchers, nameof(matchers));
@@ -93,16 +93,24 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage)
{
if (requestMessage.Headers == null)
{
return MatchScores.Mismatch;
}
if (Funcs != null)
{
return MatchScores.ToScore(Funcs.Any(f => f(requestMessage.Headers.ToDictionary(entry => entry.Key, entry => entry.Value.ToArray()))));
}
if (Matchers == null)
{
return MatchScores.Mismatch;
}
if (!requestMessage.Headers.ContainsKey(Name))
{
return MatchScores.Mismatch;
}
WireMockList<string> list = requestMessage.Headers[Name];
return Matchers.Max(m => list.Max(value => m.IsMatch(value))); // TODO : is this correct ?

View File

@@ -14,7 +14,7 @@ namespace WireMock.Matchers.Request
/// <summary>
/// The matcher.
/// </summary>
public IReadOnlyList<IMatcher> Matchers { get; }
public IReadOnlyList<IStringMatcher> Matchers { get; }
/// <summary>
/// The path functions
@@ -25,7 +25,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary>
/// <param name="paths">The paths.</param>
public RequestMessagePathMatcher([NotNull] params string[] paths) : this(paths.Select(path => new WildcardMatcher(path)).Cast<IMatcher>().ToArray())
public RequestMessagePathMatcher([NotNull] params string[] paths) : this(paths.Select(path => new WildcardMatcher(path)).Cast<IStringMatcher>().ToArray())
{
}
@@ -33,7 +33,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary>
/// <param name="matchers">The matchers.</param>
public RequestMessagePathMatcher([NotNull] params IMatcher[] matchers)
public RequestMessagePathMatcher([NotNull] params IStringMatcher[] matchers)
{
Check.NotNull(matchers, nameof(matchers));
Matchers = matchers;
@@ -59,10 +59,14 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage)
{
if (Matchers != null)
{
return Matchers.Max(m => m.IsMatch(requestMessage.Path));
}
if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.Path != null && Funcs.Any(func => func(requestMessage.Path)));
}
return MatchScores.Mismatch;
}

View File

@@ -14,7 +14,7 @@ namespace WireMock.Matchers.Request
/// <summary>
/// The matchers.
/// </summary>
public IReadOnlyList<IMatcher> Matchers { get; }
public IReadOnlyList<IStringMatcher> Matchers { get; }
/// <summary>
/// The url functions.
@@ -25,7 +25,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary>
/// <param name="urls">The urls.</param>
public RequestMessageUrlMatcher([NotNull] params string[] urls) : this(urls.Select(url => new WildcardMatcher(url)).Cast<IMatcher>().ToArray())
public RequestMessageUrlMatcher([NotNull] params string[] urls) : this(urls.Select(url => new WildcardMatcher(url)).Cast<IStringMatcher>().ToArray())
{
}
@@ -33,7 +33,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary>
/// <param name="matchers">The matchers.</param>
public RequestMessageUrlMatcher([NotNull] params IMatcher[] matchers)
public RequestMessageUrlMatcher([NotNull] params IStringMatcher[] matchers)
{
Check.NotNull(matchers, nameof(matchers));
Matchers = matchers;
@@ -59,10 +59,14 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage)
{
if (Matchers != null)
{
return Matchers.Max(matcher => matcher.IsMatch(requestMessage.Url));
}
if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.Url != null && Funcs.Any(func => func(requestMessage.Url)));
}
return MatchScores.Mismatch;
}

View File

@@ -10,8 +10,8 @@ namespace WireMock.Matchers
/// <summary>
/// SimMetricsMatcher
/// </summary>
/// <seealso cref="IMatcher" />
public class SimMetricsMatcher : IMatcher
/// <seealso cref="IStringMatcher" />
public class SimMetricsMatcher : IStringMatcher
{
private readonly string[] _patterns;
private readonly SimMetricType _simMetricType;
@@ -38,11 +38,7 @@ namespace WireMock.Matchers
_simMetricType = simMetricType;
}
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input string</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
{
IStringMetric m = GetStringMetricType();
@@ -93,19 +89,13 @@ namespace WireMock.Matchers
}
}
/// <summary>
/// Gets the pattern.
/// </summary>
/// <returns>Pattern</returns>
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public string[] GetPatterns()
{
return _patterns;
}
/// <summary>
/// Gets the name.
/// </summary>
/// <returns>Name</returns>
/// <inheritdoc cref="IMatcher.GetName"/>
public string GetName()
{
return $"SimMetricsMatcher.{_simMetricType}";

View File

@@ -7,7 +7,7 @@ namespace WireMock.Matchers
/// <summary>
/// WildcardMatcher
/// </summary>
/// <seealso cref="IMatcher" />
/// <seealso cref="RegexMatcher" />
public class WildcardMatcher : RegexMatcher
{
private readonly string[] _patterns;
@@ -31,21 +31,13 @@ namespace WireMock.Matchers
_patterns = patterns;
}
/// <summary>
/// Gets the pattern.
/// </summary>
/// <returns>Pattern</returns>
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public override string[] GetPatterns()
{
return _patterns;
}
/// <summary>
/// Gets the name.
/// </summary>
/// <returns>
/// Name
/// </returns>
/// <inheritdoc cref="IMatcher.GetName"/>
public override string GetName()
{
return "WildcardMatcher";

View File

@@ -12,8 +12,8 @@ namespace WireMock.Matchers
/// <summary>
/// XPath2Matcher
/// </summary>
/// <seealso cref="WireMock.Matchers.IMatcher" />
public class XPathMatcher : IMatcher
/// <seealso cref="IStringMatcher" />
public class XPathMatcher : IStringMatcher
{
private readonly string[] _patterns;
@@ -28,15 +28,13 @@ namespace WireMock.Matchers
_patterns = patterns;
}
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input string</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
{
if (input == null)
{
return MatchScores.Mismatch;
}
try
{
@@ -53,19 +51,13 @@ namespace WireMock.Matchers
}
}
/// <summary>
/// Gets the patterns.
/// </summary>
/// <returns>Patterns</returns>
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public string[] GetPatterns()
{
return _patterns;
}
/// <summary>
/// Gets the name.
/// </summary>
/// <returns>Name</returns>
/// <inheritdoc cref="IMatcher.GetName"/>
public string GetName()
{
return "XPathMatcher";

View File

@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using log4net;
using Newtonsoft.Json;
#if !NETSTANDARD
using Microsoft.Owin;
@@ -15,6 +16,7 @@ namespace WireMock.Owin
internal class GlobalExceptionMiddleware
#endif
{
private static readonly ILog Log = LogManager.GetLogger(typeof(GlobalExceptionMiddleware));
#if !NETSTANDARD
public GlobalExceptionMiddleware(OwinMiddleware next) : base(next) { }
#else
@@ -42,6 +44,7 @@ namespace WireMock.Owin
}
catch (Exception ex)
{
Log.Error("HttpStatusCode set to 500", ex);
await _responseMapper.MapAsync(new ResponseMessage { StatusCode = 500, Body = JsonConvert.SerializeObject(ex) }, ctx.Response);
}
}

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WireMock.Util;
#if !NETSTANDARD
using Microsoft.Owin;
#else
@@ -16,7 +17,7 @@ namespace WireMock.Owin
/// <summary>
/// OwinRequestMapper
/// </summary>
public class OwinRequestMapper
internal class OwinRequestMapper
{
/// <summary>
/// MapAsync IOwinRequest to RequestMessage
@@ -43,20 +44,6 @@ namespace WireMock.Owin
#endif
string method = request.Method;
string bodyAsString = null;
byte[] body = null;
Encoding bodyEncoding = null;
if (ParseBody(method) && request.Body != null)
{
using (var streamReader = new StreamReader(request.Body))
{
bodyAsString = await streamReader.ReadToEndAsync();
bodyEncoding = streamReader.CurrentEncoding;
}
body = bodyEncoding.GetBytes(bodyAsString);
}
Dictionary<string, string[]> headers = null;
if (request.Headers.Any())
{
@@ -77,10 +64,16 @@ namespace WireMock.Owin
}
}
return new RequestMessage(url, method, clientIP, body, bodyAsString, bodyEncoding, headers, cookies) { DateTime = DateTime.Now };
BodyData body = null;
if (request.Body != null && ShouldParseBody(method))
{
body = await BodyParser.Parse(request.Body, request.ContentType);
}
return new RequestMessage(url, method, clientIP, body, headers, cookies) { DateTime = DateTime.Now };
}
private bool ParseBody(string method)
private bool ShouldParseBody(string method)
{
/*
HEAD - No defined body semantics.

View File

@@ -3,9 +3,11 @@ using System.Threading.Tasks;
using WireMock.Logging;
using WireMock.Matchers.Request;
using System.Linq;
using log4net;
using WireMock.Matchers;
using WireMock.Util;
using Newtonsoft.Json;
using WireMock.Http;
#if !NETSTANDARD
using Microsoft.Owin;
#else
@@ -20,6 +22,7 @@ namespace WireMock.Owin
internal class WireMockMiddleware
#endif
{
private static readonly ILog Log = LogManager.GetLogger(typeof(WireMockMiddleware));
private static readonly Task CompletedTask = Task.FromResult(false);
private readonly WireMockMiddlewareOptions _options;
@@ -52,7 +55,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.Values.Where(m => m?.Scenario != null))
{
// Set start
if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState)
@@ -61,7 +64,7 @@ namespace WireMock.Owin
}
}
var mappings = _options.Mappings
var mappings = _options.Mappings.Values
.Select(m => new
{
Mapping = m,
@@ -95,6 +98,7 @@ namespace WireMock.Owin
if (targetMapping == null)
{
logRequest = true;
Log.Warn("HttpStatusCode set to 404 : No matching mapping found");
response = new ResponseMessage { StatusCode = 404, Body = "No matching mapping found" };
return;
}
@@ -103,9 +107,10 @@ namespace WireMock.Owin
if (targetMapping.IsAdminInterface && _options.AuthorizationMatcher != null)
{
bool present = request.Headers.TryGetValue("Authorization", out WireMockList<string> authorization);
bool present = request.Headers.TryGetValue(HttpKnownHeaderNames.Authorization, out WireMockList<string> authorization);
if (!present || _options.AuthorizationMatcher.IsMatch(authorization.ToString()) < MatchScores.Perfect)
{
Log.Error("HttpStatusCode set to 401");
response = new ResponseMessage { StatusCode = 401 };
return;
}
@@ -125,6 +130,7 @@ namespace WireMock.Owin
}
catch (Exception ex)
{
Log.Error("HttpStatusCode set to 500", ex);
response = new ResponseMessage { StatusCode = 500, Body = JsonConvert.SerializeObject(ex) };
}
finally

View File

@@ -17,11 +17,11 @@ namespace WireMock.Owin
{
public TimeSpan? RequestProcessingDelay { get; set; }
public IMatcher AuthorizationMatcher { get; set; }
public IStringMatcher AuthorizationMatcher { get; set; }
public bool AllowPartialMapping { get; set; }
public IList<Mapping> Mappings { get; set; } = new List<Mapping>();
public IDictionary<Guid, Mapping> Mappings { get; set; } = new ConcurrentDictionary<Guid, Mapping>();
public ObservableCollection<LogEntry> LogEntries { get; } = new ConcurentObservableCollection<LogEntry>();

View File

@@ -10,38 +10,52 @@ namespace WireMock.RequestBuilders
public interface IBodyRequestBuilder
{
/// <summary>
/// The with body.
/// WithBody: IMatcher
/// </summary>
/// <param name="matcher">The matcher.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody([NotNull] IMatcher matcher);
/// <summary>
/// The with body.
/// WithBody: Body as string
/// </summary>
/// <param name="body">The body.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody(string body);
/// <summary>
/// The with body byte[].
/// WithBody: Body as byte[]
/// </summary>
/// <param name="body">The body as byte[].</param>
/// <param name="body">The body.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody(byte[] body);
/// <summary>
/// The with body string func.
/// WithBody: Body as object
/// </summary>
/// <param name="body">The body string function.</param>
/// <param name="body">The body.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody([NotNull] Func<string, bool> body);
IRequestBuilder WithBody(object body);
/// <summary>
/// The with body byte[] func.
///WithBody: func (string)
/// </summary>
/// <param name="body">The body byte[] function.</param>
/// <param name="func">The function.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody([NotNull] Func<byte[], bool> body);
IRequestBuilder WithBody([NotNull] Func<string, bool> func);
/// <summary>
///WithBody: func (byte[])
/// </summary>
/// <param name="func">The function.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody([NotNull] Func<byte[], bool> func);
/// <summary>
///WithBody: func (object)
/// </summary>
/// <param name="func">The function.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody([NotNull] Func<object, bool> func);
}
}

View File

@@ -14,7 +14,7 @@ namespace WireMock.RequestBuilders
/// </summary>
/// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithClientIP([NotNull] params IMatcher[] matchers);
IRequestBuilder WithClientIP([NotNull] params IStringMatcher[] matchers);
/// <summary>
/// The with ClientIP.

View File

@@ -35,7 +35,7 @@ namespace WireMock.RequestBuilders
/// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithHeader([NotNull] string name, [NotNull] params IMatcher[] matchers);
IRequestBuilder WithHeader([NotNull] string name, [NotNull] params IStringMatcher[] matchers);
/// <summary>
/// The with header.
@@ -59,7 +59,7 @@ namespace WireMock.RequestBuilders
/// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithCookie([NotNull] string name, [NotNull] params IMatcher[] matchers);
IRequestBuilder WithCookie([NotNull] string name, [NotNull] params IStringMatcher[] matchers);
/// <summary>
/// The with cookie.

View File

@@ -14,7 +14,7 @@ namespace WireMock.RequestBuilders
/// </summary>
/// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithPath([NotNull] params IMatcher[] matchers);
IRequestBuilder WithPath([NotNull] params IStringMatcher[] matchers);
/// <summary>
/// The with path.
@@ -35,7 +35,7 @@ namespace WireMock.RequestBuilders
/// </summary>
/// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithUrl([NotNull] params IMatcher[] matchers);
IRequestBuilder WithUrl([NotNull] params IStringMatcher[] matchers);
/// <summary>
/// The with url.

View File

@@ -59,7 +59,7 @@ namespace WireMock.RequestBuilders
/// </summary>
/// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithClientIP(params IMatcher[] matchers)
public IRequestBuilder WithClientIP(params IStringMatcher[] matchers)
{
Check.NotNullOrEmpty(matchers, nameof(matchers));
@@ -98,7 +98,7 @@ namespace WireMock.RequestBuilders
/// </summary>
/// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithPath(params IMatcher[] matchers)
public IRequestBuilder WithPath(params IStringMatcher[] matchers)
{
Check.NotNullOrEmpty(matchers, nameof(matchers));
@@ -137,7 +137,7 @@ namespace WireMock.RequestBuilders
/// </summary>
/// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithUrl(params IMatcher[] matchers)
public IRequestBuilder WithUrl(params IStringMatcher[] matchers)
{
Check.NotNullOrEmpty(matchers, nameof(matchers));
@@ -234,67 +234,28 @@ namespace WireMock.RequestBuilders
return this;
}
/// <summary>
/// The with body.
/// </summary>
/// <param name="body">
/// The body.
/// </param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(string)"/>
public IRequestBuilder WithBody(string body)
{
_requestMatchers.Add(new RequestMessageBodyMatcher(body));
return this;
}
/// <summary>
/// The with body byte[].
/// </summary>
/// <param name="body">
/// The body as byte[].
/// </param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(byte[])"/>
public IRequestBuilder WithBody(byte[] body)
{
_requestMatchers.Add(new RequestMessageBodyMatcher(body));
return this;
}
/// <summary>
/// The with body.
/// </summary>
/// <param name="func">
/// The body function.
/// </param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithBody(Func<string, bool> func)
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(object)"/>
public IRequestBuilder WithBody(object body)
{
Check.NotNull(func, nameof(func));
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
_requestMatchers.Add(new RequestMessageBodyMatcher(body));
return this;
}
/// <summary>
/// The with body.
/// </summary>
/// <param name="func">
/// The body function.
/// </param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithBody(Func<byte[], bool> func)
{
Check.NotNull(func, nameof(func));
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
return this;
}
/// <summary>
/// The with body.
/// </summary>
/// <param name="matcher">The matcher.</param>
/// <returns>The <see cref="IRequestBuilder" />.</returns>
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(IMatcher)"/>
public IRequestBuilder WithBody(IMatcher matcher)
{
Check.NotNull(matcher, nameof(matcher));
@@ -303,16 +264,34 @@ namespace WireMock.RequestBuilders
return this;
}
/// <summary>
/// The with parameters.
/// </summary>
/// <param name="key">
/// The key.
/// </param>
/// <param name="values">
/// The values.
/// </param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(Func{string, bool})"/>
public IRequestBuilder WithBody(Func<string, bool> func)
{
Check.NotNull(func, nameof(func));
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
return this;
}
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(Func{byte[], bool})"/>
public IRequestBuilder WithBody(Func<byte[], bool> func)
{
Check.NotNull(func, nameof(func));
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
return this;
}
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(Func{object, bool})"/>
public IRequestBuilder WithBody(Func<object, bool> func)
{
Check.NotNull(func, nameof(func));
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
return this;
}
/// <inheritdoc cref="IParamsRequestBuilder.WithParam(string, string[])"/>
public IRequestBuilder WithParam(string key, params string[] values)
{
Check.NotNull(key, nameof(key));
@@ -321,11 +300,7 @@ namespace WireMock.RequestBuilders
return this;
}
/// <summary>
/// The with parameters.
/// </summary>
/// <param name="funcs">The funcs.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
/// <inheritdoc cref="IParamsRequestBuilder.WithParam(Func{IDictionary{string, WireMockList{string}}, bool}[])"/>
public IRequestBuilder WithParam(params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs)
{
Check.NotNullOrEmpty(funcs, nameof(funcs));
@@ -360,7 +335,7 @@ namespace WireMock.RequestBuilders
/// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithHeader(string name, params IMatcher[] matchers)
public IRequestBuilder WithHeader(string name, params IStringMatcher[] matchers)
{
Check.NotNull(name, nameof(name));
Check.NotNullOrEmpty(matchers, nameof(matchers));
@@ -401,7 +376,7 @@ namespace WireMock.RequestBuilders
/// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithCookie(string name, params IMatcher[] matchers)
public IRequestBuilder WithCookie(string name, params IStringMatcher[] matchers)
{
Check.NotNullOrEmpty(matchers, nameof(matchers));

View File

@@ -60,15 +60,20 @@ namespace WireMock
public string RawQuery { get; }
/// <summary>
/// Gets the bodyAsBytes.
/// </summary>
public byte[] BodyAsBytes { get; }
/// <summary>
/// Gets the body.
/// The body as string.
/// </summary>
public string Body { get; }
/// <summary>
/// The body (as JSON object).
/// </summary>
public object BodyAsJson { get; set; }
/// <summary>
/// The body (as bytearray).
/// </summary>
public byte[] BodyAsBytes { get; set; }
/// <summary>
/// Gets the Host
/// </summary>
@@ -90,10 +95,45 @@ namespace WireMock
public string Origin { get; }
/// <summary>
/// Gets the body encoding.
/// The body encoding.
/// </summary>
public Encoding BodyEncoding { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessage"/> class.
/// </summary>
/// <param name="url">The original url.</param>
/// <param name="method">The HTTP method.</param>
/// <param name="clientIP">The client IP Address.</param>
/// <param name="body">The body.</param>
/// <param name="headers">The headers.</param>
/// <param name="cookies">The cookies.</param>
public RequestMessage([NotNull] Uri url, [NotNull] string method, [NotNull] string clientIP, [CanBeNull] BodyData body, [CanBeNull] IDictionary<string, string[]> headers = null, [CanBeNull] IDictionary<string, string> cookies = null)
{
Check.NotNull(url, nameof(url));
Check.NotNull(method, nameof(method));
Check.NotNull(clientIP, nameof(clientIP));
Url = url.ToString();
Protocol = url.Scheme;
Host = url.Host;
Port = url.Port;
Origin = $"{url.Scheme}://{url.Host}:{url.Port}";
Path = WebUtility.UrlDecode(url.AbsolutePath);
Method = method.ToLower();
ClientIP = clientIP;
Body = body?.BodyAsString;
BodyEncoding = body?.Encoding;
BodyAsJson = body?.BodyAsJson;
BodyAsBytes = body?.BodyAsBytes;
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
Cookies = cookies;
RawQuery = WebUtility.UrlDecode(url.Query);
Query = ParseQuery(RawQuery);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessage"/> class.
/// </summary>

View File

@@ -247,16 +247,9 @@ namespace WireMock.ResponseBuilders
{
Check.NotNull(body, nameof(body));
string jsonBody = JsonConvert.SerializeObject(body, new JsonSerializerSettings { Formatting = Formatting.None, NullValueHandling = NullValueHandling.Ignore });
if (encoding != null && !encoding.Equals(Encoding.UTF8))
{
jsonBody = encoding.GetString(Encoding.UTF8.GetBytes(jsonBody));
ResponseMessage.BodyEncoding = encoding;
}
ResponseMessage.BodyDestination = null;
ResponseMessage.Body = jsonBody;
ResponseMessage.BodyAsJson = body;
ResponseMessage.BodyEncoding = encoding;
return this;
}

View File

@@ -166,7 +166,8 @@ namespace WireMock.Serialization
return null;
}
var patterns = matcher.GetPatterns();
IStringMatcher stringMatcher = matcher as IStringMatcher;
string[] patterns = stringMatcher != null ? stringMatcher.GetPatterns() : new string[0];
return new MatcherModel
{
@@ -192,7 +193,9 @@ namespace WireMock.Serialization
public static IMatcher Map([CanBeNull] MatcherModel matcher)
{
if (matcher == null)
{
return null;
}
var parts = matcher.Name.Split('.');
string matcherName = parts[0];

View File

@@ -7,6 +7,7 @@ using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Admin.Mappings;
using WireMock.Admin.Requests;
using WireMock.Admin.Settings;
@@ -112,6 +113,7 @@ namespace WireMock.Server
foreach (string filename in Directory.EnumerateFiles(folder).OrderBy(f => f))
{
Log.InfoFormat("Reading Static MappingFile : '{0}'", filename);
ReadStaticMappingAndAddOrUpdate(filename);
}
}
@@ -133,17 +135,22 @@ namespace WireMock.Server
return;
}
var watcher = new EnhancedFileSystemWatcher(folder, "*.json", 500);
Log.InfoFormat("Watching folder '{0}' for new, updated and deleted MappingFiles.", folder);
var watcher = new EnhancedFileSystemWatcher(folder, "*.json", 1000);
watcher.Created += (sender, args) =>
{
Log.InfoFormat("New MappingFile created : '{0}'", args.FullPath);
ReadStaticMappingAndAddOrUpdate(args.FullPath);
};
watcher.Changed += (sender, args) =>
{
Log.InfoFormat("New MappingFile updated : '{0}'", args.FullPath);
ReadStaticMappingAndAddOrUpdate(args.FullPath);
};
watcher.Deleted += (sender, args) =>
{
Log.InfoFormat("New MappingFile deleted : '{0}'", args.FullPath);
string filenameWithoutExtension = Path.GetFileNameWithoutExtension(args.FullPath);
if (Guid.TryParse(filenameWithoutExtension, out Guid guidFromFilename))
@@ -170,13 +177,14 @@ namespace WireMock.Server
string filenameWithoutExtension = Path.GetFileNameWithoutExtension(path);
MappingModel mappingModel = JsonConvert.DeserializeObject<MappingModel>(FileHelper.ReadAllText(path));
if (Guid.TryParse(filenameWithoutExtension, out Guid guidFromFilename))
{
DeserializeAndAddOrUpdateMapping(FileHelper.ReadAllText(path), guidFromFilename, path);
DeserializeAndAddOrUpdateMapping(mappingModel, guidFromFilename, path);
}
else
{
DeserializeAndAddOrUpdateMapping(FileHelper.ReadAllText(path), null, path);
DeserializeAndAddOrUpdateMapping(mappingModel, null, path);
}
}
#endregion
@@ -201,7 +209,7 @@ namespace WireMock.Server
if (settings.SaveMapping)
{
var mapping = ToMapping(requestMessage, responseMessage, settings.BlackListedHeaders ?? new string[] { });
_options.Mappings.Add(mapping);
_options.Mappings.Add(mapping.Guid, mapping);
if (settings.SaveMappingToFile)
{
@@ -256,7 +264,7 @@ namespace WireMock.Server
private ResponseMessage SettingsUpdate(RequestMessage requestMessage)
{
var settings = JsonConvert.DeserializeObject<SettingsModel>(requestMessage.Body);
var settings = requestMessage.Body != null ? JsonConvert.DeserializeObject<SettingsModel>(requestMessage.Body) : ((JObject)requestMessage.BodyAsJson).ToObject<SettingsModel>();
if (settings.AllowPartialMapping != null)
_options.AllowPartialMapping = settings.AllowPartialMapping.Value;
@@ -280,6 +288,7 @@ namespace WireMock.Server
if (mapping == null)
{
Log.Warn("HttpStatusCode set to 404 : Mapping not found");
return new ResponseMessage { StatusCode = 404, Body = "Mapping not found" };
}
@@ -292,7 +301,8 @@ namespace WireMock.Server
{
Guid guid = Guid.Parse(requestMessage.Path.TrimStart(AdminMappings.ToCharArray()));
DeserializeAndAddOrUpdateMapping(requestMessage.Body, guid);
MappingModel mappingModel = requestMessage.Body != null ? JsonConvert.DeserializeObject<MappingModel>(requestMessage.Body) : ((JObject)requestMessage.BodyAsJson).ToObject<MappingModel>();
DeserializeAndAddOrUpdateMapping(mappingModel, guid);
return new ResponseMessage { Body = "Mapping added or updated" };
}
@@ -330,10 +340,12 @@ namespace WireMock.Server
}
var model = MappingConverter.ToMappingModel(mapping);
string json = JsonConvert.SerializeObject(model, _settings);
string filename = !string.IsNullOrEmpty(mapping.Title) ? SanitizeFileName(mapping.Title) : mapping.Guid.ToString();
File.WriteAllText(Path.Combine(folder, filename + ".json"), json);
string filePath = Path.Combine(folder, filename + ".json");
Log.InfoFormat("Saving Mapping to file {0}", filePath);
File.WriteAllText(filePath, JsonConvert.SerializeObject(model, _settings));
}
private static string SanitizeFileName(string name, char replaceChar = '_')
@@ -357,24 +369,25 @@ namespace WireMock.Server
{
try
{
DeserializeAndAddOrUpdateMapping(requestMessage.Body);
MappingModel mappingModel = requestMessage.Body != null ? JsonConvert.DeserializeObject<MappingModel>(requestMessage.Body) : ((JObject)requestMessage.BodyAsJson).ToObject<MappingModel>();
DeserializeAndAddOrUpdateMapping(mappingModel);
}
catch (ArgumentException a)
{
Log.Error("HttpStatusCode set to 400", a);
return new ResponseMessage { StatusCode = 400, Body = a.Message };
}
catch (Exception e)
{
Log.Error("HttpStatusCode set to 500", e);
return new ResponseMessage { StatusCode = 500, Body = e.ToString() };
}
return new ResponseMessage { StatusCode = 201, Body = "Mapping added" };
}
private void DeserializeAndAddOrUpdateMapping(string json, Guid? guid = null, string path = null)
private void DeserializeAndAddOrUpdateMapping(MappingModel mappingModel, Guid? guid = null, string path = null)
{
var mappingModel = JsonConvert.DeserializeObject<MappingModel>(json);
Check.NotNull(mappingModel, nameof(mappingModel));
Check.NotNull(mappingModel.Request, nameof(mappingModel.Request));
Check.NotNull(mappingModel.Response, nameof(mappingModel.Response));
@@ -435,7 +448,10 @@ namespace WireMock.Server
var entry = LogEntries.FirstOrDefault(r => !r.RequestMessage.Path.StartsWith("/__admin/") && r.Guid == guid);
if (entry == null)
return new ResponseMessage { StatusCode = 404, Body = "Request not found" };
{
Log.Warn("HttpStatusCode set to 404 : Request not found");
return new ResponseMessage {StatusCode = 404, Body = "Request not found"};
}
var model = ToLogEntryModel(entry);
@@ -477,6 +493,8 @@ namespace WireMock.Server
Query = logEntry.RequestMessage.Query,
Method = logEntry.RequestMessage.Method,
Body = logEntry.RequestMessage.Body,
BodyAsJson = logEntry.RequestMessage.BodyAsJson,
BodyAsBytes = logEntry.RequestMessage.BodyAsBytes,
Headers = logEntry.RequestMessage.Headers,
Cookies = logEntry.RequestMessage.Cookies,
BodyEncoding = logEntry.RequestMessage.BodyEncoding != null ? new EncodingModel
@@ -491,6 +509,7 @@ namespace WireMock.Server
StatusCode = logEntry.ResponseMessage.StatusCode,
BodyDestination = logEntry.ResponseMessage.BodyDestination,
Body = logEntry.ResponseMessage.Body,
BodyAsJson = logEntry.ResponseMessage.BodyAsJson,
BodyAsBytes = logEntry.ResponseMessage.BodyAsBytes,
BodyOriginal = logEntry.ResponseMessage.BodyOriginal,
BodyAsFile = logEntry.ResponseMessage.BodyAsFile,
@@ -531,7 +550,7 @@ namespace WireMock.Server
#region Requests/find
private ResponseMessage RequestsFind(RequestMessage requestMessage)
{
var requestModel = JsonConvert.DeserializeObject<RequestModel>(requestMessage.Body);
var requestModel = requestMessage.Body != null ? JsonConvert.DeserializeObject<RequestModel>(requestMessage.Body) : ((JObject)requestMessage.BodyAsJson).ToObject<RequestModel>();
var request = (Request)InitRequestBuilder(requestModel);
@@ -587,7 +606,7 @@ namespace WireMock.Server
var clientIPModel = JsonUtils.ParseJTokenToObject<ClientIPModel>(requestModel.ClientIP);
if (clientIPModel?.Matchers != null)
{
requestBuilder = requestBuilder.WithPath(clientIPModel.Matchers.Select(MappingConverter.Map).ToArray());
requestBuilder = requestBuilder.WithPath(clientIPModel.Matchers.Select(MappingConverter.Map).Cast<IStringMatcher>().ToArray());
}
}
}
@@ -604,7 +623,7 @@ namespace WireMock.Server
var pathModel = JsonUtils.ParseJTokenToObject<PathModel>(requestModel.Path);
if (pathModel?.Matchers != null)
{
requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(MappingConverter.Map).ToArray());
requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(MappingConverter.Map).Cast<IStringMatcher>().ToArray());
}
}
}
@@ -621,7 +640,7 @@ namespace WireMock.Server
var urlModel = JsonUtils.ParseJTokenToObject<UrlModel>(requestModel.Url);
if (urlModel?.Matchers != null)
{
requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(MappingConverter.Map).ToArray());
requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(MappingConverter.Map).Cast<IStringMatcher>().ToArray());
}
}
}
@@ -635,7 +654,7 @@ namespace WireMock.Server
{
foreach (var headerModel in requestModel.Headers.Where(h => h.Matchers != null))
{
requestBuilder = requestBuilder.WithHeader(headerModel.Name, headerModel.Matchers.Select(MappingConverter.Map).ToArray());
requestBuilder = requestBuilder.WithHeader(headerModel.Name, headerModel.Matchers.Select(MappingConverter.Map).Cast<IStringMatcher>().ToArray());
}
}
@@ -643,7 +662,7 @@ namespace WireMock.Server
{
foreach (var cookieModel in requestModel.Cookies.Where(c => c.Matchers != null))
{
requestBuilder = requestBuilder.WithCookie(cookieModel.Name, cookieModel.Matchers.Select(MappingConverter.Map).ToArray());
requestBuilder = requestBuilder.WithCookie(cookieModel.Name, cookieModel.Matchers.Select(MappingConverter.Map).Cast<IStringMatcher>().ToArray());
}
}

View File

@@ -6,6 +6,8 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using log4net;
using Newtonsoft.Json;
using WireMock.Http;
using WireMock.Matchers;
using WireMock.Matchers.Request;
@@ -13,7 +15,6 @@ using WireMock.RequestBuilders;
using WireMock.Settings;
using WireMock.Validation;
using WireMock.Owin;
using WireMock.Serialization;
namespace WireMock.Server
{
@@ -22,6 +23,7 @@ namespace WireMock.Server
/// </summary>
public partial class FluentMockServer : IDisposable
{
private static readonly ILog Log = LogManager.GetLogger(typeof(FluentMockServer));
private const int ServerStartDelay = 100;
private readonly IOwinSelfHost _httpServer;
private readonly WireMockMiddlewareOptions _options = new WireMockMiddlewareOptions();
@@ -48,7 +50,7 @@ namespace WireMock.Server
/// Gets the mappings.
/// </summary>
[PublicAPI]
public IEnumerable<Mapping> Mappings => new ReadOnlyCollection<Mapping>(_options.Mappings);
public IEnumerable<Mapping> Mappings => _options.Mappings.Values.ToArray();
/// <summary>
/// Gets the scenarios.
@@ -156,6 +158,8 @@ namespace WireMock.Server
private FluentMockServer(IFluentMockServerSettings settings)
{
Log.DebugFormat("WireMock.Net server settings {0}", JsonConvert.SerializeObject(settings, Formatting.Indented));
if (settings.Urls != null)
{
Urls = settings.Urls.Select(u => u.EndsWith("/") ? u : $"{u}/").ToArray();
@@ -269,7 +273,10 @@ namespace WireMock.Server
[PublicAPI]
public void ResetMappings()
{
_options.Mappings = _options.Mappings.Where(m => m.IsAdminInterface).ToList();
foreach (var nonAdmin in _options.Mappings.Where(m => !m.Value.IsAdminInterface))
{
_options.Mappings.Remove(nonAdmin);
}
}
/// <summary>
@@ -280,25 +287,19 @@ namespace WireMock.Server
public bool DeleteMapping(Guid guid)
{
// Check a mapping exists with the same GUID, if so, remove it.
return DeleteMapping(m => m.Guid == guid);
if (_options.Mappings.ContainsKey(guid))
{
return _options.Mappings.Remove(guid);
}
return false;
}
private bool DeleteMapping(string path)
{
// Check a mapping exists with the same path, if so, remove it.
return DeleteMapping(m => string.Equals(m.Path, path, StringComparison.OrdinalIgnoreCase));
}
private bool DeleteMapping(Func<Mapping, bool> predicate)
{
var existingMapping = _options.Mappings.FirstOrDefault(predicate);
if (existingMapping != null)
{
_options.Mappings.Remove(existingMapping);
return true;
}
return false;
var mapping = _options.Mappings.FirstOrDefault(entry => string.Equals(entry.Value.Path, path, StringComparison.OrdinalIgnoreCase));
return DeleteMapping(mapping.Key);
}
/// <summary>
@@ -315,9 +316,10 @@ namespace WireMock.Server
/// Allows the partial mapping.
/// </summary>
[PublicAPI]
public void AllowPartialMapping()
public void AllowPartialMapping(bool allow = true)
{
_options.AllowPartialMapping = true;
Log.InfoFormat("AllowPartialMapping is set to {0}", allow);
_options.AllowPartialMapping = allow;
}
/// <summary>
@@ -388,14 +390,13 @@ namespace WireMock.Server
private void RegisterMapping(Mapping mapping)
{
// Check a mapping exists with the same Guid, if so, replace it.
var existingMapping = _options.Mappings.FirstOrDefault(m => m.Guid == mapping.Guid);
if (existingMapping != null)
if (_options.Mappings.ContainsKey(mapping.Guid))
{
_options.Mappings[_options.Mappings.IndexOf(existingMapping)] = mapping;
_options.Mappings[mapping.Guid] = mapping;
}
else
{
_options.Mappings.Add(mapping);
_options.Mappings.Add(mapping.Guid, mapping);
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using JetBrains.Annotations;
using Newtonsoft.Json;
namespace WireMock.Settings
{
@@ -63,10 +64,12 @@ namespace WireMock.Settings
/// <inheritdoc cref="IFluentMockServerSettings.PreWireMockMiddlewareInit"/>
[PublicAPI]
[JsonIgnore]
public Action<object> PreWireMockMiddlewareInit { get; set; }
/// <inheritdoc cref="IFluentMockServerSettings.PostWireMockMiddlewareInit"/>
[PublicAPI]
[JsonIgnore]
public Action<object> PostWireMockMiddlewareInit { get; set; }
}
}

View File

@@ -0,0 +1,30 @@
using System.Text;
namespace WireMock.Util
{
/// <summary>
/// BodyData
/// </summary>
public class BodyData
{
/// <summary>
/// The body encoding.
/// </summary>
public Encoding Encoding { get; set; }
/// <summary>
/// The body as string.
/// </summary>
public string BodyAsString { get; set; }
/// <summary>
/// The body (as JSON object).
/// </summary>
public object BodyAsJson { get; set; }
/// <summary>
/// The body (as bytearray).
/// </summary>
public byte[] BodyAsBytes { get; set; }
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
namespace WireMock.Util
{
internal static class BodyParser
{
private static readonly string[] TextContentTypes = { "text/", "application/xml", "application/javascript", "application/typescript", "application/xhtml+xml" };
private static async Task<Tuple<string, Encoding>> ReadStringAsync(Stream stream)
{
using (var streamReader = new StreamReader(stream))
{
string content = await streamReader.ReadToEndAsync();
return new Tuple<string, Encoding>(content, streamReader.CurrentEncoding);
}
}
private static async Task<byte[]> ReadBytesAsync(Stream stream)
{
using (var memoryStream = new MemoryStream())
{
await stream.CopyToAsync(memoryStream);
return memoryStream.ToArray();
}
}
public static async Task<BodyData> Parse([NotNull] Stream stream, [CanBeNull] string contentTypeHeaderValue)
{
var data = new BodyData();
if (contentTypeHeaderValue != null && TextContentTypes.Any(t => contentTypeHeaderValue.StartsWith(t, StringComparison.OrdinalIgnoreCase)))
{
try
{
var stringData = await ReadStringAsync(stream);
data.BodyAsString = stringData.Item1;
data.Encoding = stringData.Item2;
}
catch
{
// Reading as string failed, just get the ByteArray.
data.BodyAsBytes = await ReadBytesAsync(stream);
}
}
else if (contentTypeHeaderValue != null && contentTypeHeaderValue.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
var stringData = await ReadStringAsync(stream);
data.Encoding = stringData.Item2;
try
{
data.BodyAsJson = JsonConvert.DeserializeObject(stringData.Item1, new JsonSerializerSettings { Formatting = Formatting.Indented });
}
catch
{
// JsonConvert failed, just set the Body as string.
data.BodyAsString = stringData.Item1;
}
}
else
{
data.BodyAsBytes = await ReadBytesAsync(stream);
}
return data;
}
}
}

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.3</Version>
<Version>1.0.3.3</Version>
<Authors>Alexandre Victoor;Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -32,6 +32,10 @@
<DefineConstants>NETSTANDARD</DefineConstants>
</PropertyGroup>
<ItemGroup>
<None Remove="Server\FluentMockServer.cs~RF44936b9f.TMP" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="11.1.0">
<PrivateAssets>All</PrivateAssets>
@@ -41,7 +45,7 @@
<PackageReference Include="SimMetrics.Net" Version="1.0.4" />
<PackageReference Include="System.Net.Http" Version="4.3.3" />
<PackageReference Include="RestEase" Version="1.4.4" />
<!--<PackageReference Include="OpenSSL.X509Certificate2.Provider" Version="1.0.2" />-->
<PackageReference Include="log4net" Version="2.0.8" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">

View File

@@ -31,6 +31,7 @@ namespace WireMock.Net.Tests
var result = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/search?q=test");
// then
Check.That(_server.Mappings).HasSize(1);
Check.That(result).Contains("google");
}
@@ -53,9 +54,6 @@ namespace WireMock.Net.Tests
}
};
_server = FluentMockServer.Start(settings);
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy(_serverForProxyForwarding.Urls[0]));
// when
var requestMessage = new HttpRequestMessage
@@ -72,12 +70,15 @@ namespace WireMock.Net.Tests
var receivedRequest = _serverForProxyForwarding.LogEntries.First().RequestMessage;
Check.That(receivedRequest.Body).IsEqualTo("stringContent");
Check.That(receivedRequest.Headers).ContainsKey("Content-Type");
Check.That(receivedRequest.Headers["Content-Type"]).ContainsExactly("text/plain");
Check.That(receivedRequest.Headers["Content-Type"].First()).Contains("text/plain");
Check.That(receivedRequest.Headers).ContainsKey("bbb");
var mapping = _server.Mappings.Last();
var matcher = ((Request) mapping.RequestMatcher).GetRequestMessageMatchers<RequestMessageHeaderMatcher>().FirstOrDefault(m => m.Name == "bbb");
Check.That(matcher).IsNotNull();
// check that new proxied mapping is added
Check.That(_server.Mappings).HasSize(2);
//var newMapping = _server.Mappings.First(m => m.Guid != guid);
//var matcher = ((Request)newMapping.RequestMatcher).GetRequestMessageMatchers<RequestMessageHeaderMatcher>().FirstOrDefault(m => m.Name == "bbb");
//Check.That(matcher).IsNotNull();
}
[Fact]
@@ -100,9 +101,9 @@ namespace WireMock.Net.Tests
}
};
_server = FluentMockServer.Start(settings);
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create());
//_server
// .Given(Request.Create().WithPath("/*"))
// .RespondWith(Response.Create());
// when
var requestMessage = new HttpRequestMessage
@@ -118,9 +119,9 @@ namespace WireMock.Net.Tests
var receivedRequest = _serverForProxyForwarding.LogEntries.First().RequestMessage;
Check.That(receivedRequest.Headers).ContainsKey("bbb");
var mapping = _server.Mappings.Last();
var matcher = ((Request)mapping.RequestMatcher).GetRequestMessageMatchers<RequestMessageHeaderMatcher>().FirstOrDefault(m => m.Name == "bbb");
Check.That(matcher).IsNull();
//var mapping = _server.Mappings.Last();
//var matcher = ((Request)mapping.RequestMatcher).GetRequestMessageMatchers<RequestMessageHeaderMatcher>().FirstOrDefault(m => m.Name == "bbb");
//Check.That(matcher).IsNull();
}
[Fact]
@@ -151,7 +152,7 @@ namespace WireMock.Net.Tests
var receivedRequest = _serverForProxyForwarding.LogEntries.First().RequestMessage;
Check.That(receivedRequest.Body).IsEqualTo("");
Check.That(receivedRequest.Headers).ContainsKey("Content-Type");
Check.That(receivedRequest.Headers["Content-Type"]).ContainsExactly("text/plain");
Check.That(receivedRequest.Headers["Content-Type"].First()).Contains("text/plain");
}
[Fact]

View File

@@ -91,7 +91,7 @@ namespace WireMock.Net.Tests
[Fact]
public void FluentMockServer_Admin_Mappings_Get()
{
var guid = Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05");
Guid guid = Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05");
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/foo1").UsingGet())
@@ -103,12 +103,6 @@ namespace WireMock.Net.Tests
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]
@@ -153,8 +147,6 @@ namespace WireMock.Net.Tests
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");

View File

@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using NFluent;
using WireMock.Matchers;
using WireMock.Matchers.Request;
using WireMock.RequestBuilders;
using WireMock.Util;
using Xunit;
namespace WireMock.Net.Tests
@@ -198,5 +200,86 @@ namespace WireMock.Net.Tests
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
}
[Fact]
public void Request_WithBodyAsJson_Object_JsonPathMatcher_true()
{
// given
var spec = Request.Create().UsingAnyVerb().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]"));
// when
string jsonString = "{ \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"Wiremock\" } ] }";
var bodyData = new BodyData
{
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
Encoding = Encoding.UTF8
};
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, bodyData);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Request_WithBodyAsJson_Array_JsonPathMatcher_true()
{
// given
var spec = Request.Create().UsingAnyVerb().WithBody(new JsonPathMatcher("$.books[?(@.price < 10)]"));
// when
string jsonString = "{ \"books\": [ { \"category\": \"test1\", \"price\": 8.95 }, { \"category\": \"test2\", \"price\": 20 } ] }";
var bodyData = new BodyData
{
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
Encoding = Encoding.UTF8
};
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, bodyData);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Request_WithBodyAsObject_ExactObjectMatcher_true()
{
// Assign
object body = DateTime.MinValue;
var requestBuilder = Request.Create().UsingAnyVerb().WithBody(body);
var bodyData = new BodyData
{
BodyAsJson = DateTime.MinValue
};
// Act
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, bodyData);
// Assert
var requestMatchResult = new RequestMatchResult();
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Request_WithBodyAsBytes_ExactObjectMatcher_true()
{
// Assign
byte[] body = { 123 };
var requestBuilder = Request.Create().UsingAnyVerb().WithBody(body);
var bodyData = new BodyData
{
BodyAsBytes = new byte[] { 123 }
};
// Act
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, bodyData);
// Assert
var requestMatchResult = new RequestMatchResult();
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
}
}

View File

@@ -75,13 +75,15 @@ namespace WireMock.Net.Tests
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().WithBodyAsJson(new { value = "test" }, Encoding.ASCII);
object x = new { value = "test" };
var response = Response.Create().WithBodyAsJson(x, Encoding.ASCII);
// act
var responseMessage = await response.ProvideResponseAsync(request);
// then
Check.That(responseMessage.Body).Equals("{\"value\":\"test\"}");
Check.That(responseMessage.BodyAsJson).IsNotNull();
Check.That(responseMessage.BodyAsJson).Equals(x);
Check.That(responseMessage.BodyEncoding).Equals(Encoding.ASCII);
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using NFluent;
using WireMock.RequestBuilders;
@@ -69,7 +70,7 @@ namespace WireMock.Net.Tests
}
[Fact]
public async Task Scenario_and_State_TodoList_Example()
public void Scenario_and_State_TodoList_Example()
{
// Assign
_server = FluentMockServer.Start();
@@ -104,18 +105,18 @@ namespace WireMock.Net.Tests
// Act and Assert
string url = "http://localhost:" + _server.Ports[0];
string getResponse1 = await new HttpClient().GetStringAsync(url + "/todo/items");
string getResponse1 = new HttpClient().GetStringAsync(url + "/todo/items").Result;
Check.That(getResponse1).Equals("Buy milk");
var postResponse = await new HttpClient().PostAsync(url + "/todo/items", new StringContent("Cancel newspaper subscription"));
var postResponse = new HttpClient().PostAsync(url + "/todo/items", new StringContent("Cancel newspaper subscription")).Result;
Check.That(postResponse.StatusCode).Equals(HttpStatusCode.Created);
string getResponse2 = await new HttpClient().GetStringAsync(url + "/todo/items");
string getResponse2 = new HttpClient().GetStringAsync(url + "/todo/items").Result;
Check.That(getResponse2).Equals("Buy milk;Cancel newspaper subscription");
}
[Fact]
public async Task Should_process_request_if_equals_state_and_multiple_state_defined()
public void Should_process_request_if_equals_state_and_multiple_state_defined()
{
// given
_server = FluentMockServer.Start();
@@ -156,18 +157,20 @@ namespace WireMock.Net.Tests
.RespondWith(Response.Create()
.WithBody("Test state msg 2"));
// when
Thread.Sleep(500);
// when / then
string url = "http://localhost:" + _server.Ports[0];
var responseNoState1 = await new HttpClient().GetStringAsync(url + "/state1");
var responseNoState2 = await new HttpClient().GetStringAsync(url + "/state2");
var responseWithState1 = await new HttpClient().GetStringAsync(url + "/foo");
var responseWithState2 = await new HttpClient().GetStringAsync(url + "/foo");
// then
var responseNoState1 = new HttpClient().GetStringAsync(url + "/state1").Result;
Check.That(responseNoState1).Equals("No state msg 1");
Check.That(responseWithState1).Equals("Test state msg 1");
var responseNoState2 = new HttpClient().GetStringAsync(url + "/state2").Result;
Check.That(responseNoState2).Equals("No state msg 2");
var responseWithState1 = new HttpClient().GetStringAsync(url + "/foo").Result;
Check.That(responseWithState1).Equals("Test state msg 1");
var responseWithState2 = new HttpClient().GetStringAsync(url + "/foo").Result;
Check.That(responseWithState2).Equals("Test state msg 2");
}