Compare commits

..

23 Commits

Author SHA1 Message Date
Stef Heyenrath
fe9f4902b1 1.0.4.3 2018-06-30 00:06:53 +02:00
Stef Heyenrath
db013a56ad Merge branch 'param' 2018-06-29 23:59:30 +02:00
Stef Heyenrath
7b2deceafd Merge branch 'Fix_IRequestBuilder.WithParam' 2018-06-29 22:32:31 +02:00
Stef Heyenrath
281b970c57 WithParam (#159) 2018-06-28 20:50:09 +02:00
Stef Heyenrath
768cc621ad #156 2018-06-27 20:19:27 +02:00
Stef Heyenrath
3df8bd2fdc #156 2018-06-27 20:02:16 +02:00
Stef Heyenrath
2d1ead25cd #156 2018-06-27 19:56:53 +02:00
Stef Heyenrath
24d00845fb 1.0.4.2 2018-06-26 23:24:32 +02:00
Stef Heyenrath
4283732b6c Support for string and object in JsonMatcher. (#157)
* JsonMatcher (#154)

* small update in example code
2018-06-26 23:20:30 +02:00
Stef Heyenrath
b2690017a8 Set Microsoft.NET.Test.Sdk back to 15.3.0 2018-06-25 20:29:10 +02:00
Stef Heyenrath
9470130d65 responsebody.json 2018-06-25 20:21:40 +02:00
Stef Heyenrath
b5f0e658da 1.0.4.1 (#153) 2018-06-25 19:57:42 +02:00
Stef Heyenrath
2eff243a96 Added JsonMatcher (#153) 2018-06-25 19:36:41 +02:00
Stef Heyenrath
2895bf2dea Add gitter chat badge 2018-06-24 12:12:43 +02:00
Stef Heyenrath
f61a814ab5 Fix coveralls.net 2018-06-23 16:33:29 +02:00
Stef Heyenrath
ce2db748f1 1.0.4.0 2018-06-23 11:26:24 +02:00
Stef Heyenrath
443fc76773 Add request / response logging (#151)
Add request / response logging (#151)
2018-06-23 11:22:07 +02:00
Stef Heyenrath
454051568a 1.0.3.20 2018-05-29 22:01:15 +02:00
Stef Heyenrath
2b498f45cb Revert PortUtil.cs changes (#147) 2018-05-29 21:58:56 +02:00
Stef Heyenrath
2fcfda49c7 Update changelog 2018-05-28 15:13:34 +02:00
Stef Heyenrath
7ef0c1d68b 1.0.3.19 2018-05-28 08:43:41 +02:00
Bob Paul
297743a19a Fix code for .NET Core 2 so that server has cancellation token, and Stop method waits for shutdown. This resolves issues when using .NET Core 2 and starting/stopping server instances. (#145) 2018-05-28 08:30:18 +02:00
Stef Heyenrath
0640c88bcd Fix ConcurrentDictionary (#129) (#144) 2018-05-28 08:08:18 +02:00
48 changed files with 822 additions and 265 deletions

View File

@@ -1,3 +1,54 @@
# 1.0.4.3 (30 June 2018)
- [#159](https://github.com/WireMock-Net/WireMock.Net/issues/159) - Bug: IRequestBuilder.WithParam broken for key-only matching +fix
- [#156](https://github.com/WireMock-Net/WireMock.Net/issues/156) - Feature: when adding / updating a mapping : return more details
Commits: 2d1ead25cd...db013a56ad
# 1.0.4.2 (26 June 2018)
- [#157](https://github.com/WireMock-Net/WireMock.Net/pull/157) - Support for string and object in JsonMatcher. contributed by Stef Heyenrath ([StefH](https://github.com/StefH)) +feature
- [#155](https://github.com/WireMock-Net/WireMock.Net/pull/155) - Replace JsonMatcher with JsonObjectMatcher and directly support JSON body matching. contributed by ([DavidKorn](https://github.com/DavidKorn))
- [#154](https://github.com/WireMock-Net/WireMock.Net/issues/154) - Feature: support BodyAsJson for Request in static mapping files. +feature
Commits: 9470130d65...4283732b6c
# 1.0.4.1 (25 June 2018)
- [#153](https://github.com/WireMock-Net/WireMock.Net/issues/153) - Feature: Add JsonMatcher to support Json mapping
Commits: f61a814ab5...2eff243a96
# 1.0.4.0 (23 June 2018)
- [#151](https://github.com/WireMock-Net/WireMock.Net/issues/151) - Feature: Add logging of incoming request and body for tracability
- [#149](https://github.com/WireMock-Net/WireMock.Net/issues/149) - Question: Transformer and Delay in Static Mappings?
- [#131](https://github.com/WireMock-Net/WireMock.Net/issues/131) - Bug: CurlException Couldn't connect to Server when running multiple tests
Commits: 443fc76773...443fc76773
# 1.0.3.20 (29 May 2018)
- [#147](https://github.com/WireMock-Net/WireMock.Net/pull/147) - Revert PortUtil.cs changes contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#146](https://github.com/WireMock-Net/WireMock.Net/issues/146) - Hang possibly due to Windows firewall prompt
- [#129](https://github.com/WireMock-Net/WireMock.Net/issues/129) - Random test failures between WireMock.Net 1.0.3.1 and 1.0.3.2
Commits: 2fcfda49c7...2b498f45cb
# 1.0.3.19 (28 May 2018)
- [#129](https://github.com/WireMock-Net/WireMock.Net/issues/129) - Random test failures between WireMock.Net 1.0.3.1 and 1.0.3.2
- [#145](https://github.com/WireMock-Net/WireMock.Net/pull/145) - Cancellation token not passed to server instance in .NET Core 2 contributed by Bob Paul ([Bob11327](https://github.com/Bob11327)) +fix
- [#144](https://github.com/WireMock-Net/WireMock.Net/pull/144) - Fix ConcurrentDictionary (#129) contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
Commits: ...
# 1.0.3.18 (25 May 2018)
- [#142](https://github.com/WireMock-Net/WireMock.Net/pull/142) - Allow all headers to be set as Response headers contributed by Stef Heyenrath ([StefH](https://github.com/StefH))

View File

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

View File

@@ -1,9 +1,10 @@
# WireMock.Net
A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) which mimics the functionality from the JAVA based http://WireMock.org
[![Gitter](https://img.shields.io/gitter/room/wiremock_dotnet/Lobby.svg)](https://gitter.im/wiremock_dotnet/Lobby)
[![GitHub issues](https://img.shields.io/github/issues/WireMock-Net/WireMock.Net.svg)](https://github.com/WireMock-Net/WireMock.Net/issues)
[![Build status](https://ci.appveyor.com/api/projects/status/b3n6q3ygbww4lyls?svg=true)](https://ci.appveyor.com/project/StefH/wiremock-net)
[![Coverage Status](https://coveralls.io/repos/github/WireMock-Net/WireMock.Net/badge.svg?branch=master)](https://coveralls.io/github/WireMock-Net/WireMock.Net?branch=master)
[![GitHub issues](https://img.shields.io/github/issues/WireMock-Net/WireMock.Net.svg)](https://github.com/WireMock-Net/WireMock.Net/issues)
[![GitHub stars](https://img.shields.io/github/stars/WireMock-Net/WireMock.Net.svg)](https://github.com/WireMock-Net/WireMock.Net/stargazers)
| Name | NuGet |

View File

@@ -1,6 +1,6 @@
os: Visual Studio 2017
version: 1.0.2.{build}
version: 1.0.4.{build}
configuration:
- Debug
@@ -35,9 +35,9 @@ build_script:
test_script:
- nuget.exe install OpenCover -ExcludeVersion
- nuget.exe install coveralls.net -ExcludeVersion
- nuget.exe install coveralls.net -ExcludeVersion -Version 0.7.0
- pip install codecov
- cmd: '"OpenCover\tools\OpenCover.Console.exe" -target:dotnet.exe -targetargs:"test test\WireMock.Net.Tests\WireMock.Net.Tests.csproj --no-build" -output:coverage.xml -returntargetcode -register:user -filter:"+[WireMock.Net]* -[WireMock.Net.Tests*]*" -nodefaultfilters -returntargetcode -oldstyle -searchdirs:".\test\WireMock.Net.Tests\bin\%CONFIGURATION%\net452"'
- codecov -f "coverage.xml"
- coveralls.net\tools\csmacnz.Coveralls.exe --opencover -i .\coverage.xml
- coveralls.net\tools\csmacnz.Coveralls.exe --opencover -i .\coverage.xml

View File

@@ -43,11 +43,11 @@ namespace WireMock.Net.Client
var request = api.GetRequestsAsync().Result;
Console.WriteLine($"request = {JsonConvert.SerializeObject(request)}");
string deleteRequestsAsync = api.DeleteRequestsAsync().Result;
Console.WriteLine($"deleteRequestsAsync = {deleteRequestsAsync}");
var deleteRequestsAsync = api.DeleteRequestsAsync().Result;
Console.WriteLine($"deleteRequestsAsync = {deleteRequestsAsync.Status}");
string resetRequestsAsync = api.ResetRequestsAsync().Result;
Console.WriteLine($"resetRequestsAsync = {resetRequestsAsync}");
var resetRequestsAsync = api.ResetRequestsAsync().Result;
Console.WriteLine($"resetRequestsAsync = {resetRequestsAsync.Status}");
Console.WriteLine("Press any key to quit");
Console.ReadKey();

View File

@@ -1,6 +1,7 @@
using System;
using System.Net;
using Newtonsoft.Json;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
@@ -28,7 +29,8 @@ namespace WireMock.Net.ConsoleApplication
// SaveMapping = true
//},
PreWireMockMiddlewareInit = app => { System.Console.WriteLine($"PreWireMockMiddlewareInit : {app.GetType()}"); },
PostWireMockMiddlewareInit = app => { System.Console.WriteLine($"PostWireMockMiddlewareInit : {app.GetType()}"); }
PostWireMockMiddlewareInit = app => { System.Console.WriteLine($"PostWireMockMiddlewareInit : {app.GetType()}"); },
Logger = new WireMockConsoleLogger()
});
System.Console.WriteLine("FluentMockServer listening at {0}", string.Join(",", server.Urls));
@@ -36,11 +38,12 @@ namespace WireMock.Net.ConsoleApplication
server.AllowPartialMapping();
// .WithHeader("Stef", "Stef")
//server
// .Given(Request.Create().WithPath("*"))
// .RespondWith(Response.Create()
// .WithProxy("http://restcountries.eu"));
server
.Given(Request.Create()
.WithPath("/xpath").UsingPost()
.WithBody(new XPathMatcher("/todo-list[count(todo-item) = 3]"))
)
.RespondWith(Response.Create().WithBody("XPathMatcher!"));
server
.Given(Request
@@ -51,6 +54,26 @@ namespace WireMock.Net.ConsoleApplication
.RespondWith(Response.Create()
.WithBody(@"{ ""result"": ""JsonPathMatcher !!!""}"));
server
.Given(Request
.Create()
.WithPath("/jsonbodytest1")
.WithBody(new JsonMatcher("{ \"x\": 42, \"s\": \"s\" }"))
.UsingPost())
.WithGuid("debaf408-3b23-4c04-9d18-ef1c020e79f2")
.RespondWith(Response.Create()
.WithBody(@"{ ""result"": ""jsonbodytest1"" }"));
server
.Given(Request
.Create()
.WithPath("/jsonbodytest2")
.WithBody(new JsonMatcher(new { x = 42, s = "s" }))
.UsingPost())
.WithGuid("debaf408-3b23-4c04-9d18-ef1c020e79f3")
.RespondWith(Response.Create()
.WithBody(@"{ ""result"": ""jsonbodytest2"" }"));
server
.Given(Request
.Create()
@@ -58,13 +81,33 @@ namespace WireMock.Net.ConsoleApplication
.WithParam("$filter", "(substringof(Code, 'WA')")
.UsingGet())
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBody(@"{ ""result"": ""odata""}"));
server
.Given(Request
.Create()
.WithPath(new WildcardMatcher("/param2", true))
.WithParam("key", "test")
.UsingGet())
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson(new { result = "param2" }));
server
.Given(Request
.Create()
.WithPath(new WildcardMatcher("/param3", true))
.WithParam("key", new WildcardMatcher("t*"))
.UsingGet())
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson(new { result = "param3" }));
server
.Given(Request.Create().WithPath("/headers", "/headers_test").UsingPost().WithHeader("Content-Type", "application/json*"))
.RespondWith(Response.Create()
.WithStatusCode(201)
//.WithHeader("MyHeader", "application/json", "application/json2")
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson(new { result = "data:headers posted with 201" }));
@@ -171,8 +214,6 @@ namespace WireMock.Net.ConsoleApplication
.WithStatusCode(HttpStatusCode.Unauthorized)
.WithBody(@"{ ""result"": ""api-key missing""}"));
server
.Given(Request.Create().WithPath("/nobody").UsingGet())
.RespondWith(Response.Create().WithDelay(TimeSpan.FromSeconds(1))
@@ -182,7 +223,7 @@ namespace WireMock.Net.ConsoleApplication
.Given(Request.Create().WithPath("/partial").UsingPost().WithBody(new SimMetricsMatcher(new[] { "cat", "dog" })))
.RespondWith(Response.Create().WithStatusCode(200).WithBody("partial = 200"));
// http://localhost:8080/any/any?start=1000&stop=1&stop=2
// http://localhost:8080/trans?start=1000&stop=1&stop=2
server
.Given(Request.Create().WithPath("/trans").UsingGet())
.WithGuid("90356dba-b36c-469a-a17e-669cd84f1f05")
@@ -190,6 +231,7 @@ namespace WireMock.Net.ConsoleApplication
.WithStatusCode(200)
.WithHeader("Content-Type", "application/json")
.WithHeader("Transformed-Postman-Token", "token is {{request.headers.Postman-Token}}")
.WithHeader("xyz_{{request.headers.Postman-Token}}", "token is {{request.headers.Postman-Token}}")
.WithBody(@"{""msg"": ""Hello world CATCH-ALL on /*, {{request.path}}, bykey={{request.query.start}}, bykey={{request.query.stop}}, byidx0={{request.query.stop.[0]}}, byidx1={{request.query.stop.[1]}}"" }")
.WithTransformer()
.WithDelay(TimeSpan.FromMilliseconds(100))

View File

@@ -1,4 +1,6 @@
using log4net;
using Newtonsoft.Json;
using WireMock.Admin.Requests;
using WireMock.Logging;
namespace WireMock.Net.StandAlone.NETCoreApp
@@ -26,5 +28,11 @@ namespace WireMock.Net.StandAlone.NETCoreApp
{
Log.ErrorFormat(formatString, args);
}
public void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminRequest)
{
string message = JsonConvert.SerializeObject(logEntryModel, Formatting.Indented);
Log.DebugFormat("Admin[{0}] {1}", isAdminRequest, message);
}
}
}

View File

@@ -42,8 +42,18 @@
<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.Owin.Host.HttpListener, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Owin.Host.HttpListener.4.0.0\lib\net451\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.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.4\lib\net45\System.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
@@ -53,6 +63,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.8" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.4" targetFramework="net452" />
<package id="Microsoft.Owin.Host.HttpListener" version="4.0.0" targetFramework="net452" />
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net452" />
</packages>

View File

@@ -1,6 +1,7 @@
using System.Threading;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using WireMock.Admin.Requests;
using WireMock.Logging;
using WireMock.Net.StandAlone;
using WireMock.Settings;
@@ -42,6 +43,12 @@ namespace WireMock.Net.WebApplication
{
_logger.LogError(formatString, args);
}
public void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminrequest)
{
string message = JsonConvert.SerializeObject(logEntryModel, Formatting.Indented);
_logger.LogDebug("Admin[{0}] {1}", isAdminrequest, message);
}
}
public WireMockService(ILogger logger, IFluentMockServerSettings settings)

View File

@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Lightweight StandAlone Http Mocking Server for .Net.</Description>
<AssemblyTitle>WireMock.Net.StandAlone</AssemblyTitle>
<Version>1.0.3.18</Version>
<Version>1.0.4.3</Version>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

View File

@@ -11,14 +11,14 @@
public string Name { get; set; }
/// <summary>
/// Gets or sets the pattern.
/// Gets or sets the pattern. Can be a string (default) or an object;
/// </summary>
public string Pattern { get; set; }
public object Pattern { get; set; }
/// <summary>
/// Gets or sets the patterns.
/// Gets or sets the patterns. Can be array of strings (default) or an array of objects;
/// </summary>
public string[] Patterns { get; set; }
public object[] Patterns { get; set; }
/// <summary>
/// Gets or sets the ignore case.

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
// using System.Collections.Generic;
namespace WireMock.Admin.Mappings
{
@@ -12,10 +12,15 @@ namespace WireMock.Admin.Mappings
/// </summary>
public string Name { get; set; }
///// <summary>
///// Gets or sets the values.
///// </summary>
//public IList<string> Values { get; set; }
/// <summary>
/// Gets or sets the values.
/// Gets or sets the matchers.
/// </summary>
public IList<string> Values { get; set; }
public MatcherModel[] Matchers { get; set; }
///// <summary>
///// Gets or sets the functions.

View File

@@ -0,0 +1,20 @@
using System;
namespace WireMock.Admin.Mappings
{
/// <summary>
/// Status
/// </summary>
public class StatusModel
{
/// <summary>
/// The optional guid.
/// </summary>
public Guid? Guid { get; set; }
/// <summary>
/// The status (can also contain the error message).
/// </summary>
public string Status { get; set; }
}
}

View File

@@ -33,7 +33,7 @@ namespace WireMock.Client
/// <param name="settings">SettingsModel</param>
[Put("__admin/settings")]
[Header("Content-Type", "application/json")]
Task<string> PutSettingsAsync([Body] SettingsModel settings);
Task<StatusModel> PutSettingsAsync([Body] SettingsModel settings);
/// <summary>
/// Update the settings
@@ -41,7 +41,7 @@ namespace WireMock.Client
/// <param name="settings">SettingsModel</param>
[Post("__admin/settings")]
[Header("Content-Type", "application/json")]
Task<string> PostSettingsAsync([Body] SettingsModel settings);
Task<StatusModel> PostSettingsAsync([Body] SettingsModel settings);
/// <summary>
/// Get the mappings.
@@ -56,19 +56,19 @@ namespace WireMock.Client
/// <param name="mapping">MappingModel</param>
[Post("__admin/mappings")]
[Header("Content-Type", "application/json")]
Task<string> PostMappingAsync([Body] MappingModel mapping);
Task<StatusModel> PostMappingAsync([Body] MappingModel mapping);
/// <summary>
/// Delete all mappings.
/// </summary>
[Delete("__admin/mappings")]
Task<string> DeleteMappingsAsync();
Task<StatusModel> DeleteMappingsAsync();
/// <summary>
/// Delete (reset) all mappings.
/// </summary>
[Post("__admin/mappings/reset")]
Task<string> ResetMappingsAsync();
Task<StatusModel> ResetMappingsAsync();
/// <summary>
/// Get a mapping based on the guid
@@ -84,20 +84,20 @@ namespace WireMock.Client
/// <param name="guid">The Guid</param>
/// <param name="mapping">MappingModel</param>
[Put("__admin/mappings/{guid}")]
Task<string> PutMappingAsync([Path] Guid guid, [Body] MappingModel mapping);
Task<StatusModel> PutMappingAsync([Path] Guid guid, [Body] MappingModel mapping);
/// <summary>
/// Delete a mapping based on the guid
/// </summary>
/// <param name="guid">The Guid</param>
[Delete("__admin/mappings/{guid}")]
Task<string> DeleteMappingAsync([Path] Guid guid);
Task<StatusModel> DeleteMappingAsync([Path] Guid guid);
/// <summary>
/// Save the mappings
/// </summary>
[Post("__admin/mappings/save")]
Task<string> SaveMappingAsync();
Task<StatusModel> SaveMappingAsync();
/// <summary>
/// Get the requests.
@@ -110,13 +110,13 @@ namespace WireMock.Client
/// Delete all requests.
/// </summary>
[Delete("__admin/requests")]
Task<string> DeleteRequestsAsync();
Task<StatusModel> DeleteRequestsAsync();
/// <summary>
/// Delete (reset) all requests.
/// </summary>
[Post("__admin/requests/reset")]
Task<string> ResetRequestsAsync();
Task<StatusModel> ResetRequestsAsync();
/// <summary>
/// Get a request based on the guid
@@ -131,7 +131,7 @@ namespace WireMock.Client
/// </summary>
/// <param name="guid">The Guid</param>
[Delete("__admin/requests/{guid}")]
Task<string> DeleteRequestAsync([Path] Guid guid);
Task<StatusModel> DeleteRequestAsync([Path] Guid guid);
/// <summary>
/// Find a request based on the criteria
@@ -151,12 +151,12 @@ namespace WireMock.Client
/// Delete (reset) all scenarios
/// </summary>
[Delete("__admin/scenarios")]
Task<string> DeleteScenariosAsync();
Task<StatusModel> DeleteScenariosAsync();
/// <summary>
/// Delete (reset) all scenarios
/// </summary>
[Post("__admin/scenarios")]
Task<string> ResetScenariosAsync();
Task<StatusModel> ResetScenariosAsync();
}
}

View File

@@ -1,4 +1,5 @@
using JetBrains.Annotations;
using WireMock.Admin.Requests;
namespace WireMock.Logging
{
@@ -43,5 +44,13 @@ namespace WireMock.Logging
[PublicAPI]
[StringFormatMethod("formatString")]
void Error([NotNull] string formatString, [NotNull] params object[] args);
/// <summary>
/// Writes the LogEntryModel (LogRequestModel, LogResponseModel and more).
/// </summary>
/// <param name="logEntryModel">The Request Log Model.</param>
/// <param name="isAdminrequest">Defines if this request is an admin request.</param>
[PublicAPI]
void DebugRequestResponse([NotNull] LogEntryModel logEntryModel, bool isAdminrequest);
}
}

View File

@@ -1,4 +1,6 @@
using System;
using Newtonsoft.Json;
using WireMock.Admin.Requests;
namespace WireMock.Logging
{
@@ -8,6 +10,14 @@ namespace WireMock.Logging
/// <seealso cref="IWireMockLogger" />
public class WireMockConsoleLogger : IWireMockLogger
{
/// <summary>
/// Initializes a new instance of the <see cref="WireMockConsoleLogger"/> class.
/// </summary>
public WireMockConsoleLogger()
{
Console.OutputEncoding = System.Text.Encoding.UTF8;
}
/// <see cref="IWireMockLogger.Debug"/>
public void Debug(string formatString, params object[] args)
{
@@ -32,9 +42,16 @@ namespace WireMock.Logging
Console.WriteLine(Format("Error", formatString, args));
}
/// <see cref="IWireMockLogger.DebugRequestResponse"/>
public void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminRequest)
{
string message = JsonConvert.SerializeObject(logEntryModel, Formatting.Indented);
Console.WriteLine(Format("DebugRequestResponse", "Admin[{0}] {1}", isAdminRequest, message));
}
private static string Format(string level, string formatString, params object[] args)
{
string message = string.Format(formatString, args);
var message = args.Length > 0 ? string.Format(formatString, args) : formatString;
return $"{DateTime.UtcNow} [{level}] : {message}";
}

View File

@@ -1,4 +1,6 @@
namespace WireMock.Logging
using WireMock.Admin.Requests;
namespace WireMock.Logging
{
/// <summary>
/// WireMockNullLogger which does not log.
@@ -25,5 +27,10 @@
public void Error(string formatString, params object[] args)
{
}
/// <see cref="IWireMockLogger.DebugRequestResponse"/>
public void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminRequest)
{
}
}
}

View File

@@ -5,7 +5,7 @@ using WireMock.Validation;
namespace WireMock.Matchers
{
/// <summary>
/// ExactMatcher
/// ExactObjectMatcher
/// </summary>
/// <seealso cref="IObjectMatcher" />
public class ExactObjectMatcher : IObjectMatcher
@@ -17,7 +17,7 @@ namespace WireMock.Matchers
public MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher([NotNull] object value) : this(MatchBehaviour.AcceptOnMatch, value)
@@ -25,7 +25,7 @@ namespace WireMock.Matchers
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value.</param>
@@ -38,7 +38,7 @@ namespace WireMock.Matchers
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher([NotNull] byte[] value) : this(MatchBehaviour.AcceptOnMatch, value)
@@ -46,7 +46,7 @@ namespace WireMock.Matchers
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value.</param>

View File

@@ -10,7 +10,6 @@
/// </summary>
string Name { get; }
/// <summary>
/// Gets the match behaviour.
/// </summary>

View File

@@ -0,0 +1,15 @@
namespace WireMock.Matchers
{
/// <summary>
/// IValueMatcher
/// </summary>
/// <seealso cref="IObjectMatcher" />
public interface IValueMatcher: IObjectMatcher
{
/// <summary>
/// Gets the value (can be a string or an obejct).
/// </summary>
/// <returns>Value</returns>
object Value { get; }
}
}

View File

@@ -10,6 +10,7 @@ namespace WireMock.Matchers
/// JsonPathMatcher
/// </summary>
/// <seealso cref="IMatcher" />
/// <seealso cref="IObjectMatcher" />
public class JsonPathMatcher : IStringMatcher, IObjectMatcher
{
private readonly string[] _patterns;
@@ -91,9 +92,9 @@ namespace WireMock.Matchers
private double IsMatch(JToken jtoken)
{
// Wrap in array if needed
JToken jarray = jtoken is JArray ? jtoken : new JArray(jtoken);
JToken tokenOrArray = jtoken is JArray ? jtoken : new JArray(jtoken);
return MatchScores.ToScore(_patterns.Select(pattern => jarray.SelectToken(pattern) != null));
return MatchScores.ToScore(_patterns.Select(pattern => tokenOrArray.SelectToken(pattern) != null));
}
}
}

View File

@@ -0,0 +1,92 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Validation;
namespace WireMock.Matchers
{
/// <summary>
/// JsonMatcher
/// </summary>
public class JsonMatcher : IValueMatcher
{
/// <inheritdoc cref="IValueMatcher.Value"/>
public object Value { get; }
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JsonMatcher";
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="value">The string value to check for equality.</param>
public JsonMatcher([NotNull] string value) : this(MatchBehaviour.AcceptOnMatch, value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="value">The object value to check for equality.</param>
public JsonMatcher([NotNull] object value) : this(MatchBehaviour.AcceptOnMatch, value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The string value to check for equality.</param>
public JsonMatcher(MatchBehaviour matchBehaviour, [NotNull] string value)
{
Check.NotNull(value, nameof(value));
MatchBehaviour = matchBehaviour;
Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The object value to check for equality.</param>
public JsonMatcher(MatchBehaviour matchBehaviour, [NotNull] object value)
{
Check.NotNull(value, nameof(value));
MatchBehaviour = matchBehaviour;
Value = value;
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input)
{
bool match = false;
if (input != null)
{
try
{
// Check if JToken or object
JToken jtokenInput = input is JToken tokenInput ? tokenInput : JObject.FromObject(input);
// Check if JToken or string or object
JToken jtokenValue =
Value is JToken tokenValue ? tokenValue :
Value is string stringValue ? JToken.Parse(stringValue) :
JObject.FromObject(input);
match = JToken.DeepEquals(jtokenValue, jtokenInput);
}
catch (JsonException)
{
// just ignore JsonException
}
}
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
}
}
}

View File

@@ -25,16 +25,16 @@ namespace WireMock.Matchers.Request
public string Key { get; }
/// <summary>
/// The values
/// The matchers.
/// </summary>
public IEnumerable<string> Values { get; }
public IReadOnlyList<IStringMatcher> Matchers { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="key">The key.</param>
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key) : this(matchBehaviour, key, null)
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key) : this(matchBehaviour, key, (IStringMatcher[])null)
{
}
@@ -44,13 +44,23 @@ namespace WireMock.Matchers.Request
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="key">The key.</param>
/// <param name="values">The values.</param>
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key, [CanBeNull] IEnumerable<string> values)
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key, [CanBeNull] string[] values) : this(matchBehaviour, key, values?.Select(value => new ExactMatcher(matchBehaviour, value)).Cast<IStringMatcher>().ToArray())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="key">The key.</param>
/// <param name="matchers">The matchers.</param>
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key, [CanBeNull] IStringMatcher[] matchers)
{
Check.NotNull(key, nameof(key));
_matchBehaviour = matchBehaviour;
Key = key;
Values = values;
Matchers = matchers;
}
/// <summary>
@@ -78,21 +88,33 @@ namespace WireMock.Matchers.Request
return MatchScores.ToScore(requestMessage.Query != null && Funcs.Any(f => f(requestMessage.Query)));
}
var values = requestMessage.GetParameter(Key);
if (values == null)
WireMockList<string> valuesPresentInRequestMessage = requestMessage.GetParameter(Key);
if (valuesPresentInRequestMessage == null)
{
// Key is not present, just return Mismatch
// Key is not present at all, just return Mismatch
return MatchScores.Mismatch;
}
if (values.Count == 0 && (Values == null || !Values.Any()))
if (Matchers != null && Matchers.Any())
{
// Key is present, but no values or null, just return Perfect
// Matchers are defined, just use the matchers to calculate the match score.
var scores = new List<double>();
foreach (string valuePresentInRequestMessage in valuesPresentInRequestMessage)
{
double score = Matchers.Max(m => m.IsMatch(valuePresentInRequestMessage));
scores.Add(score);
}
return scores.Any() ? scores.Average() : MatchScores.Mismatch;
}
if (Matchers == null || !Matchers.Any())
{
// Matchers are null or not defined, and Key is present, just return Perfect.
return MatchScores.Perfect;
}
var matches = Values.Select(v => values.Contains(v));
return MatchScores.ToScore(matches);
return MatchScores.Mismatch;
}
}
}

View File

@@ -110,7 +110,7 @@ namespace WireMock.Owin
_host.Run(_cts.Token);
#else
_logger.Info("WireMock.Net server using netstandard2.0");
_host.Run();
_host.RunAsync(_cts.Token).Wait();
#endif
}
catch (Exception e)

View File

@@ -7,6 +7,7 @@ using WireMock.Matchers;
using WireMock.Util;
using Newtonsoft.Json;
using WireMock.Http;
using WireMock.Serialization;
#if !NETSTANDARD
using Microsoft.Owin;
#else
@@ -58,7 +59,7 @@ namespace WireMock.Owin
// Set start
if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState)
{
_options.Scenarios.Add(mapping.Scenario, null);
_options.Scenarios.TryAdd(mapping.Scenario, null);
}
}
@@ -153,6 +154,8 @@ namespace WireMock.Owin
private void LogRequest(LogEntry entry, bool addRequest)
{
_options.Logger.DebugRequestResponse(LogEntryMapper.Map(entry), entry.RequestMessage.Path.StartsWith("/__admin/"));
if (addRequest)
{
_options.LogEntries.Add(entry);

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using WireMock.Logging;
using WireMock.Matchers;
@@ -23,7 +22,9 @@ namespace WireMock.Owin
public bool AllowPartialMapping { get; set; }
public IDictionary<Guid, Mapping> Mappings { get; } = new ConcurrentDictionary<Guid, Mapping>();
public ConcurrentDictionary<Guid, Mapping> Mappings { get; } = new ConcurrentDictionary<Guid, Mapping>(); // Checked
public ConcurrentDictionary<string, object> Scenarios { get; } = new ConcurrentDictionary<string, object>(); // Checked
public ObservableCollection<LogEntry> LogEntries { get; } = new ConcurentObservableCollection<LogEntry>();
@@ -31,8 +32,6 @@ 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; }

View File

@@ -27,6 +27,14 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithParam([NotNull] string key, [CanBeNull] params string[] values);
/// <summary>
/// WithParam: matching on key and matchers.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithParam([NotNull] string key, [CanBeNull] params IStringMatcher[] matchers);
/// <summary>
/// WithParam: matching on key, values and matchBehaviour.
/// </summary>
@@ -36,6 +44,15 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithParam([NotNull] string key, MatchBehaviour matchBehaviour, [CanBeNull] params string[] values);
/// <summary>
/// WithParam: matching on key, matchers and matchBehaviour.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="matchers">The matchers.</param>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithParam([NotNull] string key, MatchBehaviour matchBehaviour, [CanBeNull] params IStringMatcher[] matchers);
/// <summary>
/// WithParam: matching on functions.
/// </summary>

View File

@@ -306,6 +306,12 @@ namespace WireMock.RequestBuilders
return WithParam(key, MatchBehaviour.AcceptOnMatch, values);
}
/// <inheritdoc cref="IParamsRequestBuilder.WithParam(string, IStringMatcher[])"/>
public IRequestBuilder WithParam(string key, params IStringMatcher[] matchers)
{
return WithParam(key, MatchBehaviour.AcceptOnMatch, matchers);
}
/// <inheritdoc cref="IParamsRequestBuilder.WithParam(string, MatchBehaviour, string[])"/>
public IRequestBuilder WithParam(string key, MatchBehaviour matchBehaviour, params string[] values)
{
@@ -315,6 +321,15 @@ namespace WireMock.RequestBuilders
return this;
}
/// <inheritdoc cref="IParamsRequestBuilder.WithParam(string, MatchBehaviour, IStringMatcher[])"/>
public IRequestBuilder WithParam(string key, MatchBehaviour matchBehaviour, params IStringMatcher[] matchers)
{
Check.NotNull(key, nameof(key));
_requestMatchers.Add(new RequestMessageParamMatcher(matchBehaviour, key, matchers));
return this;
}
/// <inheritdoc cref="IParamsRequestBuilder.WithParam(Func{IDictionary{string, WireMockList{string}}, bool}[])"/>
public IRequestBuilder WithParam(params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs)
{

View File

@@ -1,5 +1,4 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WireMock.Util;
@@ -8,14 +7,14 @@ using WireMock.Validation;
namespace WireMock
{
/// <summary>
/// The response.
/// The ResponseMessage.
/// </summary>
public class ResponseMessage
{
/// <summary>
/// Gets the headers.
/// </summary>
public IDictionary<string, WireMockList<string>> Headers { get; set; } = new ConcurrentDictionary<string, WireMockList<string>>();
public IDictionary<string, WireMockList<string>> Headers { get; set; } = new Dictionary<string, WireMockList<string>>();
/// <summary>
/// Gets or sets the status code.

View File

@@ -0,0 +1,70 @@
using System.Linq;
using WireMock.Admin.Mappings;
using WireMock.Admin.Requests;
using WireMock.Logging;
namespace WireMock.Serialization
{
internal static class LogEntryMapper
{
public static LogEntryModel Map(LogEntry logEntry)
{
return new LogEntryModel
{
Guid = logEntry.Guid,
Request = new LogRequestModel
{
DateTime = logEntry.RequestMessage.DateTime,
ClientIP = logEntry.RequestMessage.ClientIP,
Path = logEntry.RequestMessage.Path,
AbsoluteUrl = logEntry.RequestMessage.Url,
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
{
EncodingName = logEntry.RequestMessage.BodyEncoding.EncodingName,
CodePage = logEntry.RequestMessage.BodyEncoding.CodePage,
WebName = logEntry.RequestMessage.BodyEncoding.WebName
} : null
},
Response = new LogResponseModel
{
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,
BodyAsFileIsCached = logEntry.ResponseMessage.BodyAsFileIsCached,
Headers = logEntry.ResponseMessage.Headers,
BodyEncoding = logEntry.ResponseMessage.BodyEncoding != null ? new EncodingModel
{
EncodingName = logEntry.ResponseMessage.BodyEncoding.EncodingName,
CodePage = logEntry.ResponseMessage.BodyEncoding.CodePage,
WebName = logEntry.ResponseMessage.BodyEncoding.WebName
} : null
},
MappingGuid = logEntry.MappingGuid,
MappingTitle = logEntry.MappingTitle,
RequestMatchResult = logEntry.RequestMatchResult != null ? new LogRequestMatchModel
{
TotalScore = logEntry.RequestMatchResult.TotalScore,
TotalNumber = logEntry.RequestMatchResult.TotalNumber,
IsPerfectMatch = logEntry.RequestMatchResult.IsPerfectMatch,
AverageTotalScore = logEntry.RequestMatchResult.AverageTotalScore,
MatchDetails = logEntry.RequestMatchResult.MatchDetails.Select(x => new
{
Name = x.Key.Name.Replace("RequestMessage", string.Empty),
Score = x.Value
} as object).ToList()
} : null
};
}
}
}

View File

@@ -71,7 +71,7 @@ namespace WireMock.Serialization
Params = paramsMatchers != null && paramsMatchers.Any() ? paramsMatchers.Select(pm => new ParamModel
{
Name = pm.Key,
Values = pm.Values?.ToList()
Matchers = MatcherMapper.Map(pm.Matchers)
//Funcs = Map(pm.Funcs)
}).ToList() : null,
@@ -116,7 +116,7 @@ namespace WireMock.Serialization
mappingModel.Response.BodyAsFileIsCached = response.ResponseMessage.BodyAsFileIsCached;
mappingModel.Response.UseTransformer = response.UseTransformer;
if (response.ResponseMessage.BodyEncoding != null)
if (response.ResponseMessage.BodyEncoding != null && response.ResponseMessage.BodyEncoding.WebName != "utf-8")
{
mappingModel.Response.BodyEncoding = new EncodingModel
{
@@ -132,7 +132,7 @@ namespace WireMock.Serialization
private static IDictionary<string, object> Map(IDictionary<string, WireMockList<string>> dictionary)
{
if (dictionary == null)
if (dictionary == null || dictionary.Count == 0)
{
return null;
}

View File

@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using SimMetrics.Net;
using WireMock.Admin.Mappings;
using WireMock.Matchers;
@@ -8,6 +10,54 @@ namespace WireMock.Serialization
{
internal static class MatcherMapper
{
public static IMatcher Map([CanBeNull] MatcherModel matcher)
{
if (matcher == null)
{
return null;
}
string[] parts = matcher.Name.Split('.');
string matcherName = parts[0];
string matcherType = parts.Length > 1 ? parts[1] : null;
string[] stringPatterns = matcher.Patterns != null ? matcher.Patterns.Cast<string>().ToArray() : new [] { matcher.Pattern as string };
MatchBehaviour matchBehaviour = matcher.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch;
switch (matcherName)
{
case "ExactMatcher":
return new ExactMatcher(matchBehaviour, stringPatterns);
case "RegexMatcher":
return new RegexMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true);
case "JsonMatcher":
return new JsonMatcher(matchBehaviour, matcher.Pattern);
case "JsonPathMatcher":
return new JsonPathMatcher(matchBehaviour, stringPatterns);
case "XPathMatcher":
return new XPathMatcher(matchBehaviour, (string) matcher.Pattern);
case "WildcardMatcher":
return new WildcardMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true);
case "SimMetricsMatcher":
SimMetricType type = SimMetricType.Levenstein;
if (!string.IsNullOrEmpty(matcherType) && !Enum.TryParse(matcherType, out type))
{
throw new NotSupportedException($"Matcher '{matcherName}' with Type '{matcherType}' is not supported.");
}
return new SimMetricsMatcher(matchBehaviour, (string) matcher.Pattern, type);
default:
throw new NotSupportedException($"Matcher '{matcherName}' is not supported.");
}
}
public static MatcherModel[] Map([CanBeNull] IEnumerable<IMatcher> matchers)
{
return matchers?.Select(Map).Where(x => x != null).ToArray();
@@ -20,9 +70,15 @@ namespace WireMock.Serialization
return null;
}
string[] patterns = matcher is IStringMatcher stringMatcher ? stringMatcher.GetPatterns() : new string[0];
// If the matcher is a IStringMatcher, get the patterns.
// If the matcher is a IValueMatcher, get the value (can be string or object).
// Else empty array
object[] patterns = matcher is IStringMatcher stringMatcher ?
stringMatcher.GetPatterns().Cast<object>().ToArray() :
matcher is IValueMatcher valueMatcher ? new[] { valueMatcher.Value } :
new object[0];
bool? ignorecase = matcher is IIgnoreCaseMatcher ignoreCaseMatcher ? ignoreCaseMatcher.IgnoreCase : (bool?)null;
bool? rejectOnMatch = matcher.MatchBehaviour == MatchBehaviour.RejectOnMatch ? true : (bool?) null;
bool? rejectOnMatch = matcher.MatchBehaviour == MatchBehaviour.RejectOnMatch ? true : (bool?)null;
return new MatcherModel
{

View File

@@ -1,56 +0,0 @@
using System;
using JetBrains.Annotations;
using SimMetrics.Net;
using WireMock.Admin.Mappings;
using WireMock.Matchers;
namespace WireMock.Serialization
{
internal static class MatcherModelMapper
{
public static IMatcher Map([CanBeNull] MatcherModel matcher)
{
if (matcher == null)
{
return null;
}
string[] parts = matcher.Name.Split('.');
string matcherName = parts[0];
string matcherType = parts.Length > 1 ? parts[1] : null;
string[] patterns = matcher.Patterns ?? new[] { matcher.Pattern };
MatchBehaviour matchBehaviour = matcher.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch;
switch (matcherName)
{
case "ExactMatcher":
return new ExactMatcher(matchBehaviour, patterns);
case "RegexMatcher":
return new RegexMatcher(matchBehaviour, patterns, matcher.IgnoreCase == true);
case "JsonPathMatcher":
return new JsonPathMatcher(matchBehaviour, patterns);
case "XPathMatcher":
return new XPathMatcher(matchBehaviour, matcher.Pattern);
case "WildcardMatcher":
return new WildcardMatcher(matchBehaviour, patterns, matcher.IgnoreCase == true);
case "SimMetricsMatcher":
SimMetricType type = SimMetricType.Levenstein;
if (!string.IsNullOrEmpty(matcherType) && !Enum.TryParse(matcherType, out type))
{
throw new NotSupportedException($"Matcher '{matcherName}' with Type '{matcherType}' is not supported.");
}
return new SimMetricsMatcher(matchBehaviour, matcher.Pattern, type);
default:
throw new NotSupportedException($"Matcher '{matcherName}' is not supported.");
}
}
}
}

View File

@@ -9,7 +9,6 @@ using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Admin.Mappings;
using WireMock.Admin.Requests;
using WireMock.Admin.Settings;
using WireMock.Http;
using WireMock.Logging;
@@ -38,6 +37,7 @@ namespace WireMock.Server
private const string AdminScenarios = "/__admin/scenarios";
private readonly RegexMatcher _adminMappingsGuidPathMatcher = new RegexMatcher(MatchBehaviour.AcceptOnMatch, @"^\/__admin\/mappings\/(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$");
private readonly RegexMatcher _adminRequestsGuidPathMatcher = new RegexMatcher(MatchBehaviour.AcceptOnMatch, @"^\/__admin\/requests\/(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$");
private readonly IDictionary<string, WireMockList<string>> _contentTypeJsonHeaders = new Dictionary<string, WireMockList<string>> { { HttpKnownHeaderNames.ContentType, new WireMockList<string> { ContentTypeJson } } };
private readonly JsonSerializerSettings _settings = new JsonSerializerSettings
{
@@ -210,7 +210,7 @@ namespace WireMock.Server
if (settings.SaveMapping)
{
var mapping = ToMapping(requestMessage, responseMessage, settings.BlackListedHeaders ?? new string[] { });
_options.Mappings.Add(mapping.Guid, mapping);
_options.Mappings.TryAdd(mapping.Guid, mapping);
if (settings.SaveMappingToFile)
{
@@ -239,7 +239,11 @@ namespace WireMock.Server
}
});
if (requestMessage.Body != null)
if (requestMessage.BodyAsJson != null)
{
request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyAsJson));
}
else if (requestMessage.Body != null)
{
request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.Body));
}
@@ -280,7 +284,7 @@ namespace WireMock.Server
_options.RequestProcessingDelay = TimeSpan.FromMilliseconds(settings.GlobalProcessingDelay.Value);
}
return new ResponseMessage { Body = "Settings updated" };
return CreateResponseMessage("Settings updated");
}
#endregion Settings
@@ -293,7 +297,7 @@ namespace WireMock.Server
if (mapping == null)
{
_logger.Warn("HttpStatusCode set to 404 : Mapping not found");
return new ResponseMessage { StatusCode = 404, Body = "Mapping not found" };
return CreateResponseMessage("Mapping not found", 404);
}
var model = MappingConverter.ToMappingModel(mapping);
@@ -308,7 +312,7 @@ namespace WireMock.Server
var mappingModel = DeserializeObject<MappingModel>(requestMessage);
DeserializeAndAddOrUpdateMapping(mappingModel, guid);
return new ResponseMessage { Body = "Mapping added or updated" };
return CreateResponseMessage("Mapping added or updated", 200, guid);
}
private ResponseMessage MappingDelete(RequestMessage requestMessage)
@@ -317,10 +321,10 @@ namespace WireMock.Server
if (DeleteMapping(guid))
{
return new ResponseMessage { Body = "Mapping removed" };
return CreateResponseMessage("Mapping removed", 200, guid);
}
return new ResponseMessage { Body = "Mapping not found" };
return CreateResponseMessage("Mapping not found", 404);
}
#endregion Mapping/{guid}
@@ -332,7 +336,7 @@ namespace WireMock.Server
SaveMappingToFile(mapping);
}
return new ResponseMessage { Body = "Mappings saved to disk" };
return CreateResponseMessage("Mappings saved to disk");
}
private void SaveMappingToFile(Mapping mapping)
@@ -371,26 +375,27 @@ namespace WireMock.Server
private ResponseMessage MappingsPost(RequestMessage requestMessage)
{
Guid? guid;
try
{
var mappingModel = DeserializeObject<MappingModel>(requestMessage);
DeserializeAndAddOrUpdateMapping(mappingModel);
guid = DeserializeAndAddOrUpdateMapping(mappingModel);
}
catch (ArgumentException a)
{
_logger.Error("HttpStatusCode set to 400 {0}", a);
return new ResponseMessage { StatusCode = 400, Body = a.Message };
return CreateResponseMessage(a.Message, 400);
}
catch (Exception e)
{
_logger.Error("HttpStatusCode set to 500 {0}", e);
return new ResponseMessage { StatusCode = 500, Body = e.ToString() };
return CreateResponseMessage(e.ToString(), 500);
}
return new ResponseMessage { StatusCode = 201, Body = "Mapping added" };
return CreateResponseMessage("Mapping added", 201, guid);
}
private void DeserializeAndAddOrUpdateMapping(MappingModel mappingModel, Guid? guid = null, string path = null)
private Guid DeserializeAndAddOrUpdateMapping(MappingModel mappingModel, Guid? guid = null, string path = null)
{
Check.NotNull(mappingModel, nameof(mappingModel));
Check.NotNull(mappingModel.Request, nameof(mappingModel.Request));
@@ -399,7 +404,7 @@ namespace WireMock.Server
var requestBuilder = InitRequestBuilder(mappingModel.Request);
var responseBuilder = InitResponseBuilder(mappingModel.Response);
IRespondWithAProvider respondProvider = Given(requestBuilder);
var respondProvider = Given(requestBuilder);
if (guid != null)
{
@@ -433,6 +438,8 @@ namespace WireMock.Server
}
respondProvider.RespondWith(responseBuilder);
return respondProvider.Guid;
}
private ResponseMessage MappingsDelete(RequestMessage requestMessage)
@@ -441,7 +448,7 @@ namespace WireMock.Server
ResetScenarios();
return new ResponseMessage { Body = "Mappings deleted" };
return CreateResponseMessage("Mappings deleted");
}
#endregion Mappings
@@ -454,10 +461,10 @@ namespace WireMock.Server
if (entry == null)
{
_logger.Warn("HttpStatusCode set to 404 : Request not found");
return new ResponseMessage { StatusCode = 404, Body = "Request not found" };
return CreateResponseMessage("Request not found", 404);
}
var model = ToLogEntryModel(entry);
var model = LogEntryMapper.Map(entry);
return ToJson(model);
}
@@ -467,9 +474,11 @@ namespace WireMock.Server
Guid guid = Guid.Parse(requestMessage.Path.Substring(AdminRequests.Length + 1));
if (DeleteLogEntry(guid))
return new ResponseMessage { Body = "Request removed" };
{
return CreateResponseMessage("Request removed");
}
return new ResponseMessage { Body = "Request not found" };
return CreateResponseMessage("Request not found", 404);
}
#endregion Request/{guid}
@@ -478,76 +487,16 @@ namespace WireMock.Server
{
var result = LogEntries
.Where(r => !r.RequestMessage.Path.StartsWith("/__admin/"))
.Select(ToLogEntryModel);
.Select(LogEntryMapper.Map);
return ToJson(result);
}
private LogEntryModel ToLogEntryModel(LogEntry logEntry)
{
return new LogEntryModel
{
Guid = logEntry.Guid,
Request = new LogRequestModel
{
DateTime = logEntry.RequestMessage.DateTime,
ClientIP = logEntry.RequestMessage.ClientIP,
Path = logEntry.RequestMessage.Path,
AbsoluteUrl = logEntry.RequestMessage.Url,
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
{
EncodingName = logEntry.RequestMessage.BodyEncoding.EncodingName,
CodePage = logEntry.RequestMessage.BodyEncoding.CodePage,
WebName = logEntry.RequestMessage.BodyEncoding.WebName
} : null
},
Response = new LogResponseModel
{
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,
BodyAsFileIsCached = logEntry.ResponseMessage.BodyAsFileIsCached,
Headers = logEntry.ResponseMessage.Headers,
BodyEncoding = logEntry.ResponseMessage.BodyEncoding != null ? new EncodingModel
{
EncodingName = logEntry.ResponseMessage.BodyEncoding.EncodingName,
CodePage = logEntry.ResponseMessage.BodyEncoding.CodePage,
WebName = logEntry.ResponseMessage.BodyEncoding.WebName
} : null
},
MappingGuid = logEntry.MappingGuid,
MappingTitle = logEntry.MappingTitle,
RequestMatchResult = logEntry.RequestMatchResult != null ? new LogRequestMatchModel
{
TotalScore = logEntry.RequestMatchResult.TotalScore,
TotalNumber = logEntry.RequestMatchResult.TotalNumber,
IsPerfectMatch = logEntry.RequestMatchResult.IsPerfectMatch,
AverageTotalScore = logEntry.RequestMatchResult.AverageTotalScore,
MatchDetails = logEntry.RequestMatchResult.MatchDetails.Select(x => new
{
Name = x.Key.Name.Replace("RequestMessage", string.Empty),
Score = x.Value
} as object).ToList()
} : null
};
}
private ResponseMessage RequestsDelete(RequestMessage requestMessage)
{
ResetLogEntries();
return new ResponseMessage { Body = "Requests deleted" };
return CreateResponseMessage("Requests deleted");
}
#endregion Requests
@@ -568,7 +517,7 @@ namespace WireMock.Server
}
}
var result = dict.OrderBy(x => x.Value.AverageTotalScore).Select(x => x.Key).Select(ToLogEntryModel);
var result = dict.OrderBy(x => x.Value.AverageTotalScore).Select(x => x.Key).Select(LogEntryMapper.Map);
return ToJson(result);
}
@@ -577,7 +526,7 @@ namespace WireMock.Server
#region Scenarios
private ResponseMessage ScenariosGet(RequestMessage requestMessage)
{
var scenarios = Scenarios.Select(s => new
var scenarios = Scenarios.ToArray().Select(s => new
{
Name = s.Key,
Started = s.Value != null,
@@ -590,7 +539,7 @@ namespace WireMock.Server
{
ResetScenarios();
return new ResponseMessage { Body = "Scenarios reset" };
return CreateResponseMessage("Scenarios reset");
}
#endregion
@@ -609,7 +558,7 @@ namespace WireMock.Server
var clientIPModel = JsonUtils.ParseJTokenToObject<ClientIPModel>(requestModel.ClientIP);
if (clientIPModel?.Matchers != null)
{
requestBuilder = requestBuilder.WithPath(clientIPModel.Matchers.Select(MatcherModelMapper.Map).Cast<IStringMatcher>().ToArray());
requestBuilder = requestBuilder.WithPath(clientIPModel.Matchers.Select(MatcherMapper.Map).Cast<IStringMatcher>().ToArray());
}
}
}
@@ -625,7 +574,7 @@ namespace WireMock.Server
var pathModel = JsonUtils.ParseJTokenToObject<PathModel>(requestModel.Path);
if (pathModel?.Matchers != null)
{
requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(MatcherModelMapper.Map).Cast<IStringMatcher>().ToArray());
requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(MatcherMapper.Map).Cast<IStringMatcher>().ToArray());
}
}
}
@@ -641,7 +590,7 @@ namespace WireMock.Server
var urlModel = JsonUtils.ParseJTokenToObject<UrlModel>(requestModel.Url);
if (urlModel?.Matchers != null)
{
requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(MatcherModelMapper.Map).Cast<IStringMatcher>().ToArray());
requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(MatcherMapper.Map).Cast<IStringMatcher>().ToArray());
}
}
}
@@ -655,7 +604,7 @@ namespace WireMock.Server
{
foreach (var headerModel in requestModel.Headers.Where(h => h.Matchers != null))
{
requestBuilder = requestBuilder.WithHeader(headerModel.Name, headerModel.Matchers.Select(MatcherModelMapper.Map).Cast<IStringMatcher>().ToArray());
requestBuilder = requestBuilder.WithHeader(headerModel.Name, headerModel.Matchers.Select(MatcherMapper.Map).Cast<IStringMatcher>().ToArray());
}
}
@@ -663,21 +612,21 @@ namespace WireMock.Server
{
foreach (var cookieModel in requestModel.Cookies.Where(c => c.Matchers != null))
{
requestBuilder = requestBuilder.WithCookie(cookieModel.Name, cookieModel.Matchers.Select(MatcherModelMapper.Map).Cast<IStringMatcher>().ToArray());
requestBuilder = requestBuilder.WithCookie(cookieModel.Name, cookieModel.Matchers.Select(MatcherMapper.Map).Cast<IStringMatcher>().ToArray());
}
}
if (requestModel.Params != null)
{
foreach (var paramModel in requestModel.Params)
foreach (var paramModel in requestModel.Params.Where(c => c.Matchers != null))
{
requestBuilder = paramModel.Values == null ? requestBuilder.WithParam(paramModel.Name) : requestBuilder.WithParam(paramModel.Name, paramModel.Values.ToArray());
requestBuilder = requestBuilder.WithParam(paramModel.Name, paramModel.Matchers.Select(MatcherMapper.Map).Cast<IStringMatcher>().ToArray());
}
}
if (requestModel.Body?.Matcher != null)
{
var bodyMatcher = MatcherModelMapper.Map(requestModel.Body.Matcher);
var bodyMatcher = MatcherMapper.Map(requestModel.Body.Matcher);
requestBuilder = requestBuilder.WithBody(bodyMatcher);
}
@@ -779,5 +728,17 @@ namespace WireMock.Server
JsonConvert.DeserializeObject<T>(requestMessage.Body) :
((JObject)requestMessage.BodyAsJson).ToObject<T>();
}
private ResponseMessage CreateResponseMessage(string message, int statusCode = 200, Guid? guid = null)
{
var response = new ResponseMessage
{
StatusCode = statusCode,
Headers = _contentTypeJsonHeaders,
BodyAsJson = new StatusModel { Status = message, Guid = guid }
};
return response;
}
}
}

