Compare commits

...

6 Commits

Author SHA1 Message Date
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
29 changed files with 445 additions and 171 deletions

View File

@@ -1,3 +1,19 @@
# 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))

View File

@@ -1,5 +1,5 @@
https://github.com/GitTools/GitReleaseNotes
GitReleaseNotes.exe . /OutputFile CHANGELOG.md /Version 1.0.3.20
GitReleaseNotes.exe . /OutputFile CHANGELOG.md /Version 1.0.4.1
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

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

@@ -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,16 @@ namespace WireMock.Net.ConsoleApplication
.RespondWith(Response.Create()
.WithBody(@"{ ""result"": ""JsonPathMatcher !!!""}"));
server
.Given(Request
.Create()
.WithPath("/jsonbodytest")
.WithBody(new JsonMatcher("{ \"x\": 42, \"s\": \"s\" }"))
.UsingPost())
.WithGuid("debaf408-3b23-4c04-9d18-ef1c020e79f2")
.RespondWith(Response.Create()
.WithBody(@"{ ""result"": ""jsonbodytest"" }"));
server
.Given(Request
.Create()

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

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

View File

@@ -10,6 +10,11 @@
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the value. Used by <see cref="Matchers.JsonMatcher"/>.
/// </summary>
public string Value { get; set; }
/// <summary>
/// Gets or sets the pattern.
/// </summary>

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.
/// </summary>
/// <returns>Value</returns>
string GetValue();
}
}

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,67 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Validation;
namespace WireMock.Matchers
{
/// <summary>
/// JsonMatcher
/// </summary>
public class JsonMatcher : IValueMatcher
{
private readonly string _value;
/// <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 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="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value to check for equality.</param>
public JsonMatcher(MatchBehaviour matchBehaviour, [NotNull] string 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 jtoken = input is JToken token ? token : JObject.FromObject(input);
match = JToken.DeepEquals(JToken.Parse(_value), jtoken);
}
catch (JsonException)
{
// just ignore JsonException
}
}
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
}
/// <inheritdoc cref="IValueMatcher.GetValue"/>
public string GetValue() => _value;
}
}

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

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

@@ -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[] 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 "JsonMatcher":
return new JsonMatcher(matchBehaviour, matcher.Pattern);
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.");
}
}
public static MatcherModel[] Map([CanBeNull] IEnumerable<IMatcher> matchers)
{
return matchers?.Select(Map).Where(x => x != null).ToArray();
@@ -20,9 +70,11 @@ namespace WireMock.Serialization
return null;
}
string[] patterns = matcher is IStringMatcher stringMatcher ? stringMatcher.GetPatterns() : new string[0];
string[] patterns = matcher is IStringMatcher stringMatcher ?
stringMatcher.GetPatterns() :
matcher is IValueMatcher valueMatcher ? new[] { valueMatcher.GetValue() } : new string[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;
@@ -457,7 +456,7 @@ namespace WireMock.Server
return new ResponseMessage { StatusCode = 404, Body = "Request not found" };
}
var model = ToLogEntryModel(entry);
var model = LogEntryMapper.Map(entry);
return ToJson(model);
}
@@ -478,71 +477,11 @@ 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();
@@ -568,7 +507,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);
}
@@ -609,7 +548,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 +564,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 +580,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 +594,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,7 +602,7 @@ 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());
}
}
@@ -677,7 +616,7 @@ namespace WireMock.Server
if (requestModel.Body?.Matcher != null)
{
var bodyMatcher = MatcherModelMapper.Map(requestModel.Body.Matcher);
var bodyMatcher = MatcherMapper.Map(requestModel.Body.Matcher);
requestBuilder = requestBuilder.WithBody(bodyMatcher);
}

View File

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

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

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,100 @@
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
string value = matcher.GetValue();
// 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_JObject()
{
// 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_JObject_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

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

@@ -14,17 +14,17 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
<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' ">