Compare commits

..

5 Commits

Author SHA1 Message Date
Stef Heyenrath
288a50ccaf 1.4.33 2022-01-24 12:54:36 +01:00
Stef Heyenrath
ccd433b202 Add support for Cors (#714) 2022-01-24 12:26:19 +01:00
Stef Heyenrath
d6c36bc23b 1.4.32 2022-01-17 15:56:28 +00:00
Levan Nozadze
6b393ebc1d Added support of custom matchers in static mappings (#713)
* Added support of custom matchers in static mappings

* Fixed code style issues

* Fixed naming and code style

* added empty line

* Ignore serialization of CustomMatcherMappings property in WireMockServerSettings

* Added integration tests for CustomMatcherMappings
2022-01-17 16:04:37 +01:00
Stef Heyenrath
60bdc06d29 Small refactor on Template logic 2022-01-06 21:25:15 +01:00
26 changed files with 512 additions and 51 deletions

View File

@@ -1,3 +1,9 @@
# 1.4.33 (24 January 2022)
- [#714](https://github.com/WireMock-Net/WireMock.Net/pull/714) - Add support for Cors [feature] contributed by [StefH](https://github.com/StefH)
# 1.4.32 (17 January 2022)
- [#713](https://github.com/WireMock-Net/WireMock.Net/pull/713) - Added support of custom matchers in static mappings contributed by [levanoz](https://github.com/levanoz)
# 1.4.31 (06 January 2022)
- [#706](https://github.com/WireMock-Net/WireMock.Net/pull/706) - Provide open api schema to dynamic examples generator so you can generate accurate data [feature] contributed by [brunotarghetta](https://github.com/brunotarghetta)
- [#707](https://github.com/WireMock-Net/WireMock.Net/pull/707) - Use NuGet "Stef.Validation" [feature] contributed by [StefH](https://github.com/StefH)

View File

@@ -4,7 +4,7 @@
</PropertyGroup>
<PropertyGroup>
<VersionPrefix>1.4.31</VersionPrefix>
<VersionPrefix>1.4.33</VersionPrefix>
<PackageReleaseNotes>See CHANGELOG.md</PackageReleaseNotes>
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>

View File

@@ -1,6 +1,6 @@
rem https://github.com/StefH/GitHubReleaseNotes
SET version=1.4.31
SET version=1.4.33
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc duplicate --version %version% --token %GH_TOKEN%

View File

@@ -1,6 +1,4 @@
# 1.4.31 (06 January 2022)
- #706 Provide open api schema to dynamic examples generator so you can generate accurate data [feature]
- #707 Use NuGet &quot;Stef.Validation&quot; [feature]
- #710 Add ReplaceNodeOption flag [feature]
# 1.4.33 (24 January 2022)
- #714 Add support for Cors [feature]
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md

View File

@@ -6,8 +6,6 @@ using System.Threading;
using log4net;
using log4net.Config;
using log4net.Repository;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
@@ -35,33 +33,6 @@ namespace WireMock.Net.StandAlone.NETCoreApp
settings.Logger.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
/* https://stackoverflow.com/questions/31942037/how-to-enable-cors-in-asp-net-core */
/* Enable Cors */
var policyName = "MyPolicy";
settings.AdditionalServiceRegistration = services =>
{
services.AddCors(corsOptions =>
corsOptions.AddPolicy(policyName,
corsPolicyBuilder =>
{
corsPolicyBuilder
.AllowAnyHeader()
.AllowAnyMethod()
.AllowAnyOrigin();
}));
settings.Logger.Debug("Enable Cors");
};
/* Use Cors */
settings.PreWireMockMiddlewareInit = app =>
{
var appBuilder = (IApplicationBuilder)app;
appBuilder.UseCors(policyName);
settings.Logger.Debug("Use Cors");
};
_server = WireMockServer.Start(settings);
_server.Given(Request.Create().WithPath("/api/sap")

View File

@@ -1,8 +1,8 @@
{
"profiles": {
"WireMock.Net.StandAlone.NETCoreApp": {
"commandName": "Project",
"commandLineArgs": "--Urls http://localhost:9091 --WireMockLogger WireMockConsoleLogger"
"commandName": "Project",
"commandLineArgs": "--Urls http://localhost:9091 --CorsPolicyOptions AllowAll --WireMockLogger WireMockConsoleLogger"
}
}
}

View File

@@ -1,5 +1,6 @@
using System.Text.RegularExpressions;
using WireMock.Handlers;
using WireMock.Types;
namespace WireMock.Admin.Settings
{
@@ -53,5 +54,10 @@ namespace WireMock.Admin.Settings
/// Save unmatched requests to a file using the <see cref="IFileSystemHandler"/>. (default set to false).
/// </summary>
public bool? SaveUnmatchedRequests { get; set; }
/// <summary>
/// Policies to use when using CORS. By default CORS is disabled. [Optional]
/// </summary>
public string CorsPolicyOptions { get; set; }
}
}

View File

@@ -0,0 +1,36 @@
using System;
namespace WireMock.Types
{
/// <summary>
/// Policies to use when using CORS.
/// </summary>
[Flags]
public enum CorsPolicyOptions
{
/// <summary>
/// Cors is disabled
/// </summary>
None = 0,
/// <summary>
/// Ensures that the policy allows any header.
/// </summary>
AllowAnyHeader = 0b00000001,
/// <summary>
/// Ensures that the policy allows any method.
/// </summary>
AllowAnyMethod = 0b00000010,
/// <summary>
/// Ensures that the policy allows any origin.
/// </summary>
AllowAnyOrigin = 0b00000100,
/// <summary>
/// Ensures that the policy allows any header, method and origin.
/// </summary>
AllowAll = AllowAnyHeader | AllowAnyMethod | AllowAnyOrigin
}
}

View File

@@ -0,0 +1,48 @@
#if NETCOREAPP3_1_OR_GREATER
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using WireMock.Types;
namespace WireMock.Owin
{
internal partial class AspNetCoreSelfHost
{
public void AddCors(IServiceCollection services)
{
if (_wireMockMiddlewareOptions.CorsPolicyOptions > CorsPolicyOptions.None)
{
/* https://stackoverflow.com/questions/31942037/how-to-enable-cors-in-asp-net-core */
/* Enable Cors */
services.AddCors(corsOptions => corsOptions
.AddPolicy(CorsPolicyName,
corsPolicyBuilder =>
{
if (_wireMockMiddlewareOptions.CorsPolicyOptions.Value.HasFlag(CorsPolicyOptions.AllowAnyHeader))
{
corsPolicyBuilder.AllowAnyHeader();
}
if (_wireMockMiddlewareOptions.CorsPolicyOptions.Value.HasFlag(CorsPolicyOptions.AllowAnyMethod))
{
corsPolicyBuilder.AllowAnyMethod();
}
if (_wireMockMiddlewareOptions.CorsPolicyOptions.Value.HasFlag(CorsPolicyOptions.AllowAnyOrigin))
{
corsPolicyBuilder.AllowAnyOrigin();
}
}));
}
}
public void UseCors(IApplicationBuilder appBuilder)
{
if (_wireMockMiddlewareOptions.CorsPolicyOptions > CorsPolicyOptions.None)
{
/* Use Cors */
appBuilder.UseCors(CorsPolicyName);
}
}
}
}
#endif

View File

@@ -1,10 +1,11 @@
#if USE_ASPNETCORE && !NETSTANDARD1_3
#if USE_ASPNETCORE && !NETSTANDARD1_3
using System.Collections.Generic;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using WireMock.HttpsCertificate;
using WireMock.Types;
namespace WireMock.Owin
{

View File

@@ -18,6 +18,8 @@ namespace WireMock.Owin
{
internal partial class AspNetCoreSelfHost : IOwinSelfHost
{
private const string CorsPolicyName = "WireMock.Net - Policy";
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private readonly IWireMockMiddlewareOptions _wireMockMiddlewareOptions;
private readonly IWireMockLogger _logger;
@@ -68,12 +70,18 @@ namespace WireMock.Owin
services.AddSingleton<IOwinRequestMapper, OwinRequestMapper>();
services.AddSingleton<IOwinResponseMapper, OwinResponseMapper>();
#if NETCOREAPP3_1_OR_GREATER
AddCors(services);
#endif
_wireMockMiddlewareOptions.AdditionalServiceRegistration?.Invoke(services);
})
.Configure(appBuilder =>
{
appBuilder.UseMiddleware<GlobalExceptionMiddleware>();
#if NETCOREAPP3_1_OR_GREATER
UseCors(appBuilder);
#endif
_wireMockMiddlewareOptions.PreWireMockMiddlewareInit?.Invoke(appBuilder);
appBuilder.UseMiddleware<WireMockMiddleware>();

View File

@@ -4,6 +4,8 @@ using WireMock.Handlers;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Util;
using JetBrains.Annotations;
using WireMock.Types;
#if !USE_ASPNETCORE
using Owin;
#else
@@ -39,6 +41,8 @@ namespace WireMock.Owin
#if USE_ASPNETCORE
Action<IServiceCollection> AdditionalServiceRegistration { get; set; }
CorsPolicyOptions? CorsPolicyOptions { get; set; }
#endif
IFileSystemHandler FileSystemHandler { get; set; }

View File

@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
using WireMock.Handlers;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Types;
using WireMock.Util;
#if !USE_ASPNETCORE
using Owin;
@@ -39,6 +40,8 @@ namespace WireMock.Owin
#if USE_ASPNETCORE
public Action<IServiceCollection> AdditionalServiceRegistration { get; set; }
public CorsPolicyOptions? CorsPolicyOptions { get; set; }
#endif
/// <inheritdoc cref="IWireMockMiddlewareOptions.FileSystemHandler"/>

View File

@@ -105,6 +105,11 @@ namespace WireMock.Serialization
return new SimMetricsMatcher(matchBehaviour, stringPatterns, type, throwExceptionWhenMatcherFails);
default:
if (_settings.CustomMatcherMappings != null && _settings.CustomMatcherMappings.ContainsKey(matcherName))
{
return _settings.CustomMatcherMappings[matcherName](matcher);
}
throw new NotSupportedException($"Matcher '{matcherName}' is not supported.");
}
}

View File

@@ -293,7 +293,11 @@ namespace WireMock.Server
HandleRequestsSynchronously = _settings.HandleRequestsSynchronously,
ThrowExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails,
UseRegexExtended = _settings.UseRegexExtended,
SaveUnmatchedRequests = _settings.SaveUnmatchedRequests
SaveUnmatchedRequests = _settings.SaveUnmatchedRequests,
#if USE_ASPNETCORE
CorsPolicyOptions = _settings.CorsPolicyOptions?.ToString()
#endif
};
return ToJson(model);
@@ -315,6 +319,13 @@ namespace WireMock.Server
_settings.UseRegexExtended = settings.UseRegexExtended;
_settings.SaveUnmatchedRequests = settings.SaveUnmatchedRequests;
#if USE_ASPNETCORE
if (Enum.TryParse<CorsPolicyOptions>(settings.CorsPolicyOptions, true, out var corsPolicyOptions))
{
_settings.CorsPolicyOptions = corsPolicyOptions;
}
#endif
return ResponseMessageBuilder.Create("Settings updated");
}
#endregion Settings

View File

@@ -243,6 +243,8 @@ namespace WireMock.Server
#if USE_ASPNETCORE
_options.AdditionalServiceRegistration = _settings.AdditionalServiceRegistration;
_options.CorsPolicyOptions = _settings.CorsPolicyOptions;
_httpServer = new AspNetCoreSelfHost(_options, urlOptions);
#else
_httpServer = new OwinSelfHost(_options, urlOptions);

View File

@@ -1,13 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using HandlebarsDotNet;
using JetBrains.Annotations;
using Newtonsoft.Json;
using WireMock.Admin.Mappings;
using WireMock.Handlers;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.RegularExpressions;
#if USE_ASPNETCORE
using Microsoft.Extensions.DependencyInjection;
using WireMock.Types;
#endif
namespace WireMock.Settings
@@ -132,6 +136,12 @@ namespace WireMock.Settings
/// </summary>
[PublicAPI]
Action<IServiceCollection> AdditionalServiceRegistration { get; set; }
/// <summary>
/// Policies to use when using CORS. By default CORS is disabled. [Optional]
/// </summary>
[PublicAPI]
CorsPolicyOptions? CorsPolicyOptions { get; set; }
#endif
/// <summary>
@@ -229,5 +239,11 @@ namespace WireMock.Settings
/// </summary>
[PublicAPI]
bool? SaveUnmatchedRequests { get; set; }
/// <summary>
/// Custom matcher mappings for static mappings
/// </summary>
[PublicAPI, JsonIgnore]
IDictionary<string, Func<MatcherModel, IMatcher>> CustomMatcherMappings { get; set; }
}
}

View File

@@ -1,9 +1,13 @@
using System;
using System.Collections.Generic;
using HandlebarsDotNet;
using JetBrains.Annotations;
using Newtonsoft.Json;
using WireMock.Admin.Mappings;
using WireMock.Handlers;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Types;
#if USE_ASPNETCORE
using Microsoft.Extensions.DependencyInjection;
#endif
@@ -94,6 +98,10 @@ namespace WireMock.Settings
[PublicAPI]
[JsonIgnore]
public Action<IServiceCollection> AdditionalServiceRegistration { get; set; }
/// <inheritdoc cref="IWireMockServerSettings.CorsPolicyOptions"/>
[PublicAPI]
public CorsPolicyOptions? CorsPolicyOptions { get; set; }
#endif
/// <inheritdoc cref="IWireMockServerSettings.Logger"/>
@@ -158,5 +166,9 @@ namespace WireMock.Settings
/// <inheritdoc cref="IWireMockServerSettings.SaveUnmatchedRequests"/>
[PublicAPI]
public bool? SaveUnmatchedRequests { get; set; }
/// <inheritdoc cref="IWireMockServerSettings.CustomMatcherMappings"/>
[PublicAPI, JsonIgnore]
public IDictionary<string, Func<MatcherModel, IMatcher>> CustomMatcherMappings { get; set; }
}
}

View File

@@ -1,6 +1,9 @@
using System;
using System.Linq;
using JetBrains.Annotations;
using WireMock.Logging;
using Stef.Validation;
using WireMock.Logging;
using WireMock.Types;
namespace WireMock.Settings
{
@@ -50,9 +53,18 @@ namespace WireMock.Settings
HandleRequestsSynchronously = parser.GetBoolValue("HandleRequestsSynchronously"),
ThrowExceptionWhenMatcherFails = parser.GetBoolValue("ThrowExceptionWhenMatcherFails"),
UseRegexExtended = parser.GetBoolValue(nameof(IWireMockServerSettings.UseRegexExtended), true),
SaveUnmatchedRequests = parser.GetBoolValue(nameof(IWireMockServerSettings.SaveUnmatchedRequests))
SaveUnmatchedRequests = parser.GetBoolValue(nameof(IWireMockServerSettings.SaveUnmatchedRequests)),
};
#if USE_ASPNETCORE
settings.CorsPolicyOptions = parser.GetValue(
nameof(IWireMockServerSettings.CorsPolicyOptions), values =>
{
var value = string.Join(string.Empty, values);
return Enum.TryParse<CorsPolicyOptions>(value, true, out var corsPolicyOptions) ? corsPolicyOptions : CorsPolicyOptions.None;
});
#endif
if (logger != null)
{
settings.Logger = logger;

View File

@@ -1,6 +1,7 @@
using System;
using System;
using HandlebarsDotNet;
using JetBrains.Annotations;
using Stef.Validation;
using WireMock.Handlers;
namespace WireMock.Transformers.Handlebars
@@ -12,7 +13,7 @@ namespace WireMock.Transformers.Handlebars
public HandlebarsContextFactory([NotNull] IFileSystemHandler fileSystemHandler, [CanBeNull] Action<IHandlebars, IFileSystemHandler> action)
{
_fileSystemHandler = fileSystemHandler ?? throw new ArgumentNullException(nameof(fileSystemHandler));
_fileSystemHandler = Guard.NotNull(fileSystemHandler);
_action = action;
}

View File

@@ -1,5 +1,5 @@
using System;
using Scriban;
using Stef.Validation;
using WireMock.Handlers;
using WireMock.Types;
@@ -13,7 +13,7 @@ namespace WireMock.Transformers.Scriban
public ScribanContext(IFileSystemHandler fileSystemHandler, TransformerType transformerType)
{
FileSystemHandler = fileSystemHandler ?? throw new ArgumentNullException(nameof(fileSystemHandler));
FileSystemHandler = Guard.NotNull(fileSystemHandler);
_transformerType = transformerType;
}

View File

@@ -1,4 +1,4 @@
using WireMock.Handlers;
using WireMock.Handlers;
using WireMock.Types;
using Stef.Validation;
@@ -11,11 +11,8 @@ namespace WireMock.Transformers.Scriban
public ScribanContextFactory(IFileSystemHandler fileSystemHandler, TransformerType transformerType)
{
Guard.NotNull(fileSystemHandler, nameof(fileSystemHandler));
Guard.Condition(transformerType, t => t == TransformerType.Scriban || t == TransformerType.ScribanDotLiquid, nameof(transformerType));
_fileSystemHandler = fileSystemHandler;
_transformerType = transformerType;
_fileSystemHandler = Guard.NotNull(fileSystemHandler);
_transformerType = Guard.Condition(transformerType, t => t == TransformerType.Scriban || t == TransformerType.ScribanDotLiquid);
}
public ITransformerContext Create()

View File

@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using AnyOfTypes;
using Newtonsoft.Json;
using WireMock.Matchers;
using WireMock.Models;
namespace WireMock.Net.Tests.Serialization
{
/// <summary>
/// This matcher is only for unit test purposes
/// </summary>
public class CustomPathParamMatcher : IStringMatcher
{
public string Name => nameof(CustomPathParamMatcher);
public MatchBehaviour MatchBehaviour { get; }
public bool ThrowException { get; }
private readonly string _path;
private readonly string[] _pathParts;
private readonly Dictionary<string, string> _pathParams;
public CustomPathParamMatcher(string path, Dictionary<string, string> pathParams) : this(MatchBehaviour.AcceptOnMatch, path, pathParams)
{
}
public CustomPathParamMatcher(MatchBehaviour matchBehaviour, string path, Dictionary<string, string> pathParams, bool throwException = false)
{
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
_path = path;
_pathParts = GetPathParts(path);
_pathParams = pathParams.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);
}
public double IsMatch(string input)
{
var inputParts = GetPathParts(input);
if (inputParts.Length != _pathParts.Length)
{
return MatchScores.Mismatch;
}
try
{
for (int i = 0; i < inputParts.Length; i++)
{
var inputPart = inputParts[i];
var pathPart = _pathParts[i];
if (pathPart.StartsWith("{") && pathPart.EndsWith("}"))
{
var pathParamName = pathPart.Trim('{').Trim('}');
if (!_pathParams.ContainsKey(pathParamName))
{
return MatchScores.Mismatch;
}
if (!Regex.IsMatch(inputPart, _pathParams[pathParamName], RegexOptions.IgnoreCase))
{
return MatchScores.Mismatch;
}
}
else
{
if (!inputPart.Equals(pathPart, StringComparison.InvariantCultureIgnoreCase))
{
return MatchScores.Mismatch;
}
}
}
}
catch
{
if (ThrowException)
{
throw;
}
return MatchScores.Mismatch;
}
return MatchScores.Perfect;
}
public AnyOf<string, StringPattern>[] GetPatterns()
{
return new[] { new AnyOf<string, StringPattern>(JsonConvert.SerializeObject(new CustomPathParamMatcherModel(_path, _pathParams))) };
}
private string[] GetPathParts(string path)
{
var hashMarkIndex = path.IndexOf('#');
if (hashMarkIndex != -1)
{
path = path.Substring(0, hashMarkIndex);
}
var queryParamsIndex = path.IndexOf('?');
if (queryParamsIndex != -1)
{
path = path.Substring(0, queryParamsIndex);
}
return path.Trim().Trim('/').ToLower().Split('/');
}
}
}

View File

@@ -0,0 +1,20 @@
using System.Collections.Generic;
namespace WireMock.Net.Tests.Serialization
{
public class CustomPathParamMatcherModel
{
public string Path { get; set; }
public Dictionary<string, string> PathParams { get; set; }
public CustomPathParamMatcherModel()
{
}
public CustomPathParamMatcherModel(string path, Dictionary<string, string> pathParams)
{
Path = path;
PathParams = pathParams;
}
}
}

View File

@@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
using AnyOfTypes;
using FluentAssertions;
using FluentAssertions.Execution;
using Moq;
using Newtonsoft.Json;
using NFluent;
using WireMock.Admin.Mappings;
using WireMock.Handlers;
@@ -310,5 +313,71 @@ namespace WireMock.Net.Tests.Serialization
// Act
Check.ThatCode(() => _sut.Map(model)).Throws<NotSupportedException>();
}
[Fact]
public void MatcherModelMapper_Map_MatcherModelToCustomMatcher()
{
// Arrange
var patternModel = new CustomPathParamMatcherModel("/customer/{customerId}/document/{documentId}",
new Dictionary<string, string>(2)
{
{ "customerId", @"^[0-9]+$" },
{ "documentId", @"^[0-9a-zA-Z\-\_]+\.[a-zA-Z]+$" }
});
var model = new MatcherModel
{
Name = nameof(CustomPathParamMatcher),
Pattern = JsonConvert.SerializeObject(patternModel)
};
var settings = new WireMockServerSettings();
settings.CustomMatcherMappings = settings.CustomMatcherMappings ?? new Dictionary<string, Func<MatcherModel, IMatcher>>();
settings.CustomMatcherMappings[nameof(CustomPathParamMatcher)] = matcherModel =>
{
var matcherParams = JsonConvert.DeserializeObject<CustomPathParamMatcherModel>((string)matcherModel.Pattern);
return new CustomPathParamMatcher(
matcherModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch,
matcherParams.Path, matcherParams.PathParams,
settings.ThrowExceptionWhenMatcherFails == true
);
};
var sut = new MatcherMapper(settings);
// Act
var matcher = sut.Map(model) as CustomPathParamMatcher;
// Assert
matcher.Should().NotBeNull();
}
[Fact]
public void MatcherModelMapper_Map_CustomMatcherToMatcherModel()
{
// Arrange
var matcher = new CustomPathParamMatcher("/customer/{customerId}/document/{documentId}",
new Dictionary<string, string>(2)
{
{ "customerId", @"^[0-9]+$" },
{ "documentId", @"^[0-9a-zA-Z\-\_]+\.[a-zA-Z]+$" }
});
// Act
var model = _sut.Map(matcher);
// Assert
using (new AssertionScope())
{
model.Should().NotBeNull();
model.Name.Should().Be(nameof(CustomPathParamMatcher));
var matcherParams = JsonConvert.DeserializeObject<CustomPathParamMatcherModel>((string)model.Pattern);
matcherParams.Path.Should().Be("/customer/{customerId}/document/{documentId}");
matcherParams.PathParams.Should().BeEquivalentTo(new Dictionary<string, string>(2)
{
{ "customerId", @"^[0-9]+$" },
{ "documentId", @"^[0-9a-zA-Z\-\_]+\.[a-zA-Z]+$" }
});
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
@@ -7,10 +8,16 @@ using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using FluentAssertions;
using Newtonsoft.Json;
using NFluent;
using WireMock.Admin.Mappings;
using WireMock.Matchers;
using WireMock.Net.Tests.Serialization;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using WireMock.Settings;
using WireMock.Types;
using WireMock.Util;
using Xunit;
@@ -91,6 +98,29 @@ namespace WireMock.Net.Tests
server.Stop();
}
#if NETCOREAPP3_1_OR_GREATER
[Fact]
public async Task WireMockServer_WithCorsPolicyOptions_Should_Work_Correct()
{
// Arrange
var settings = new WireMockServerSettings
{
CorsPolicyOptions = CorsPolicyOptions.AllowAll
};
var server = WireMockServer.Start(settings);
server.Given(Request.Create().WithPath("/*")).RespondWith(Response.Create().WithBody("x"));
// Act
var response = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + "/foo").ConfigureAwait(false);
// Asser.
response.Should().Be("x");
server.Stop();
}
#endif
[Fact]
public async Task WireMockServer_Should_delay_responses_for_a_given_route()
{
@@ -383,6 +413,102 @@ namespace WireMock.Net.Tests
server.Stop();
}
[Fact]
public async Task WireMockServer_Using_JsonMapping_And_CustomMatcher_WithCorrectParams_ShouldMatch()
{
// Arrange
var settings = new WireMockServerSettings();
settings.WatchStaticMappings = true;
settings.WatchStaticMappingsInSubdirectories = true;
settings.CustomMatcherMappings = new Dictionary<string, Func<MatcherModel, IMatcher>>();
settings.CustomMatcherMappings[nameof(CustomPathParamMatcher)] = matcherModel =>
{
var matcherParams = JsonConvert.DeserializeObject<CustomPathParamMatcherModel>((string)matcherModel.Pattern);
return new CustomPathParamMatcher(
matcherModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch,
matcherParams.Path, matcherParams.PathParams,
settings.ThrowExceptionWhenMatcherFails == true
);
};
var server = WireMockServer.Start(settings);
server.WithMapping(@"{
""Request"": {
""Path"": {
""Matchers"": [
{
""Name"": ""CustomPathParamMatcher"",
""Pattern"": ""{\""path\"":\""/customer/{customerId}/document/{documentId}\"",\""pathParams\"":{\""customerId\"":\""^[0-9]+$\"",\""documentId\"":\""^[0-9a-zA-Z\\\\-_]+\\\\.[a-zA-Z]+$\""}}""
}
]
}
},
""Response"": {
""StatusCode"": 200,
""Headers"": {
""Content-Type"": ""application/json""
},
""Body"": ""OK""
}
}");
// Act
var response = await new HttpClient().PostAsync("http://localhost:" + server.Ports[0] + "/customer/132/document/pic.jpg", new StringContent("{ Hi = \"Hello World\" }")).ConfigureAwait(false);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
server.Stop();
}
[Fact]
public async Task WireMockServer_Using_JsonMapping_And_CustomMatcher_WithIncorrectParams_ShouldNotMatch()
{
// Arrange
var settings = new WireMockServerSettings();
settings.WatchStaticMappings = true;
settings.WatchStaticMappingsInSubdirectories = true;
settings.CustomMatcherMappings = new Dictionary<string, Func<MatcherModel, IMatcher>>();
settings.CustomMatcherMappings[nameof(CustomPathParamMatcher)] = matcherModel =>
{
var matcherParams = JsonConvert.DeserializeObject<CustomPathParamMatcherModel>((string)matcherModel.Pattern);
return new CustomPathParamMatcher(
matcherModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch,
matcherParams.Path, matcherParams.PathParams,
settings.ThrowExceptionWhenMatcherFails == true
);
};
var server = WireMockServer.Start(settings);
server.WithMapping(@"{
""Request"": {
""Path"": {
""Matchers"": [
{
""Name"": ""CustomPathParamMatcher"",
""Pattern"": ""{\""path\"":\""/customer/{customerId}/document/{documentId}\"",\""pathParams\"":{\""customerId\"":\""^[0-9]+$\"",\""documentId\"":\""^[0-9a-zA-Z\\\\-_]+\\\\.[a-zA-Z]+$\""}}""
}
]
}
},
""Response"": {
""StatusCode"": 200,
""Headers"": {
""Content-Type"": ""application/json""
},
""Body"": ""OK""
}
}");
// Act
var response = await new HttpClient().PostAsync("http://localhost:" + server.Ports[0] + "/customer/132/document/pic", new StringContent("{ Hi = \"Hello World\" }")).ConfigureAwait(false);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
server.Stop();
}
#endif
}
}