View File

@@ -56,7 +56,7 @@ namespace WireMock.Server
/// Gets the scenarios.
/// </summary>
[PublicAPI]
public IDictionary<string, object> Scenarios => new ConcurrentDictionary<string, object>(_options.Scenarios);
public ConcurrentDictionary<string, object> Scenarios => new ConcurrentDictionary<string, object>(_options.Scenarios); // Checked
#region Start/Stop
/// <summary>
@@ -161,6 +161,7 @@ namespace WireMock.Server
settings.Logger = settings.Logger ?? new WireMockConsoleLogger();
_logger = settings.Logger;
_logger.Info("WireMock.Net by Stef Heyenrath (https://github.com/WireMock-Net/WireMock.Net)");
_logger.Debug("WireMock.Net server settings {0}", JsonConvert.SerializeObject(settings, Formatting.Indented));
if (settings.Urls != null)
@@ -248,7 +249,9 @@ namespace WireMock.Server
[PublicAPI]
public void Stop()
{
_httpServer?.StopAsync();
var result = _httpServer?.StopAsync();
if (result != null)
result.Wait(); //wait for stop to actually happen
}
#endregion
@@ -292,9 +295,9 @@ namespace WireMock.Server
[PublicAPI]
public void ResetMappings()
{
foreach (var nonAdmin in _options.Mappings.Where(m => !m.Value.IsAdminInterface))
foreach (var nonAdmin in _options.Mappings.ToArray().Where(m => !m.Value.IsAdminInterface))
{
_options.Mappings.Remove(nonAdmin);
_options.Mappings.TryRemove(nonAdmin.Key, out _);
}
}
@@ -308,7 +311,7 @@ namespace WireMock.Server
// Check a mapping exists with the same GUID, if so, remove it.
if (_options.Mappings.ContainsKey(guid))
{
return _options.Mappings.Remove(guid);
return _options.Mappings.TryRemove(guid, out _);
}
return false;
@@ -317,7 +320,7 @@ namespace WireMock.Server
private bool DeleteMapping(string path)
{
// Check a mapping exists with the same path, if so, remove it.
var mapping = _options.Mappings.FirstOrDefault(entry => string.Equals(entry.Value.Path, path, StringComparison.OrdinalIgnoreCase));
var mapping = _options.Mappings.ToArray().FirstOrDefault(entry => string.Equals(entry.Value.Path, path, StringComparison.OrdinalIgnoreCase));
return DeleteMapping(mapping.Key);
}
@@ -415,7 +418,7 @@ namespace WireMock.Server
}
else
{
_options.Mappings.Add(mapping.Guid, mapping);
_options.Mappings.TryAdd(mapping.Guid, mapping);
}
}
}

