mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-17 23:03:46 +01:00
Fix MappingMatcher in case of an exception in LinqMatcher. (#322)
* Fix MappingMatcher in case of an exception in LinqMatcher. * update unit-tests
This commit is contained in:
@@ -56,11 +56,23 @@ namespace WireMock.Matchers
|
||||
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
|
||||
public double IsMatch(string input)
|
||||
{
|
||||
double match = MatchScores.Mismatch;
|
||||
|
||||
// Convert a single input string to a Queryable string-list with 1 entry.
|
||||
IQueryable queryable = new[] { input }.AsQueryable();
|
||||
|
||||
// Use the Any(...) method to check if the result matches
|
||||
double match = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern)));
|
||||
try
|
||||
{
|
||||
// Use the Any(...) method to check if the result matches
|
||||
match = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern)));
|
||||
|
||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// just ignore exception
|
||||
// TODO add logging?
|
||||
}
|
||||
|
||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||
}
|
||||
@@ -68,6 +80,8 @@ namespace WireMock.Matchers
|
||||
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
|
||||
public double IsMatch(object input)
|
||||
{
|
||||
double match = MatchScores.Mismatch;
|
||||
|
||||
JObject value;
|
||||
switch (input)
|
||||
{
|
||||
@@ -83,16 +97,27 @@ namespace WireMock.Matchers
|
||||
// Convert a single object to a Queryable JObject-list with 1 entry.
|
||||
var queryable1 = new[] { value }.AsQueryable();
|
||||
|
||||
// Generate the DynamicLinq select statement.
|
||||
string dynamicSelect = JsonUtils.GenerateDynamicLinqStatement(value);
|
||||
try
|
||||
{
|
||||
// Generate the DynamicLinq select statement.
|
||||
string dynamicSelect = JsonUtils.GenerateDynamicLinqStatement(value);
|
||||
|
||||
// Execute DynamicLinq Select statement.
|
||||
var queryable2 = queryable1.Select(dynamicSelect);
|
||||
// Execute DynamicLinq Select statement.
|
||||
var queryable2 = queryable1.Select(dynamicSelect);
|
||||
|
||||
// Use the Any(...) method to check if the result matches.
|
||||
double match = MatchScores.ToScore(_patterns.Select(pattern => queryable2.Any(pattern)));
|
||||
// Use the Any(...) method to check if the result matches.
|
||||
match = MatchScores.ToScore(_patterns.Select(pattern => queryable2.Any(pattern)));
|
||||
|
||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// just ignore exception
|
||||
// TODO add logging?
|
||||
}
|
||||
|
||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace WireMock.Matchers
|
||||
catch (Exception)
|
||||
{
|
||||
// just ignore exception
|
||||
// TODO add logging?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.Owin
|
||||
namespace WireMock.Owin
|
||||
{
|
||||
internal interface IMappingMatcher
|
||||
{
|
||||
(IMapping Mapping, RequestMatchResult RequestMatchResult) Match(RequestMessage request);
|
||||
MappingMatcherResult FindBestMatch(RequestMessage request);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using WireMock.Matchers.Request;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Owin
|
||||
@@ -15,34 +16,41 @@ namespace WireMock.Owin
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public (IMapping Mapping, RequestMatchResult RequestMatchResult) Match(RequestMessage request)
|
||||
public MappingMatcherResult FindBestMatch(RequestMessage request)
|
||||
{
|
||||
var mappings = _options.Mappings.Values
|
||||
.Select(m => new
|
||||
var mappings = new List<MappingMatcherResult>();
|
||||
foreach (var mapping in _options.Mappings.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
Mapping = m,
|
||||
MatchResult = m.GetRequestMatchResult(request, m.Scenario != null && _options.Scenarios.ContainsKey(m.Scenario) ? _options.Scenarios[m.Scenario].NextState : null)
|
||||
})
|
||||
.ToList();
|
||||
string scenario = mapping.Scenario != null && _options.Scenarios.ContainsKey(mapping.Scenario) ? _options.Scenarios[mapping.Scenario].NextState : null;
|
||||
|
||||
mappings.Add(new MappingMatcherResult
|
||||
{
|
||||
Mapping = mapping,
|
||||
RequestMatchResult = mapping.GetRequestMatchResult(request, scenario)
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_options.Logger.Error($"Getting a Request MatchResult for Mapping '{mapping.Guid}' failed. This mapping will not be evaluated. Exception: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
if (_options.AllowPartialMapping)
|
||||
{
|
||||
var partialMappings = mappings
|
||||
.Where(pm => (pm.Mapping.IsAdminInterface && pm.MatchResult.IsPerfectMatch) || !pm.Mapping.IsAdminInterface)
|
||||
.OrderBy(m => m.MatchResult)
|
||||
.Where(pm => (pm.Mapping.IsAdminInterface && pm.RequestMatchResult.IsPerfectMatch) || !pm.Mapping.IsAdminInterface)
|
||||
.OrderBy(m => m.RequestMatchResult)
|
||||
.ThenBy(m => m.Mapping.Priority)
|
||||
.ToList();
|
||||
|
||||
var bestPartialMatch = partialMappings.FirstOrDefault(pm => pm.MatchResult.AverageTotalScore > 0.0);
|
||||
|
||||
return (bestPartialMatch?.Mapping, bestPartialMatch?.MatchResult);
|
||||
return partialMappings.FirstOrDefault(pm => pm.RequestMatchResult.AverageTotalScore > 0.0);
|
||||
}
|
||||
|
||||
var perfectMatch = mappings
|
||||
return mappings
|
||||
.OrderBy(m => m.Mapping.Priority)
|
||||
.FirstOrDefault(m => m.MatchResult.IsPerfectMatch);
|
||||
|
||||
return (perfectMatch?.Mapping, perfectMatch?.MatchResult);
|
||||
.FirstOrDefault(m => m.RequestMatchResult.IsPerfectMatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/WireMock.Net/Owin/MappingMatcherResult.cs
Normal file
11
src/WireMock.Net/Owin/MappingMatcherResult.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.Owin
|
||||
{
|
||||
internal class MappingMatcherResult
|
||||
{
|
||||
public IMapping Mapping { get; set; }
|
||||
|
||||
public RequestMatchResult RequestMatchResult { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Matchers.Request;
|
||||
using System.Linq;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Util;
|
||||
@@ -74,7 +73,7 @@ namespace WireMock.Owin
|
||||
|
||||
bool logRequest = false;
|
||||
ResponseMessage response = null;
|
||||
(IMapping TargetMapping, RequestMatchResult RequestMatchResult) result = (null, null);
|
||||
MappingMatcherResult result = null;
|
||||
try
|
||||
{
|
||||
foreach (var mapping in _options.Mappings.Values.Where(m => m?.Scenario != null))
|
||||
@@ -89,9 +88,9 @@ namespace WireMock.Owin
|
||||
}
|
||||
}
|
||||
|
||||
result = _mappingMatcher.Match(request);
|
||||
var targetMapping = result.TargetMapping;
|
||||
result = _mappingMatcher.FindBestMatch(request);
|
||||
|
||||
var targetMapping = result?.Mapping;
|
||||
if (targetMapping == null)
|
||||
{
|
||||
logRequest = true;
|
||||
@@ -129,7 +128,7 @@ namespace WireMock.Owin
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_options.Logger.Error($"Providing a Response for Mapping '{result.TargetMapping.Guid}' failed. HttpStatusCode set to 500. Exception: {ex}");
|
||||
_options.Logger.Error($"Providing a Response for Mapping '{result?.Mapping?.Guid}' failed. HttpStatusCode set to 500. Exception: {ex}");
|
||||
response = ResponseMessageBuilder.Create(JsonConvert.SerializeObject(ex), 500);
|
||||
}
|
||||
finally
|
||||
@@ -139,9 +138,9 @@ namespace WireMock.Owin
|
||||
Guid = Guid.NewGuid(),
|
||||
RequestMessage = request,
|
||||
ResponseMessage = response,
|
||||
MappingGuid = result.TargetMapping?.Guid,
|
||||
MappingTitle = result.TargetMapping?.Title,
|
||||
RequestMatchResult = result.RequestMatchResult
|
||||
MappingGuid = result?.Mapping?.Guid,
|
||||
MappingTitle = result?.Mapping?.Title,
|
||||
RequestMatchResult = result?.RequestMatchResult
|
||||
};
|
||||
|
||||
LogRequest(log, logRequest);
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace WireMock.Net.Tests.Owin
|
||||
public class MappingMatcherTests
|
||||
{
|
||||
private readonly Mock<IWireMockMiddlewareOptions> _optionsMock;
|
||||
private readonly IMappingMatcher _sut;
|
||||
private readonly MappingMatcher _sut;
|
||||
|
||||
public MappingMatcherTests()
|
||||
{
|
||||
@@ -24,25 +24,50 @@ namespace WireMock.Net.Tests.Owin
|
||||
_optionsMock.Setup(o => o.LogEntries).Returns(new ConcurrentObservableCollection<LogEntry>());
|
||||
_optionsMock.Setup(o => o.Scenarios).Returns(new ConcurrentDictionary<string, ScenarioState>());
|
||||
|
||||
var loggerMock = new Mock<IWireMockLogger>();
|
||||
loggerMock.SetupAllProperties();
|
||||
loggerMock.Setup(l => l.Error(It.IsAny<string>()));
|
||||
_optionsMock.Setup(o => o.Logger).Returns(loggerMock.Object);
|
||||
|
||||
_sut = new MappingMatcher(_optionsMock.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MappingMatcher_Match_NoMappingsDefined()
|
||||
public void MappingMatcher_FindBestMatch_WhenNoMappingsDefined_ShouldReturnNull()
|
||||
{
|
||||
// Assign
|
||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1");
|
||||
|
||||
// Act
|
||||
var result = _sut.Match(request);
|
||||
var result = _sut.FindBestMatch(request);
|
||||
|
||||
// Assert and Verify
|
||||
Check.That(result.Mapping).IsNull();
|
||||
Check.That(result.RequestMatchResult).IsNull();
|
||||
Check.That(result).IsNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MappingMatcher_Match_GetBestMapping_Exact()
|
||||
public void MappingMatcher_FindBestMatch_WhenMappingThrowsException_ShouldReturnNull()
|
||||
{
|
||||
// Assign
|
||||
var mappingMock = new Mock<IMapping>();
|
||||
mappingMock.Setup(m => m.GetRequestMatchResult(It.IsAny<RequestMessage>(), It.IsAny<string>())).Throws<Exception>();
|
||||
|
||||
var mappings = new ConcurrentDictionary<Guid, IMapping>();
|
||||
mappings.TryAdd(Guid.NewGuid(), mappingMock.Object);
|
||||
|
||||
_optionsMock.Setup(o => o.Mappings).Returns(mappings);
|
||||
|
||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1");
|
||||
|
||||
// Act
|
||||
var result = _sut.FindBestMatch(request);
|
||||
|
||||
// Assert and Verify
|
||||
Check.That(result).IsNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MappingMatcher_FindBestMatch_WhenAllowPartialMappingIsFalse_ShouldReturnExactMatch()
|
||||
{
|
||||
// Assign
|
||||
var mappings = InitMappings(new[] { (Guid.Parse("00000000-0000-0000-0000-000000000001"), 0.1), (Guid.Parse("00000000-0000-0000-0000-000000000002"), 1.0) });
|
||||
@@ -51,7 +76,7 @@ namespace WireMock.Net.Tests.Owin
|
||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1");
|
||||
|
||||
// Act
|
||||
var result = _sut.Match(request);
|
||||
var result = _sut.FindBestMatch(request);
|
||||
|
||||
// Assert and Verify
|
||||
Check.That(result.Mapping.Guid).IsEqualTo(Guid.Parse("00000000-0000-0000-0000-000000000002"));
|
||||
@@ -59,7 +84,7 @@ namespace WireMock.Net.Tests.Owin
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MappingMatcher_Match_GetBestMapping_AllowPartialMapping()
|
||||
public void MappingMatcher_FindBestMatch_WhenAllowPartialMappingIsTrue_ShouldReturnAnyMatch()
|
||||
{
|
||||
// Assign
|
||||
_optionsMock.SetupGet(o => o.AllowPartialMapping).Returns(true);
|
||||
@@ -69,7 +94,7 @@ namespace WireMock.Net.Tests.Owin
|
||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1");
|
||||
|
||||
// Act
|
||||
var result = _sut.Match(request);
|
||||
var result = _sut.FindBestMatch(request);
|
||||
|
||||
// Assert and Verify
|
||||
Check.That(result.Mapping.Guid).IsEqualTo(Guid.Parse("00000000-0000-0000-0000-000000000002"));
|
||||
|
||||
@@ -11,7 +11,6 @@ using WireMock.Owin.Mappers;
|
||||
using WireMock.Util;
|
||||
using WireMock.Admin.Requests;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Matchers;
|
||||
using System.Collections.Generic;
|
||||
#if NET452
|
||||
@@ -61,7 +60,7 @@ namespace WireMock.Net.Tests.Owin
|
||||
|
||||
_matcherMock = new Mock<IMappingMatcher>();
|
||||
_matcherMock.SetupAllProperties();
|
||||
_matcherMock.Setup(m => m.Match(It.IsAny<RequestMessage>())).Returns(((IMapping)null, (RequestMatchResult)null));
|
||||
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns(new MappingMatcherResult());
|
||||
|
||||
_contextMock = new Mock<IContext>();
|
||||
|
||||
@@ -92,7 +91,7 @@ namespace WireMock.Net.Tests.Owin
|
||||
|
||||
_optionsMock.SetupGet(o => o.AuthorizationMatcher).Returns(new ExactMatcher());
|
||||
_mappingMock.SetupGet(m => m.IsAdminInterface).Returns(true);
|
||||
_matcherMock.Setup(m => m.Match(It.IsAny<RequestMessage>())).Returns((_mappingMock.Object, (RequestMatchResult)null));
|
||||
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns(new MappingMatcherResult { Mapping = _mappingMock.Object });
|
||||
|
||||
// Act
|
||||
await _sut.Invoke(_contextMock.Object);
|
||||
@@ -113,7 +112,7 @@ namespace WireMock.Net.Tests.Owin
|
||||
|
||||
_optionsMock.SetupGet(o => o.AuthorizationMatcher).Returns(new ExactMatcher());
|
||||
_mappingMock.SetupGet(m => m.IsAdminInterface).Returns(true);
|
||||
_matcherMock.Setup(m => m.Match(It.IsAny<RequestMessage>())).Returns((_mappingMock.Object, (RequestMatchResult)null));
|
||||
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns(new MappingMatcherResult { Mapping = _mappingMock.Object });
|
||||
|
||||
// Act
|
||||
await _sut.Invoke(_contextMock.Object);
|
||||
|
||||
Reference in New Issue
Block a user