View File

@@ -8,6 +8,11 @@ namespace WireMock.Server
/// </summary>
public interface IRespondWithAProvider
{
/// <summary>
/// Gets the unique identifier for this mapping.
/// </summary>
Guid Guid { get; }
/// <summary>
/// Define a unique identifier for this mapping.
/// </summary>

View File

@@ -10,7 +10,6 @@ namespace WireMock.Server
internal class RespondWithAProvider : IRespondWithAProvider
{
private int _priority;
private Guid? _guid;
private string _title;
private string _path;
private object _executionConditionState;
@@ -19,6 +18,8 @@ namespace WireMock.Server
private readonly RegistrationCallback _registrationCallback;
private readonly IRequestMatcher _requestMatcher;
public Guid Guid { get; private set; } = Guid.NewGuid();
/// <summary>
/// Initializes a new instance of the <see cref="RespondWithAProvider"/> class.
/// </summary>
@@ -36,8 +37,7 @@ namespace WireMock.Server
/// <param name="provider">The provider.</param>
public void RespondWith(IResponseProvider provider)
{
var mappingGuid = _guid ?? Guid.NewGuid();
_registrationCallback(new Mapping(mappingGuid, _title, _path, _requestMatcher, provider, _priority, _scenario, _executionConditionState, _nextState));
_registrationCallback(new Mapping(Guid, _title, _path, _requestMatcher, provider, _priority, _scenario, _executionConditionState, _nextState));
}
/// <see cref="IRespondWithAProvider.WithGuid(string)"/>
@@ -49,7 +49,7 @@ namespace WireMock.Server
/// <see cref="IRespondWithAProvider.WithGuid(Guid)"/>
public IRespondWithAProvider WithGuid(Guid guid)
{
_guid = guid;
Guid = guid;
return this;
}

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.18</Version>
<Version>1.0.4.3</Version>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

View File

@@ -33,10 +33,12 @@ namespace WireMock.Net.Tests
Priority = 500,
Title = "test"
};
string result = await api.PostMappingAsync(model);
var result = await api.PostMappingAsync(model);
// Assert
Check.That(result).IsNotNull();
Check.That(result.Status).IsNotNull();
Check.That(result.Guid).IsNotNull();
var mapping = server.Mappings.Single(m => m.Priority == 500);
Check.That(mapping).IsNotNull();

View File

@@ -88,7 +88,7 @@ namespace WireMock.Net.Tests
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings", guid + ".json");
string json = File.ReadAllText(folder);
string responseBodyFilePath = Path.Combine(GetCurrentFolder(), "ResponseBodyFiles", "responsebody.json");
string responseBodyFilePath = Path.Combine(GetCurrentFolder(), "responsebody.json");
dynamic jsonObj = JsonConvert.DeserializeObject(json);
jsonObj["Response"]["BodyAsFile"] = responseBodyFilePath;

View File

@@ -38,11 +38,11 @@ namespace WireMock.Net.Tests.Matchers
public void ExactObjectMatcher_IsMatch_AcceptOnMatch()
{
// Assign
object obj = 1;
object obj = new { x = 500, s = "s" };
// Act
var matcher = new ExactObjectMatcher(obj);
double result = matcher.IsMatch(1);
double result = matcher.IsMatch(new { x = 500, s = "s" });
// Assert
Check.That(result).IsEqualTo(1.0);
@@ -52,11 +52,11 @@ namespace WireMock.Net.Tests.Matchers
public void ExactObjectMatcher_IsMatch_RejectOnMatch()
{
// Assign
object obj = 1;
object obj = new { x = 500, s = "s" };
// Act
var matcher = new ExactObjectMatcher(MatchBehaviour.RejectOnMatch, obj);
double result = matcher.IsMatch(1);
double result = matcher.IsMatch(new { x = 500, s = "s" });
// Assert
Check.That(result).IsEqualTo(0.0);

View File

@@ -0,0 +1,132 @@
using Newtonsoft.Json.Linq;
using NFluent;
using WireMock.Matchers;
using Xunit;
namespace WireMock.Net.Tests.Matchers
{
public class JsonMatcherTests
{
[Fact]
public void JsonMatcher_GetName()
{
// Assign
var matcher = new JsonMatcher("{}");
// Act
string name = matcher.Name;
// Assert
Check.That(name).Equals("JsonMatcher");
}
[Fact]
public void JsonMatcher_GetValue()
{
// Assign
var matcher = new JsonMatcher("{}");
// Act
object value = matcher.Value;
// Assert
Check.That(value).Equals("{}");
}
[Fact]
public void JsonMatcher_IsMatch_NullString()
{
// Assign
string s = null;
var matcher = new JsonMatcher("");
// Act
double match = matcher.IsMatch(s);
// Assert
Check.That(match).IsEqualTo(0);
}
[Fact]
public void JsonMatcher_IsMatch_NullObject()
{
// Assign
object o = null;
var matcher = new JsonMatcher("");
// Act
double match = matcher.IsMatch(o);
// Assert
Check.That(match).IsEqualTo(0);
}
[Fact]
public void JsonMatcher_IsMatch_JObject1()
{
// Assign
var matcher = new JsonMatcher(new { Id = 1, Name = "test" });
// Act
var jobject = new JObject
{
{ "Id", new JValue(1) },
{ "Name", new JValue("Test") }
};
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonMatcher_IsMatch_JObject2()
{
// Assign
var matcher = new JsonMatcher(new { Id = 1, Name = "test" });
// Act
var jobject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }");
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonMatcher_IsMatch_JObjectAsString()
{
// Assign
var matcher = new JsonMatcher("{ \"Id\" : 1, \"Name\" : \"Test\" }");
// Act
var jobject = new JObject
{
{ "Id", new JValue(1) },
{ "Name", new JValue("Test") }
};
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonMatcher_IsMatch_JObjectAsString_RejectOnMatch()
{
// Assign
var matcher = new JsonMatcher(MatchBehaviour.RejectOnMatch, "{ \"Id\" : 1, \"Name\" : \"Test\" }");
// Act
var jobject = new JObject
{
{ "Id", new JValue(1) },
{ "Name", new JValue("Test") }
};
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(0.0, match);
}
}
}

View File

@@ -9,7 +9,7 @@ namespace WireMock.Net.Tests.RequestMatchers
public class RequestMessageParamMatcherTests
{
[Fact]
public void RequestMessageParamMatcher_GetMatchingScore_AllMatch()
public void RequestMessageParamMatcher_GetMatchingScore_KeyWithValuesPresentInUrl_MatchExactOnStringValues()
{
// Assign
var requestMessage = new RequestMessage(new Uri("http://localhost?key=test1,test2"), "GET", "127.0.0.1");
@@ -24,7 +24,22 @@ namespace WireMock.Net.Tests.RequestMatchers
}
[Fact]
public void RequestMessageParamMatcher_GetMatchingScore_PartialMatch()
public void RequestMessageParamMatcher_GetMatchingScore_KeyWithValuesPresentInUrl_MatchExactOnExactMatchers()
{
// Assign
var requestMessage = new RequestMessage(new Uri("http://localhost?key=test1,test2"), "GET", "127.0.0.1");
var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", new IStringMatcher[] { new ExactMatcher("test1"), new ExactMatcher("test2") });
// Act
var result = new RequestMatchResult();
double score = matcher.GetMatchingScore(requestMessage, result);
// Assert
Check.That(score).IsEqualTo(1.0d);
}
[Fact]
public void RequestMessageParamMatcher_GetMatchingScore_KeyWithValuesPresentInUrl_MatchOnKeyWithValues_PartialMatch()
{
// Assign
var requestMessage = new RequestMessage(new Uri("http://localhost?key=test0,test2"), "GET", "127.0.0.1");
@@ -39,7 +54,7 @@ namespace WireMock.Net.Tests.RequestMatchers
}
[Fact]
public void RequestMessageParamMatcher_GetMatchingScore_OnlyKeyPresent()
public void RequestMessageParamMatcher_GetMatchingScore_OnlyKeyPresentInUrl_MatchOnKeyWithValues_Fails()
{
// Assign
var requestMessage = new RequestMessage(new Uri("http://localhost?key"), "GET", "127.0.0.1");
@@ -54,7 +69,7 @@ namespace WireMock.Net.Tests.RequestMatchers
}
[Fact]
public void RequestMessageParamMatcher_GetMatchingScore_OnlyKeyPresent_WithNull()
public void RequestMessageParamMatcher_GetMatchingScore_OnlyKeyPresentInUrl_MatchOnKey()
{
// Assign
var requestMessage = new RequestMessage(new Uri("http://localhost?key"), "GET", "127.0.0.1");
@@ -69,7 +84,7 @@ namespace WireMock.Net.Tests.RequestMatchers
}
[Fact]
public void RequestMessageParamMatcher_GetMatchingScore_OnlyKeyPresent_WithEmptyArray()
public void RequestMessageParamMatcher_GetMatchingScore_OnlyKeyPresentInUrl_MatchOnKeyWithEmptyArray()
{
// Assign
var requestMessage = new RequestMessage(new Uri("http://localhost?key"), "GET", "127.0.0.1");
@@ -82,5 +97,20 @@ namespace WireMock.Net.Tests.RequestMatchers
// Assert
Check.That(score).IsEqualTo(1.0d);
}
[Fact]
public void RequestMessageParamMatcher_GetMatchingScore_KeyWithValuePresentInUrl_MatchOnKey()
{
// Assign
var requestMessage = new RequestMessage(new Uri("http://localhost?key=frank@contoso.com"), "GET", "127.0.0.1");
var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key");
// Act
var result = new RequestMatchResult();
double score = matcher.GetMatchingScore(requestMessage, result);
// Assert
Check.That(score).IsEqualTo(1.0d);
}
}
}

View File

@@ -13,7 +13,7 @@ namespace WireMock.Net.Tests.Serialization
public void MatcherModelMapper_Map_Null()
{
// Act
IMatcher matcher = MatcherModelMapper.Map(null);
IMatcher matcher = MatcherMapper.Map((MatcherModel)null);
// Assert
Check.That(matcher).IsNull();
@@ -30,7 +30,7 @@ namespace WireMock.Net.Tests.Serialization
};
// Act
var matcher = (ExactMatcher)MatcherModelMapper.Map(model);
var matcher = (ExactMatcher)MatcherMapper.Map(model);
// Assert
Check.That(matcher.GetPatterns()).ContainsExactly("x");
@@ -47,7 +47,7 @@ namespace WireMock.Net.Tests.Serialization
};
// Act
var matcher = (ExactMatcher)MatcherModelMapper.Map(model);
var matcher = (ExactMatcher)MatcherMapper.Map(model);
// Assert
Check.That(matcher.GetPatterns()).ContainsExactly("x", "y");
@@ -65,7 +65,7 @@ namespace WireMock.Net.Tests.Serialization
};
// Act
var matcher = (RegexMatcher)MatcherModelMapper.Map(model);
var matcher = (RegexMatcher)MatcherMapper.Map(model);
// Assert
Check.That(matcher.GetPatterns()).ContainsExactly("x", "y");
@@ -84,7 +84,7 @@ namespace WireMock.Net.Tests.Serialization
};
// Act
var matcher = (WildcardMatcher)MatcherModelMapper.Map(model);
var matcher = (WildcardMatcher)MatcherMapper.Map(model);
// Assert
Check.That(matcher.GetPatterns()).ContainsExactly("x", "y");
@@ -102,7 +102,7 @@ namespace WireMock.Net.Tests.Serialization
};
// Act
var matcher = (SimMetricsMatcher)MatcherModelMapper.Map(model);
var matcher = (SimMetricsMatcher)MatcherMapper.Map(model);
// Assert
Check.That(matcher.GetPatterns()).ContainsExactly("x");
@@ -119,7 +119,7 @@ namespace WireMock.Net.Tests.Serialization
};
// Act
var matcher = (SimMetricsMatcher)MatcherModelMapper.Map(model);
var matcher = (SimMetricsMatcher)MatcherMapper.Map(model);
// Assert
Check.That(matcher.GetPatterns()).ContainsExactly("x");
@@ -136,7 +136,7 @@ namespace WireMock.Net.Tests.Serialization
};
// Act
Check.ThatCode(() => MatcherModelMapper.Map(model)).Throws<NotSupportedException>();
Check.ThatCode(() => MatcherMapper.Map(model)).Throws<NotSupportedException>();
}
[Fact]
@@ -150,7 +150,7 @@ namespace WireMock.Net.Tests.Serialization
};
// Act
Check.ThatCode(() => MatcherModelMapper.Map(model)).Throws<NotSupportedException>();
Check.ThatCode(() => MatcherMapper.Map(model)).Throws<NotSupportedException>();
}
}
}

View File

@@ -16,23 +16,23 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="Microsoft.Owin.Host.HttpListener" Version="3.1.0" />
<PackageReference Include="Moq" Version="4.8.2" />
<PackageReference Include="Moq" Version="4.8.3" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="NFluent" Version="2.2.0" />
<PackageReference Include="OpenCover" Version="4.6.519" />
<PackageReference Include="ReportGenerator" Version="3.1.2" />
<PackageReference Include="SimMetrics.Net" Version="1.0.4" />
<PackageReference Include="System.Threading" Version="4.3.0" />
<PackageReference Include="xunit" Version="2.3.0-beta1-build3642" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0-beta1-build1309" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
</ItemGroup>
<ItemGroup>
<None Update="ResponseBodyFiles\responsebody.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<None Update="responsebody.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\00000002-ee28-4f29-ae63-1ac9b0802d86.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>