Compare commits

...

12 Commits
1.3.3 ... 1.3.6

Author SHA1 Message Date
Stef Heyenrath
2d95167866 1.3.6 2020-11-10 15:58:08 +00:00
Stef Heyenrath
b14bc01bf2 ProxyThisHttps (#538) 2020-11-10 16:42:17 +01:00
Mahmoud Ali
c104b8beba Add assertions for ClientIP, Url and ProxyUrl (#529)
* Add assertions for ClientIP Url and ProxyUrl

* Requested changes
2020-11-10 16:41:44 +01:00
Stef Heyenrath
09533f1e3a Add Custom Certificate settings (#537) 2020-11-10 16:40:15 +01:00
Stef Heyenrath
a0fdc002c8 WithCallback should use also use enum HttpStatusCode (#535)
* Fix #533

* simplyfy code
2020-11-10 10:20:57 +01:00
Stef Heyenrath
e107b5cfca <VersionPrefix>1.3.5</VersionPrefix> 2020-11-04 17:44:51 +01:00
Stef Heyenrath
5d3cbdbfc6 1.3.5 2020-11-04 16:43:03 +00:00
Stef Heyenrath
b8cbeb55b9 WithCallback-Async (#531) 2020-11-04 17:32:32 +01:00
Stef Heyenrath
5b083d753e Fix dotnet-sonarscanner (#530) 2020-11-02 19:37:46 +01:00
Stef Heyenrath
99dbb3f9b6 1.3.4 2020-10-17 08:50:41 +02:00
Stef Heyenrath
6b3bbd8540 Handlebars.Net.Helpers Version="1.1.0" (#525) 2020-10-17 08:47:11 +02:00
Stef Heyenrath
c465ecdd40 ContinuousIntegrationBuild (#522) 2020-10-16 12:40:55 +02:00
40 changed files with 1063 additions and 340 deletions

View File

@@ -1,3 +1,18 @@
# 1.3.6 (10 November 2020)
- [#529](https://github.com/WireMock-Net/WireMock.Net/pull/529) - Add assertions for ClientIP, Url and ProxyUrl [feature] contributed by [akamud](https://github.com/akamud)
- [#535](https://github.com/WireMock-Net/WireMock.Net/pull/535) - WithCallback should use also use enum HttpStatusCode [bug] contributed by [StefH](https://github.com/StefH)
- [#537](https://github.com/WireMock-Net/WireMock.Net/pull/537) - Add Custom Certificate settings [feature] contributed by [StefH](https://github.com/StefH)
- [#533](https://github.com/WireMock-Net/WireMock.Net/issues/533) - Stubbed response with only callback returns unexpected status code. [bug]
- [#536](https://github.com/WireMock-Net/WireMock.Net/issues/536) - Overriding the default ssl certificate via file. [feature]
# 1.3.5 (04 November 2020)
- [#530](https://github.com/WireMock-Net/WireMock.Net/pull/530) - Fix dotnet-sonarscanner [bug] contributed by [StefH](https://github.com/StefH)
- [#531](https://github.com/WireMock-Net/WireMock.Net/pull/531) - Add WithCallback-Async [feature] contributed by [StefH](https://github.com/StefH)
# 1.3.4 (17 October 2020)
- [#522](https://github.com/WireMock-Net/WireMock.Net/pull/522) - Add ContinuousIntegrationBuild property [feature] contributed by [StefH](https://github.com/StefH)
- [#525](https://github.com/WireMock-Net/WireMock.Net/pull/525) - Handlebars.Net.Helpers Version=&quot;1.1.0&quot; [feature] contributed by [StefH](https://github.com/StefH)
# 1.3.3 (15 October 2020)
- [#520](https://github.com/WireMock-Net/WireMock.Net/pull/520) - Make kestrel limits configurable contributed by [eduherminio](https://github.com/eduherminio)
- [#521](https://github.com/WireMock-Net/WireMock.Net/issues/521) - Make Kestrel limits configurable [feature]

View File

@@ -4,7 +4,7 @@
</PropertyGroup>
<PropertyGroup>
<VersionPrefix>1.3.3</VersionPrefix>
<VersionPrefix>1.3.6</VersionPrefix>
<PackageReleaseNotes>See CHANGELOG.md</PackageReleaseNotes>
<PackageIconUrl>https://raw.githubusercontent.com/WireMock-Net/WireMock.Net/master/WireMock.Net-Logo.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>
@@ -14,6 +14,10 @@
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition="'$(TF_BUILD)' == 'true'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
<Choose>
<!-- The environment variable `Prerelease` is set in the azure-pipelines.yml file. -->
<When Condition=" '$(Prerelease)' != '' ">
@@ -23,4 +27,4 @@
</PropertyGroup>
</When>
</Choose>
</Project>
</Project>

View File

@@ -1,3 +1,3 @@
https://github.com/StefH/GitHubReleaseNotes
GitHubReleaseNotes.exe --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc --version 1.3.3
GitHubReleaseNotes.exe --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc --version 1.3.6

View File

@@ -71,6 +71,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.WebApplication
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.WebApplication.NETCore3", "examples\WireMock.Net.WebApplication.NETCore3\WireMock.Net.WebApplication.NETCore3.csproj", "{E1C56967-3DC7-46CB-A1DF-B13167A0D9D4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Console.NETCoreApp3WithCertificate", "examples\WireMock.Net.Console.NETCoreApp3WithCertificate\WireMock.Net.Console.NETCoreApp3WithCertificate.csproj", "{925E421A-1B3F-4202-B48F-734743573A4B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -173,6 +175,10 @@ Global
{E1C56967-3DC7-46CB-A1DF-B13167A0D9D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1C56967-3DC7-46CB-A1DF-B13167A0D9D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1C56967-3DC7-46CB-A1DF-B13167A0D9D4}.Release|Any CPU.Build.0 = Release|Any CPU
{925E421A-1B3F-4202-B48F-734743573A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{925E421A-1B3F-4202-B48F-734743573A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{925E421A-1B3F-4202-B48F-734743573A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{925E421A-1B3F-4202-B48F-734743573A4B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -202,6 +208,7 @@ Global
{B6269AAC-170A-4346-8B9A-579DED3D9A95} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{6F38CB3A-6DA1-408A-AECD-E434523C2838} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{E1C56967-3DC7-46CB-A1DF-B13167A0D9D4} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{925E421A-1B3F-4202-B48F-734743573A4B} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}

View File

@@ -28,7 +28,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
<PackageReference Include="Handlebars.Net.Helpers" Version="1.0.0" />
<PackageReference Include="Handlebars.Net.Helpers" Version="1.1.0" />
<PackageReference Include="log4net" Version="2.0.8" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<!--<PackageReference Include="Microsoft.CodeAnalysis.Scripting.Common" Version="3.4.0" />-->

View File

@@ -0,0 +1,36 @@
using WireMock.Logging;
using WireMock.Server;
using WireMock.Settings;
namespace WireMock.Net.Console.NETCoreApp3WithCertificate
{
class Program
{
static void Main(string[] args)
{
string url = "https://localhost:8433/";
var server = WireMockServer.Start(new WireMockServerSettings
{
Urls = new[] { url },
StartAdminInterface = true,
Logger = new WireMockConsoleLogger(),
CertificateSettings = new WireMockCertificateSettings
{
X509StoreName = "My",
X509StoreLocation = "CurrentUser",
X509StoreThumbprintOrSubjectName = "FE16586076A8B3F3E2F1466803A6C4C7CA35455B"
// X509CertificateFilePath = "example.pfx",
// X509CertificatePassword = "wiremock"
}
});
System.Console.WriteLine("WireMockServer listening at {0}", string.Join(",", server.Urls));
System.Console.WriteLine("Press any key to stop the server");
System.Console.ReadKey();
server.Stop();
}
}
}

View File

@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="example.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,28 @@
-----BEGIN CERTIFICATE-----
MIIEsDCCApigAwIBAgIQJbH6hSGKdoFI0B7qCIOK7jANBgkqhkiG9w0BAQUFADAU
MRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjAxMDMwMjMwMDAwWhcNMzAxMTA2MjMw
MDAwWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQCl5fQSrRgT3Q6WoULR98Y+rrDWtTTgVpbLU04G0hLZ4yUeP7Wa
yuVbvx7zX8XT4lA8Hu5T/GG91U077JcSSEjnPBFsh4hE7FkRoSYIEW6BFG7D7eUG
dGHnDV8UkSRQ97LJPyjXuHVDJzNDJ9xQGMzOZ4n8vQ7SEKBw9hRG2ugkP5b2jVIN
e1E549tq2jnIVpKCZ4+prf64ZLsaokX7VHe+b/CW3GoAqUUaUjdTpAQ7LpypJuFz
415enOrKQe+UEBdqhGlgcC/O/Bw0uq4qVk+NNe5DEINVwoYs9XjNdzxuIkkAtcCt
avTEzhHf8zWYLb5Nt2DIOcRGVELvRhsBX4um5f7dOGzMbXzBfUdjkP2O4hi6crhm
Hba5bNkj4Zw2EHR9Xua3nadGCj22z0vpMKP2gXdFVnxFqQlaUWBLtwwN9p6tCQHl
kU7wypvOHUsMa2Ojg5eZP4RpYFvZG3kkc9zTZCSakgw2n0ampBbvxPP11/AYIXtz
HKu3CKcpjVQ+lE0DAU/Mm77QJ24TMbXmAydwCf1UCdFbDUZhdM9lspHvA0J9eiCv
LOE94BrpVKuZ6TrAW0LZjAmBnkqYQAewhTW7GSgARE+QQcwfyu03Ck7id3Zt4FeQ
sQDo0NNj7zQOy3Y1GK0ZYAVZv/GUeHMkxpClSWPoub/f5SJ4YzD5Il0cQQIDAQAB
MA0GCSqGSIb3DQEBBQUAA4ICAQBd91xfUepnWcKwmupie2h1CAAQZEunyW78i++t
evABfBu0TgV4s6Xe0umFv9V4r+O+rrF3ddSudbSOPBEb0Ooe+e3YGlNk1JrI1EEn
fhb0YI8bMfBNpl85yNqxgByra7JF2mG4qbAnjrCs/PZkXo/34N29SY6dyZ7mffR3
r/l01Rdm3ogRwGkiMUeKb3iGwLUy1T55svuI3Zc13N+NJT1s9NqpwWeK/jFK/WRN
5Hi9W3DmlGCYAwFPCyBaQagxpGuGIpNsU0hKp86W5EvJpBpmCihfwlydH8ZbkHJ9
jx2UDgTCaDzmaiKysiTP2HHDBsReL4tjakBksa9jkTfy5ajB53F3aUVs4jvTA46L
w8wcAJlRPBz5siBrv4CH/0lBMyNeYzuqmDY3ulF4IMKNb5Kk9Ye4Pt0474z50A4v
fSah+9iwI/mubaJ5tK522AtWtUoOIAswIwpDQyNeJPOggyzT2Y2OYZdGuFAoMYuq
ZD58k4Yo+vky9K88l8NuzNJJvtgTKtT+/9qfMucxFmnvwbKEEULP3sw1FUKkPtM4
f242FIV/XnOeloDmhGGeTB7aODB+gGCvgmOH92njjUEIv+SnYQkflQaRhhyNIACi
ZvWlP/96H+X4fUG5kVNBHY021ZWmurUDqVxWUaswg63+DfsZcYtt6wgxiAN4ssXG
wLnLPw==
-----END CERTIFICATE-----

View File

@@ -12,6 +12,7 @@ using WireMock.ResponseBuilders;
using WireMock.Server;
using WireMock.Settings;
using WireMock.Util;
using System.Threading.Tasks;
namespace WireMock.Net.ConsoleApplication
{
@@ -249,6 +250,13 @@ namespace WireMock.Net.ConsoleApplication
.WithProxy("http://www.google.com")
);
server
.Given(Request.Create().WithHeader("ProxyThisHttps", "true")
.UsingGet())
.RespondWith(Response.Create()
.WithProxy("https://www.google.com")
);
server
.Given(Request.Create().WithPath("/bodyasbytes.png")
.UsingGet())
@@ -521,9 +529,29 @@ namespace WireMock.Net.ConsoleApplication
.WithBodyAsJson(new { Id = "5bdf076c-5654-4b3e-842c-7caf1fabf8c9" }));
server
.Given(Request.Create().WithPath("/random200or505").UsingGet())
.RespondWith(Response.Create().WithCallback(request => new ResponseMessage
.RespondWith(Response.Create().WithCallback(request =>
{
StatusCode = new Random().Next(1, 100) == 1 ? 504 : 200
int code = new Random().Next(1, 2) == 1 ? 505 : 200;
return new ResponseMessage
{
BodyData = new BodyData { BodyAsString = "random200or505:" + code, DetectedBodyType = Types.BodyType.String },
StatusCode = code
};
}));
server
.Given(Request.Create().WithPath("/random200or505async").UsingGet())
.RespondWith(Response.Create().WithCallback(async request =>
{
await Task.Delay(1);
int code = new Random().Next(1, 2) == 1 ? 505 : 200;
return new ResponseMessage
{
BodyData = new BodyData { BodyAsString = "random200or505async:" + code, DetectedBodyType = Types.BodyType.String },
StatusCode = code
};
}));
System.Console.WriteLine(JsonConvert.SerializeObject(server.MappingModels, Formatting.Indented));

View File

@@ -16,8 +16,7 @@ namespace WireMock.FluentAssertions
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> AtAbsoluteUrl(string absoluteUrl, string because = "",
params object[] becauseArgs)
public AndConstraint<WireMockAssertions> AtAbsoluteUrl(string absoluteUrl, string because = "", params object[] becauseArgs)
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
@@ -36,13 +35,11 @@ namespace WireMock.FluentAssertions
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithHeader(string expectedKey, string value,
string because = "", params object[] becauseArgs)
public AndConstraint<WireMockAssertions> WithHeader(string expectedKey, string value, string because = "", params object[] becauseArgs)
=> WithHeader(expectedKey, new[] {value}, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithHeader(string expectedKey, string[] expectedValues,
string because = "", params object[] becauseArgs)
public AndConstraint<WireMockAssertions> WithHeader(string expectedKey, string[] expectedValues, string because = "", params object[] becauseArgs)
{
var headersDictionary = _subject.LogEntries.SelectMany(x => x.RequestMessage.Headers)
.ToDictionary(x => x.Key, x => x.Value);
@@ -72,5 +69,62 @@ namespace WireMock.FluentAssertions
return new AndConstraint<WireMockAssertions>(this);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> AtUrl(string url, string because = "", params object[] becauseArgs)
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
.Given(() => _subject.LogEntries.Select(x => x.RequestMessage).ToList())
.ForCondition(requests => requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called at address matching the url {0}{reason}, but no calls were made.",
url)
.Then
.ForCondition(x => x.Any(y => y.Url == url))
.FailWith(
"Expected {context:wiremockserver} to have been called at address matching the url {0}{reason}, but didn't find it among the calls to {1}.",
_ => url, requests => requests.Select(request => request.Url));
return new AndConstraint<WireMockAssertions>(this);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithProxyUrl(string proxyUrl, string because = "", params object[] becauseArgs)
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
.Given(() => _subject.LogEntries.Select(x => x.RequestMessage).ToList())
.ForCondition(requests => requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called with proxy url {0}{reason}, but no calls were made.",
proxyUrl)
.Then
.ForCondition(x => x.Any(y => y.ProxyUrl == proxyUrl))
.FailWith(
"Expected {context:wiremockserver} to have been called with proxy url {0}{reason}, but didn't find it among the calls with {1}.",
_ => proxyUrl, requests => requests.Select(request => request.ProxyUrl));
return new AndConstraint<WireMockAssertions>(this);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> FromClientIP(string clientIP, string because = "", params object[] becauseArgs)
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
.Given(() => _subject.LogEntries.Select(x => x.RequestMessage).ToList())
.ForCondition(requests => requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called from client IP {0}{reason}, but no calls were made.",
clientIP)
.Then
.ForCondition(x => x.Any(y => y.ClientIP == clientIP))
.FailWith(
"Expected {context:wiremockserver} to have been called from client IP {0}{reason}, but didn't find it among the calls from IP(s) {1}.",
_ => clientIP, requests => requests.Select(request => request.ClientIP));
return new AndConstraint<WireMockAssertions>(this);
}
}
}

View File

@@ -41,7 +41,7 @@ namespace WireMock.Http
{
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
var x509Certificate2 = ClientCertificateHelper.GetCertificate(settings.ClientX509Certificate2ThumbprintOrSubjectName);
var x509Certificate2 = CertificateLoader.LoadCertificate(settings.ClientX509Certificate2ThumbprintOrSubjectName);
handler.ClientCertificates.Add(x509Certificate2);
}

View File

@@ -0,0 +1,100 @@
using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace WireMock.HttpsCertificate
{
internal static class CertificateLoader
{
/// <summary>
/// Used by the WireMock.Net server
/// </summary>
public static X509Certificate2 LoadCertificate(
string storeName,
string storeLocation,
string thumbprintOrSubjectName,
string filePath,
string password,
string host)
{
if (!string.IsNullOrEmpty(storeName) && !string.IsNullOrEmpty(storeLocation))
{
var thumbprintOrSubjectNameOrHost = thumbprintOrSubjectName ?? host;
var certStore = new X509Store((StoreName)Enum.Parse(typeof(StoreName), storeName), (StoreLocation)Enum.Parse(typeof(StoreLocation), storeLocation));
try
{
certStore.Open(OpenFlags.ReadOnly);
// Attempt to find by Thumbprint first
var matchingCertificates = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprintOrSubjectNameOrHost, false);
if (matchingCertificates.Count == 0)
{
// Fallback to SubjectName
matchingCertificates = certStore.Certificates.Find(X509FindType.FindBySubjectName, thumbprintOrSubjectNameOrHost, false);
if (matchingCertificates.Count == 0)
{
// No certificates matched the search criteria.
throw new FileNotFoundException($"No Certificate found with in store '{storeName}', location '{storeLocation}' for Thumbprint or SubjectName '{thumbprintOrSubjectNameOrHost}'.");
}
}
// Use the first matching certificate.
return matchingCertificates[0];
}
finally
{
#if NETSTANDARD || NET46
certStore.Dispose();
#else
certStore.Close();
#endif
}
}
if (!string.IsNullOrEmpty(filePath) && !string.IsNullOrEmpty(password))
{
return new X509Certificate2(filePath, password);
}
throw new InvalidOperationException("X509StoreName and X509StoreLocation OR X509CertificateFilePath and X509CertificatePassword are mandatory.");
}
/// <summary>
/// Used for Proxy
/// </summary>
public static X509Certificate2 LoadCertificate(string thumbprintOrSubjectName)
{
var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
// Certificate must be in the local machine store
certStore.Open(OpenFlags.ReadOnly);
// Attempt to find by Thumbprint first
var matchingCertificates = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprintOrSubjectName, false);
if (matchingCertificates.Count == 0)
{
// Fallback to SubjectName
matchingCertificates = certStore.Certificates.Find(X509FindType.FindBySubjectName, thumbprintOrSubjectName, false);
if (matchingCertificates.Count == 0)
{
// No certificates matched the search criteria.
throw new FileNotFoundException("No certificate found with specified Thumbprint or SubjectName.", thumbprintOrSubjectName);
}
}
// Use the first matching certificate.
return matchingCertificates[0];
}
finally
{
#if NETSTANDARD || NET46
certStore.Dispose();
#else
certStore.Close();
#endif
}
}
}
}

View File

@@ -1,42 +0,0 @@
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace WireMock.HttpsCertificate
{
internal static class ClientCertificateHelper
{
public static X509Certificate2 GetCertificate(string thumbprintOrSubjectName)
{
X509Store certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
// Certificate must be in the local machine store
certStore.Open(OpenFlags.ReadOnly);
// Attempt to find by thumbprint first
var matchingCertificates = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprintOrSubjectName, false);
if (matchingCertificates.Count == 0)
{
// Fallback to subject name
matchingCertificates = certStore.Certificates.Find(X509FindType.FindBySubjectName, thumbprintOrSubjectName, false);
if (matchingCertificates.Count == 0)
{
// No certificates matched the search criteria.
throw new FileNotFoundException("No certificate found with specified Thumbprint or SubjectName.", thumbprintOrSubjectName);
}
}
// Use the first matching certificate.
return matchingCertificates[0];
}
finally
{
#if NETSTANDARD || NET46
certStore.Dispose();
#else
certStore.Close();
#endif
}
}
}
}

View File

@@ -1,10 +1,10 @@
#if USE_ASPNETCORE && !NETSTANDARD1_3
using System;
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;
namespace WireMock.Owin
{
@@ -18,20 +18,34 @@ namespace WireMock.Owin
options.Limits.MaxResponseBufferSize = null;
}
private static void SetHttpsAndUrls(KestrelServerOptions options, ICollection<(string Url, int Port)> urlDetails)
private static void SetHttpsAndUrls(KestrelServerOptions kestrelOptions, IWireMockMiddlewareOptions wireMockMiddlewareOptions, IEnumerable<HostUrlDetails> urlDetails)
{
foreach (var detail in urlDetails)
foreach (var urlDetail in urlDetails)
{
if (detail.Url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
if (urlDetail.IsHttps)
{
options.Listen(System.Net.IPAddress.Any, detail.Port, listenOptions =>
kestrelOptions.Listen(System.Net.IPAddress.Any, urlDetail.Port, listenOptions =>
{
listenOptions.UseHttps();
if (wireMockMiddlewareOptions.CustomCertificateDefined)
{
listenOptions.UseHttps(CertificateLoader.LoadCertificate(
wireMockMiddlewareOptions.X509StoreName,
wireMockMiddlewareOptions.X509StoreLocation,
wireMockMiddlewareOptions.X509ThumbprintOrSubjectName,
wireMockMiddlewareOptions.X509CertificateFilePath,
wireMockMiddlewareOptions.X509CertificatePassword,
urlDetail.Host)
);
}
else
{
listenOptions.UseHttps();
}
});
}
else
{
options.Listen(System.Net.IPAddress.Any, detail.Port);
kestrelOptions.Listen(System.Net.IPAddress.Any, urlDetail.Port);
}
}
}

View File

@@ -1,7 +1,5 @@
#if USE_ASPNETCORE && NETSTANDARD1_3
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel;
using Microsoft.Extensions.Configuration;
@@ -19,12 +17,28 @@ namespace WireMock.Owin
options.Limits.MaxResponseBufferSize = null;
}
private static void SetHttpsAndUrls(KestrelServerOptions options, ICollection<(string Url, int Port)> urlDetails)
private static void SetHttpsAndUrls(KestrelServerOptions options, IWireMockMiddlewareOptions wireMockMiddlewareOptions, IEnumerable<HostUrlDetails> urlDetails)
{
var urls = urlDetails.Select(u => u.Url);
if (urls.Any(u => u.StartsWith("https://", StringComparison.OrdinalIgnoreCase)))
foreach (var urlDetail in urlDetails)
{
options.UseHttps(PublicCertificateHelper.GetX509Certificate2());
if (urlDetail.IsHttps)
{
if (wireMockMiddlewareOptions.CustomCertificateDefined)
{
options.UseHttps(CertificateLoader.LoadCertificate(
wireMockMiddlewareOptions.X509StoreName,
wireMockMiddlewareOptions.X509StoreLocation,
wireMockMiddlewareOptions.X509ThumbprintOrSubjectName,
wireMockMiddlewareOptions.X509CertificateFilePath,
wireMockMiddlewareOptions.X509CertificatePassword,
urlDetail.Host)
);
}
else
{
options.UseHttps(PublicCertificateHelper.GetX509Certificate2());
}
}
}
}
}

View File

@@ -18,7 +18,7 @@ namespace WireMock.Owin
internal partial class AspNetCoreSelfHost : IOwinSelfHost
{
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private readonly IWireMockMiddlewareOptions _options;
private readonly IWireMockMiddlewareOptions _wireMockMiddlewareOptions;
private readonly IWireMockLogger _logger;
private readonly HostUrlOptions _urlOptions;
@@ -33,14 +33,14 @@ namespace WireMock.Owin
public Exception RunningException => _runningException;
public AspNetCoreSelfHost([NotNull] IWireMockMiddlewareOptions options, [NotNull] HostUrlOptions urlOptions)
public AspNetCoreSelfHost([NotNull] IWireMockMiddlewareOptions wireMockMiddlewareOptions, [NotNull] HostUrlOptions urlOptions)
{
Check.NotNull(options, nameof(options));
Check.NotNull(wireMockMiddlewareOptions, nameof(wireMockMiddlewareOptions));
Check.NotNull(urlOptions, nameof(urlOptions));
_logger = options.Logger ?? new WireMockConsoleLogger();
_logger = wireMockMiddlewareOptions.Logger ?? new WireMockConsoleLogger();
_options = options;
_wireMockMiddlewareOptions = wireMockMiddlewareOptions;
_urlOptions = urlOptions;
}
@@ -61,7 +61,7 @@ namespace WireMock.Owin
.ConfigureAppConfigurationUsingEnvironmentVariables()
.ConfigureServices(services =>
{
services.AddSingleton(_options);
services.AddSingleton(_wireMockMiddlewareOptions);
services.AddSingleton<IMappingMatcher, MappingMatcher>();
services.AddSingleton<IOwinRequestMapper, OwinRequestMapper>();
services.AddSingleton<IOwinResponseMapper, OwinResponseMapper>();
@@ -70,17 +70,17 @@ namespace WireMock.Owin
{
appBuilder.UseMiddleware<GlobalExceptionMiddleware>();
_options.PreWireMockMiddlewareInit?.Invoke(appBuilder);
_wireMockMiddlewareOptions.PreWireMockMiddlewareInit?.Invoke(appBuilder);
appBuilder.UseMiddleware<WireMockMiddleware>();
_options.PostWireMockMiddlewareInit?.Invoke(appBuilder);
_wireMockMiddlewareOptions.PostWireMockMiddlewareInit?.Invoke(appBuilder);
})
.UseKestrel(options =>
{
SetKestrelOptionsLimits(options);
SetHttpsAndUrls(options, _urlOptions.GetDetails());
SetHttpsAndUrls(options, _wireMockMiddlewareOptions, _urlOptions.GetDetails());
})
.ConfigureKestrelServerOptions()
@@ -107,7 +107,7 @@ namespace WireMock.Owin
{
Urls.Add(address.Replace("0.0.0.0", "localhost"));
PortUtils.TryExtract(address, out string protocol, out string host, out int port);
PortUtils.TryExtract(address, out bool isHttps, out string protocol, out string host, out int port);
Ports.Add(port);
}

View File

@@ -0,0 +1,15 @@
namespace WireMock.Owin
{
internal class HostUrlDetails
{
public bool IsHttps { get; set; }
public string Url { get; set; }
public string Protocol { get; set; }
public string Host { get; set; }
public int Port { get; set; }
}
}

View File

@@ -5,26 +5,29 @@ namespace WireMock.Owin
{
internal class HostUrlOptions
{
private const string LOCALHOST = "localhost";
public ICollection<string> Urls { get; set; }
public int? Port { get; set; }
public bool UseSSL { get; set; }
public ICollection<(string Url, int Port)> GetDetails()
public ICollection<HostUrlDetails> GetDetails()
{
var list = new List<(string Url, int Port)>();
var list = new List<HostUrlDetails>();
if (Urls == null)
{
int port = Port > 0 ? Port.Value : FindFreeTcpPort();
list.Add(($"{(UseSSL ? "https" : "http")}://localhost:{port}", port));
string protocol = UseSSL ? "https" : "http";
list.Add(new HostUrlDetails { IsHttps = UseSSL, Url = $"{protocol}://{LOCALHOST}:{port}", Protocol = protocol, Host = LOCALHOST, Port = port });
}
else
{
foreach (string url in Urls)
{
PortUtils.TryExtract(url, out string protocol, out string host, out int port);
list.Add((url, port));
PortUtils.TryExtract(url, out bool isHttps, out string protocol, out string host, out int port);
list.Add(new HostUrlDetails { IsHttps = isHttps, Url = url, Protocol = protocol, Host = host, Port = port });
}
}

View File

@@ -47,5 +47,17 @@ namespace WireMock.Owin
bool? DisableRequestBodyDecompressing { get; set; }
bool? HandleRequestsSynchronously { get; set; }
string X509StoreName { get; set; }
string X509StoreLocation { get; set; }
string X509ThumbprintOrSubjectName { get; set; }
string X509CertificateFilePath { get; set; }
string X509CertificatePassword { get; set; }
bool CustomCertificateDefined { get; }
}
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
@@ -79,16 +80,21 @@ namespace WireMock.Owin.Mappers
break;
}
switch (responseMessage.StatusCode)
var statusCodeType = responseMessage.StatusCode?.GetType();
switch (statusCodeType)
{
case int statusCodeAsInteger:
response.StatusCode = MapStatusCode(statusCodeAsInteger);
case Type typeAsIntOrEnum when typeAsIntOrEnum == typeof(int) || typeAsIntOrEnum == typeof(int?) || typeAsIntOrEnum.GetTypeInfo().IsEnum:
response.StatusCode = MapStatusCode((int)responseMessage.StatusCode);
break;
case Type typeAsString when typeAsString == typeof(string):
// Note: this case will also match on null
int.TryParse(responseMessage.StatusCode as string, out int result);
response.StatusCode = MapStatusCode(result);
break;
case string statusCodeAsString:
// Note: this case will also match on null
int.TryParse(statusCodeAsString, out int result);
response.StatusCode = MapStatusCode(result);
default:
break;
}

View File

@@ -53,5 +53,25 @@ namespace WireMock.Owin
/// <inheritdoc cref="IWireMockMiddlewareOptions.HandleRequestsSynchronously"/>
public bool? HandleRequestsSynchronously { get; set; }
/// <inheritdoc cref="IWireMockMiddlewareOptions.X509StoreName"/>
public string X509StoreName { get; set; }
/// <inheritdoc cref="IWireMockMiddlewareOptions.X509StoreLocation"/>
public string X509StoreLocation { get; set; }
/// <inheritdoc cref="IWireMockMiddlewareOptions.X509ThumbprintOrSubjectName"/>
public string X509ThumbprintOrSubjectName { get; set; }
/// <inheritdoc cref="IWireMockMiddlewareOptions.X509CertificateFilePath"/>
public string X509CertificateFilePath { get; set; }
/// <inheritdoc cref="IWireMockMiddlewareOptions.X509CertificatePassword"/>
public string X509CertificatePassword { get; set; }
/// <inheritdoc cref="IWireMockMiddlewareOptions.CustomCertificateDefined"/>
public bool CustomCertificateDefined =>
!string.IsNullOrEmpty(X509StoreName) && !string.IsNullOrEmpty(X509StoreLocation) ||
!string.IsNullOrEmpty(X509CertificateFilePath) && !string.IsNullOrEmpty(X509CertificatePassword);
}
}

View File

@@ -1,19 +1,27 @@
using System;
using JetBrains.Annotations;
using WireMock.ResponseProviders;
namespace WireMock.ResponseBuilders
{
/// <summary>
/// The CallbackResponseBuilder interface.
/// </summary>
public interface ICallbackResponseBuilder : IResponseProvider
{
/// <summary>
/// The callback builder
/// </summary>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
[PublicAPI]
IResponseBuilder WithCallback([NotNull] Func<RequestMessage, ResponseMessage> callbackHandler);
}
using System;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.ResponseProviders;
namespace WireMock.ResponseBuilders
{
/// <summary>
/// The CallbackResponseBuilder interface.
/// </summary>
public interface ICallbackResponseBuilder : IResponseProvider
{
/// <summary>
/// The callback builder
/// </summary>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
[PublicAPI]
IResponseBuilder WithCallback([NotNull] Func<RequestMessage, ResponseMessage> callbackHandler);
/// <summary>
/// The async callback builder
/// </summary>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
[PublicAPI]
IResponseBuilder WithCallback([NotNull] Func<RequestMessage, Task<ResponseMessage>> callbackHandler);
}
}

View File

@@ -0,0 +1,60 @@
using System;
using System.Threading.Tasks;
using WireMock.Validation;
namespace WireMock.ResponseBuilders
{
public partial class Response
{
/// <summary>
/// A delegate to execute to generate the response.
/// </summary>
public Func<RequestMessage, ResponseMessage> Callback { get; private set; }
/// <summary>
/// A delegate to execute to generate the response async.
/// </summary>
public Func<RequestMessage, Task<ResponseMessage>> CallbackAsync { get; private set; }
/// <summary>
/// Defines if the method WithCallback(...) is used.
/// </summary>
public bool WithCallbackUsed { get; private set; }
/// <inheritdoc cref="ICallbackResponseBuilder.WithCallback(Func{RequestMessage, ResponseMessage})"/>
public IResponseBuilder WithCallback(Func<RequestMessage, ResponseMessage> callbackHandler)
{
Check.NotNull(callbackHandler, nameof(callbackHandler));
return WithCallbackInternal(true, callbackHandler);
}
/// <inheritdoc cref="ICallbackResponseBuilder.WithCallback(Func{RequestMessage, Task{ResponseMessage}})"/>
public IResponseBuilder WithCallback(Func<RequestMessage, Task<ResponseMessage>> callbackHandler)
{
Check.NotNull(callbackHandler, nameof(callbackHandler));
return WithCallbackInternal(true, callbackHandler);
}
private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func<RequestMessage, ResponseMessage> callbackHandler)
{
Check.NotNull(callbackHandler, nameof(callbackHandler));
WithCallbackUsed = withCallbackUsed;
Callback = callbackHandler;
return this;
}
private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func<RequestMessage, Task<ResponseMessage>> callbackHandler)
{
Check.NotNull(callbackHandler, nameof(callbackHandler));
WithCallbackUsed = withCallbackUsed;
CallbackAsync = callbackHandler;
return this;
}
}
}

View File

@@ -42,16 +42,6 @@ namespace WireMock.ResponseBuilders
/// </summary>
public ResponseMessage ResponseMessage { get; }
/// <summary>
/// A delegate to execute to generate the response.
/// </summary>
public Func<RequestMessage, ResponseMessage> Callback { get; private set; }
/// <summary>
/// Defines if the method WithCallback(...) is used.
/// </summary>
public bool WithCallbackUsed { get; private set; }
/// <summary>
/// Creates this instance.
/// </summary>
@@ -311,25 +301,6 @@ namespace WireMock.ResponseBuilders
return WithDelay(TimeSpan.FromMilliseconds(milliseconds));
}
/// <inheritdoc cref="ICallbackResponseBuilder.WithCallback"/>
public IResponseBuilder WithCallback(Func<RequestMessage, ResponseMessage> callbackHandler)
{
Check.NotNull(callbackHandler, nameof(callbackHandler));
return WithCallbackInternal(true, callbackHandler);
}
/// <inheritdoc cref="ICallbackResponseBuilder.WithCallback"/>
private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func<RequestMessage, ResponseMessage> callbackHandler)
{
Check.NotNull(callbackHandler, nameof(callbackHandler));
WithCallbackUsed = withCallbackUsed;
Callback = callbackHandler;
return this;
}
/// <inheritdoc cref="IResponseProvider.ProvideResponseAsync(RequestMessage, IWireMockServerSettings)"/>
public async Task<ResponseMessage> ProvideResponseAsync(RequestMessage requestMessage, IWireMockServerSettings settings)
{
@@ -365,13 +336,20 @@ namespace WireMock.ResponseBuilders
}
ResponseMessage responseMessage;
if (Callback == null)
if (Callback == null && CallbackAsync == null)
{
responseMessage = ResponseMessage;
}
else
{
responseMessage = Callback(requestMessage);
if (Callback != null)
{
responseMessage = Callback(requestMessage);
}
else
{
responseMessage = await CallbackAsync(requestMessage);
}
if (!WithCallbackUsed)
{

View File

@@ -230,6 +230,15 @@ namespace WireMock.Server
_options.DisableJsonBodyParsing = _settings.DisableJsonBodyParsing;
_options.HandleRequestsSynchronously = settings.HandleRequestsSynchronously;
if (settings.CustomCertificateDefined)
{
_options.X509StoreName = settings.CertificateSettings.X509StoreName;
_options.X509StoreLocation = settings.CertificateSettings.X509StoreLocation;
_options.X509ThumbprintOrSubjectName = settings.CertificateSettings.X509StoreThumbprintOrSubjectName;
_options.X509CertificateFilePath = settings.CertificateSettings.X509CertificateFilePath;
_options.X509CertificatePassword = settings.CertificateSettings.X509CertificatePassword;
}
_matcherMapper = new MatcherMapper(_settings);
_mappingConverter = new MappingConverter(_matcherMapper);

View File

@@ -0,0 +1,44 @@
namespace WireMock.Settings
{
/// <summary>
/// If https is used, these settings can be used to configure the CertificateSettings in case a custom certificate instead the default .NET certificate should be used.
///
/// X509StoreName and X509StoreLocation should be defined
/// OR
/// X509CertificateFilePath and X509CertificatePassword should be defined
/// </summary>
public interface IWireMockCertificateSettings
{
/// <summary>
/// X509 StoreName (AddressBook, AuthRoot, CertificateAuthority, My, Root, TrustedPeople or TrustedPublisher)
/// </summary>
string X509StoreName { get; set; }
/// <summary>
/// X509 StoreLocation (CurrentUser or LocalMachine)
/// </summary>
string X509StoreLocation { get; set; }
/// <summary>
/// X509 Thumbprint or SubjectName (if not defined, the 'host' is used)
/// </summary>
string X509StoreThumbprintOrSubjectName { get; set; }
/// <summary>
/// X509Certificate FilePath
/// </summary>
string X509CertificateFilePath { get; set; }
/// <summary>
/// X509Certificate Password
/// </summary>
string X509CertificatePassword { get; set; }
/// <summary>
/// X509StoreName and X509StoreLocation should be defined
/// OR
/// X509CertificateFilePath and X509CertificatePassword should be defined
/// </summary>
bool IsDefined { get; }
}
}

View File

@@ -170,5 +170,21 @@ namespace WireMock.Settings
/// </summary>
[PublicAPI]
bool? ThrowExceptionWhenMatcherFails { get; set; }
/// <summary>
/// If https is used, these settings can be used to configure the CertificateSettings in case a custom certificate instead the default .NET certificate should be used.
///
/// X509StoreName and X509StoreLocation should be defined
/// OR
/// X509CertificateFilePath and X509CertificatePassword should be defined
/// </summary>
[PublicAPI]
IWireMockCertificateSettings CertificateSettings { get; set; }
/// <summary>
/// Defines if custom CertificateSettings are defined
/// </summary>
[PublicAPI]
bool CustomCertificateDefined { get; }
}
}

View File

@@ -0,0 +1,36 @@
using JetBrains.Annotations;
namespace WireMock.Settings
{
/// <summary>
/// <see cref="IWireMockCertificateSettings"/>
/// </summary>
public class WireMockCertificateSettings : IWireMockCertificateSettings
{
/// <inheritdoc cref="IWireMockCertificateSettings.X509StoreName"/>
[PublicAPI]
public string X509StoreName { get; set; }
/// <inheritdoc cref="IWireMockCertificateSettings.X509StoreLocation"/>
[PublicAPI]
public string X509StoreLocation { get; set; }
/// <inheritdoc cref="IWireMockCertificateSettings.X509StoreThumbprintOrSubjectName"/>
[PublicAPI]
public string X509StoreThumbprintOrSubjectName { get; set; }
/// <inheritdoc cref="IWireMockCertificateSettings.X509CertificateFilePath"/>
[PublicAPI]
public string X509CertificateFilePath { get; set; }
/// <inheritdoc cref="IWireMockCertificateSettings.X509CertificatePassword"/>
[PublicAPI]
public string X509CertificatePassword { get; set; }
/// <inheritdoc cref="IWireMockCertificateSettings.IsDefined"/>
[PublicAPI]
public bool IsDefined =>
!string.IsNullOrEmpty(X509StoreName) && !string.IsNullOrEmpty(X509StoreLocation) ||
!string.IsNullOrEmpty(X509CertificateFilePath) && !string.IsNullOrEmpty(X509CertificatePassword);
}
}

View File

@@ -1,6 +1,6 @@
using HandlebarsDotNet;
using System;
using HandlebarsDotNet;
using JetBrains.Annotations;
using System;
using Newtonsoft.Json;
using WireMock.Handlers;
using WireMock.Logging;
@@ -121,5 +121,13 @@ namespace WireMock.Settings
/// <inheritdoc cref="IWireMockServerSettings.ThrowExceptionWhenMatcherFails"/>
[PublicAPI]
public bool? ThrowExceptionWhenMatcherFails { get; set; }
/// <inheritdoc cref="IWireMockServerSettings.CertificateSettings"/>
[PublicAPI]
public IWireMockCertificateSettings CertificateSettings { get; set; }
/// <inheritdoc cref="IWireMockServerSettings.CustomCertificateDefined"/>
[PublicAPI]
public bool CustomCertificateDefined => CertificateSettings?.IsDefined == true;
}
}

View File

@@ -60,12 +60,12 @@ namespace WireMock.Settings
settings.Urls = parser.GetValues("Urls", new[] { "http://*:9091/" });
}
string proxyURL = parser.GetStringValue("ProxyURL");
if (!string.IsNullOrEmpty(proxyURL))
string proxyUrl = parser.GetStringValue("ProxyURL") ?? parser.GetStringValue("ProxyUrl");
if (!string.IsNullOrEmpty(proxyUrl))
{
settings.ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = proxyURL,
Url = proxyUrl,
SaveMapping = parser.GetBoolValue("SaveMapping"),
SaveMappingToFile = parser.GetBoolValue("SaveMappingToFile"),
SaveMappingForStatusCodePattern = parser.GetStringValue("SaveMappingForStatusCodePattern"),
@@ -87,6 +87,19 @@ namespace WireMock.Settings
}
}
var certificateSettings = new WireMockCertificateSettings
{
X509StoreName = parser.GetStringValue("X509StoreName"),
X509StoreLocation = parser.GetStringValue("X509StoreLocation"),
X509StoreThumbprintOrSubjectName = parser.GetStringValue("X509StoreThumbprintOrSubjectName"),
X509CertificateFilePath = parser.GetStringValue("X509CertificateFilePath"),
X509CertificatePassword = parser.GetStringValue("X509CertificatePassword")
};
if (certificateSettings.IsDefined)
{
settings.CertificateSettings = certificateSettings;
}
return settings;
}
}

View File

@@ -1,4 +1,5 @@
using System.Net;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text.RegularExpressions;
@@ -32,21 +33,23 @@ namespace WireMock.Util
}
/// <summary>
/// Extract the protocol, host and port from a URL.
/// Extract the if-isHttps, protocol, host and port from a URL.
/// </summary>
public static bool TryExtract(string url, out string protocol, out string host, out int port)
public static bool TryExtract(string url, out bool isHttps, out string protocol, out string host, out int port)
{
isHttps = false;
protocol = null;
host = null;
port = default(int);
port = default;
Match m = UrlDetailsRegex.Match(url);
if (m.Success)
var match = UrlDetailsRegex.Match(url);
if (match.Success)
{
protocol = m.Groups["proto"].Value;
host = m.Groups["host"].Value;
protocol = match.Groups["proto"].Value;
isHttps = protocol.StartsWith("https", StringComparison.OrdinalIgnoreCase);
host = match.Groups["host"].Value;
return int.TryParse(m.Groups["port"].Value, out port);
return int.TryParse(match.Groups["port"].Value, out port);
}
return false;

View File

@@ -58,7 +58,7 @@
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.12" />
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.12" />
<PackageReference Include="JmesPath.Net" Version="1.0.125" />
<PackageReference Include="Handlebars.Net.Helpers" Version="1.0.0" />
<PackageReference Include="Handlebars.Net.Helpers" Version="1.1.0" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Debug - Sonar'">

View File

@@ -9,6 +9,7 @@ using WireMock.Server;
using Xunit;
using WireMock.FluentAssertions;
using System.Threading.Tasks;
using WireMock.Settings;
using static System.Environment;
namespace WireMock.Net.Tests.FluentAssertions
@@ -23,10 +24,10 @@ namespace WireMock.Net.Tests.FluentAssertions
{
_server = WireMockServer.Start();
_server.Given(Request.Create().UsingAnyMethod())
.RespondWith(Response.Create().WithStatusCode(200));
.RespondWith(Response.Create().WithSuccess());
_portUsed = _server.Ports.First();
_httpClient = new HttpClient { BaseAddress = new Uri($"http://localhost:{_portUsed}") };
_httpClient = new HttpClient { BaseAddress = new Uri(_server.Urls[0]) };
}
[Fact]
@@ -155,6 +156,134 @@ namespace WireMock.Net.Tests.FluentAssertions
.And.Message.Should()
.Be($"{string.Join(NewLine, missingValue1Message, missingValue2Message)}{NewLine}");
}
[Fact]
public async Task AtUrl_WhenACallWasMadeToUrl_Should_BeOK()
{
await _httpClient.GetAsync("anyurl");
_server.Should()
.HaveReceivedACall()
.AtUrl($"http://localhost:{_portUsed}/anyurl");
}
[Fact]
public void AtUrl_Should_ThrowWhenNoCallsWereMade()
{
Action act = () => _server.Should()
.HaveReceivedACall()
.AtUrl("anyurl");
act.Should().Throw<Exception>()
.And.Message.Should()
.Be(
"Expected _server to have been called at address matching the url \"anyurl\", but no calls were made.");
}
[Fact]
public async Task AtUrl_Should_ThrowWhenNoCallsMatchingTheUrlWereMade()
{
await _httpClient.GetAsync("");
Action act = () => _server.Should()
.HaveReceivedACall()
.AtUrl("anyurl");
act.Should().Throw<Exception>()
.And.Message.Should()
.Be(
$"Expected _server to have been called at address matching the url \"anyurl\", but didn't find it among the calls to {{\"http://localhost:{_portUsed}/\"}}.");
}
[Fact]
public async Task WithProxyUrl_WhenACallWasMadeWithProxyUrl_Should_BeOK()
{
_server.ResetMappings();
_server.Given(Request.Create().UsingAnyMethod())
.RespondWith(Response.Create().WithProxy(new ProxyAndRecordSettings {Url = "http://localhost:9999"}));
await _httpClient.GetAsync("");
_server.Should()
.HaveReceivedACall()
.WithProxyUrl($"http://localhost:9999");
}
[Fact]
public void WithProxyUrl_Should_ThrowWhenNoCallsWereMade()
{
_server.ResetMappings();
_server.Given(Request.Create().UsingAnyMethod())
.RespondWith(Response.Create().WithProxy(new ProxyAndRecordSettings {Url = "http://localhost:9999"}));
Action act = () => _server.Should()
.HaveReceivedACall()
.WithProxyUrl("anyurl");
act.Should().Throw<Exception>()
.And.Message.Should()
.Be(
"Expected _server to have been called with proxy url \"anyurl\", but no calls were made.");
}
[Fact]
public async Task WithProxyUrl_Should_ThrowWhenNoCallsWithTheProxyUrlWereMade()
{
_server.ResetMappings();
_server.Given(Request.Create().UsingAnyMethod())
.RespondWith(Response.Create().WithProxy(new ProxyAndRecordSettings {Url = "http://localhost:9999"}));
await _httpClient.GetAsync("");
Action act = () => _server.Should()
.HaveReceivedACall()
.WithProxyUrl("anyurl");
act.Should().Throw<Exception>()
.And.Message.Should()
.Be(
$"Expected _server to have been called with proxy url \"anyurl\", but didn't find it among the calls with {{\"http://localhost:9999\"}}.");
}
[Fact]
public async Task FromClientIP_whenACallWasMadeFromClientIP_Should_BeOK()
{
await _httpClient.GetAsync("");
var clientIP = _server.LogEntries.Last().RequestMessage.ClientIP;
_server.Should()
.HaveReceivedACall()
.FromClientIP(clientIP);
}
[Fact]
public void FromClientIP_Should_ThrowWhenNoCallsWereMade()
{
Action act = () => _server.Should()
.HaveReceivedACall()
.FromClientIP("different-ip");
act.Should().Throw<Exception>()
.And.Message.Should()
.Be(
"Expected _server to have been called from client IP \"different-ip\", but no calls were made.");
}
[Fact]
public async Task FromClientIP_Should_ThrowWhenNoCallsFromClientIPWereMade()
{
await _httpClient.GetAsync("");
var clientIP = _server.LogEntries.Last().RequestMessage.ClientIP;
Action act = () => _server.Should()
.HaveReceivedACall()
.FromClientIP("different-ip");
act.Should().Throw<Exception>()
.And.Message.Should()
.Be(
$"Expected _server to have been called from client IP \"different-ip\", but didn't find it among the calls from IP(s) {{\"{clientIP}\"}}.");
}
public void Dispose()
{

View File

@@ -1,65 +1,94 @@
using System.Threading.Tasks;
using FluentAssertions;
using WireMock.Models;
using WireMock.ResponseBuilders;
using WireMock.Settings;
using WireMock.Types;
using WireMock.Util;
using Xunit;
namespace WireMock.Net.Tests.ResponseBuilders
{
public class ResponseWithCallbackTests
{
private readonly WireMockServerSettings _settings = new WireMockServerSettings();
[Fact]
public async Task Response_WithCallback()
{
// Assign
var requestMessage = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1");
var response = Response.Create()
.WithCallback(request => new ResponseMessage
{
BodyData = new BodyData
{
DetectedBodyType = BodyType.String,
BodyAsString = request.Path + "Bar"
},
StatusCode = 302
});
// Act
var responseMessage = await response.ProvideResponseAsync(requestMessage, _settings);
// Assert
responseMessage.BodyData.BodyAsString.Should().Be("/fooBar");
responseMessage.StatusCode.Should().Be(302);
}
[Fact]
public async Task Response_WithCallback_And_UseTransformer_Is_True()
{
// Assign
var requestMessage = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1");
var response = Response.Create()
.WithCallback(request => new ResponseMessage
{
BodyData = new BodyData
{
DetectedBodyType = BodyType.String,
BodyAsString = "{{request.Path}}Bar"
},
StatusCode = 302
})
.WithTransformer();
// Act
var responseMessage = await response.ProvideResponseAsync(requestMessage, _settings);
// Assert
responseMessage.BodyData.BodyAsString.Should().Be("/fooBar");
responseMessage.StatusCode.Should().Be(302);
}
}
using System.Threading.Tasks;
using FluentAssertions;
using WireMock.Models;
using WireMock.ResponseBuilders;
using WireMock.Settings;
using WireMock.Types;
using WireMock.Util;
using Xunit;
namespace WireMock.Net.Tests.ResponseBuilders
{
public class ResponseWithCallbackTests
{
private readonly WireMockServerSettings _settings = new WireMockServerSettings();
[Fact]
public async Task Response_WithCallbackAsync()
{
// Assign
var requestMessage = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1");
var response = Response.Create()
.WithCallback(async request =>
{
await Task.Delay(1);
return new ResponseMessage
{
BodyData = new BodyData
{
DetectedBodyType = BodyType.String,
BodyAsString = request.Path + "Bar"
},
StatusCode = 302
};
});
// Act
var responseMessage = await response.ProvideResponseAsync(requestMessage, _settings);
// Assert
responseMessage.BodyData.BodyAsString.Should().Be("/fooBar");
responseMessage.StatusCode.Should().Be(302);
}
[Fact]
public async Task Response_WithCallback()
{
// Assign
var requestMessage = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1");
var response = Response.Create()
.WithCallback(request => new ResponseMessage
{
BodyData = new BodyData
{
DetectedBodyType = BodyType.String,
BodyAsString = request.Path + "Bar"
},
StatusCode = 302
});
// Act
var responseMessage = await response.ProvideResponseAsync(requestMessage, _settings);
// Assert
responseMessage.BodyData.BodyAsString.Should().Be("/fooBar");
responseMessage.StatusCode.Should().Be(302);
}
[Fact]
public async Task Response_WithCallback_And_UseTransformer_Is_True()
{
// Assign
var requestMessage = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1");
var response = Response.Create()
.WithCallback(request => new ResponseMessage
{
BodyData = new BodyData
{
DetectedBodyType = BodyType.String,
BodyAsString = "{{request.Path}}Bar"
},
StatusCode = 302
})
.WithTransformer();
// Act
var responseMessage = await response.ProvideResponseAsync(requestMessage, _settings);
// Assert
responseMessage.BodyData.BodyAsString.Should().Be("/fooBar");
responseMessage.StatusCode.Should().Be(302);
}
}
}

View File

@@ -1,3 +1,4 @@
using FluentAssertions;
using NFluent;
using WireMock.Util;
using Xunit;
@@ -13,13 +14,14 @@ namespace WireMock.Net.Tests.Util
string url = "test";
// Act
bool result = PortUtils.TryExtract(url, out string proto, out string host, out int port);
bool result = PortUtils.TryExtract(url, out bool isHttps, out string proto, out string host, out int port);
// Assert
Check.That(result).IsFalse();
Check.That(proto).IsNull();
Check.That(host).IsNull();
Check.That(port).IsEqualTo(default(int));
result.Should().BeFalse();
isHttps.Should().BeFalse();
proto.Should().BeNull();
host.Should().BeNull();
port.Should().Be(default(int));
}
[Fact]
@@ -29,39 +31,58 @@ namespace WireMock.Net.Tests.Util
string url = "http://0.0.0.0";
// Act
bool result = PortUtils.TryExtract(url, out string proto, out string host, out int port);
bool result = PortUtils.TryExtract(url, out bool isHttps, out string proto, out string host, out int port);
// Assert
Check.That(result).IsFalse();
Check.That(proto).IsNull();
Check.That(host).IsNull();
Check.That(port).IsEqualTo(default(int));
result.Should().BeFalse();
isHttps.Should().BeFalse();
proto.Should().BeNull();
host.Should().BeNull();
port.Should().Be(default(int));
}
[Fact]
public void PortUtils_TryExtract_ValidUrl1_Returns_True()
public void PortUtils_TryExtract_Http_Returns_True()
{
// Assign
string url = "http://wiremock.net:1234";
// Act
bool result = PortUtils.TryExtract(url, out bool isHttps, out string proto, out string host, out int port);
// Assert
result.Should().BeTrue();
isHttps.Should().BeFalse();
proto.Should().Be("http");
host.Should().Be("wiremock.net");
port.Should().Be(1234);
}
[Fact]
public void PortUtils_TryExtract_Https_Returns_True()
{
// Assign
string url = "https://wiremock.net:5000";
// Act
bool result = PortUtils.TryExtract(url, out string proto, out string host, out int port);
bool result = PortUtils.TryExtract(url, out bool isHttps, out string proto, out string host, out int port);
// Assert
Check.That(result).IsTrue();
Check.That(proto).IsEqualTo("https");
Check.That(host).IsEqualTo("wiremock.net");
Check.That(port).IsEqualTo(5000);
result.Should().BeTrue();
isHttps.Should().BeTrue();
proto.Should().Be("https");
host.Should().Be("wiremock.net");
port.Should().Be(5000);
}
[Fact]
public void PortUtils_TryExtract_ValidUrl2_Returns_True()
public void PortUtils_TryExtract_Https0_0_0_0_Returns_True()
{
// Assign
string url = "https://0.0.0.0:5000";
// Act
bool result = PortUtils.TryExtract(url, out string proto, out string host, out int port);
bool result = PortUtils.TryExtract(url, out bool isHttps, out string proto, out string host, out int port);
// Assert
Check.That(result).IsTrue();

View File

@@ -1,104 +1,104 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Authors>Stef Heyenrath</Authors>
<!--<TargetFrameworks>net452;netcoreapp2.1</TargetFrameworks>-->
<TargetFramework>netcoreapp3.1</TargetFramework>
<DebugType>full</DebugType>
<AssemblyName>WireMock.Net.Tests</AssemblyName>
<PackageId>WireMock.Net.Tests</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<ProjectGuid>{31DC2EF8-C3FE-467D-84BE-FB5D956E612E}</ProjectGuid>
<!-- https://github.com/tonerdo/coverlet/issues/6 -->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<SonarQubeTestProject>True</SonarQubeTestProject>
<SonarQubeExclude>True</SonarQubeExclude>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../../src/WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<!--<DelaySign>true</DelaySign>-->
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<!--https://developercommunity.visualstudio.com/content/problem/26347/unit-tests-fail-with-fileloadexception-newtonsoftj-1.html-->
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net.FluentAssertions\WireMock.Net.FluentAssertions.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net.RestClient\WireMock.Net.RestClient.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Codecov" Version="1.10.0" />
<PackageReference Include="coverlet.msbuild" Version="2.8.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="System.Threading" Version="4.3.0" />
<PackageReference Include="RestEase" Version="1.4.10" />
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.12" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="Moq" Version="4.14.5" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NFluent" Version="2.7.0" />
<PackageReference Include="OpenCover" Version="4.7.922" />
<PackageReference Include="ReportGenerator" Version="4.6.7" />
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.12" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<!--<PackageReference Include="StrongNamer" Version="0.0.8" />-->
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net452'">
<PackageReference Include="Microsoft.Owin.Host.HttpListener" Version="3.1.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="Microsoft.AspNetCore" Version="2.1.4" />
</ItemGroup>
<ItemGroup>
<None Update="responsebody.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\00000002-ee28-4f29-ae63-1ac9b0802d86.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\00000002-ee28-4f29-ae63-1ac9b0802d87.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Authors>Stef Heyenrath</Authors>
<!--<TargetFrameworks>net452;netcoreapp2.1</TargetFrameworks>-->
<TargetFramework>netcoreapp3.1</TargetFramework>
<DebugType>full</DebugType>
<AssemblyName>WireMock.Net.Tests</AssemblyName>
<PackageId>WireMock.Net.Tests</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<ProjectGuid>{31DC2EF8-C3FE-467D-84BE-FB5D956E612E}</ProjectGuid>
<!-- https://github.com/tonerdo/coverlet/issues/6 -->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<SonarQubeTestProject>True</SonarQubeTestProject>
<SonarQubeExclude>True</SonarQubeExclude>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../../src/WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<!--<DelaySign>true</DelaySign>-->
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<!--https://developercommunity.visualstudio.com/content/problem/26347/unit-tests-fail-with-fileloadexception-newtonsoftj-1.html-->
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net.FluentAssertions\WireMock.Net.FluentAssertions.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net.RestClient\WireMock.Net.RestClient.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Codecov" Version="1.10.0" />
<PackageReference Include="coverlet.msbuild" Version="2.8.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="System.Threading" Version="4.3.0" />
<PackageReference Include="RestEase" Version="1.4.10" />
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.12" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="Moq" Version="4.14.5" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NFluent" Version="2.7.0" />
<PackageReference Include="OpenCover" Version="4.7.922" />
<PackageReference Include="ReportGenerator" Version="4.6.7" />
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.12" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<!--<PackageReference Include="StrongNamer" Version="0.0.8" />-->
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net452'">
<PackageReference Include="Microsoft.Owin.Host.HttpListener" Version="3.1.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="Microsoft.AspNetCore" Version="2.1.4" />
</ItemGroup>
<ItemGroup>
<None Update="responsebody.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\00000002-ee28-4f29-ae63-1ac9b0802d86.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\00000002-ee28-4f29-ae63-1ac9b0802d87.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\351f0240-bba0-4bcb-93c6-1feba0fe8799.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\array.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\documentdb_root.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\MyXmlResponse.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\subdirectory\MyXmlResponse.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
</None>
<None Update="__admin\mappings\array.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\documentdb_root.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\MyXmlResponse.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\subdirectory\MyXmlResponse.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,37 @@
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using FluentAssertions;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using Xunit;
namespace WireMock.Net.Tests
{
public partial class WireMockServerTests
{
[Theory]
[InlineData(HttpStatusCode.Conflict)]
[InlineData(409)]
[InlineData("409")]
public async Task WireMockServer_WithCallback_Should_Use_StatusCodeFromResponse(object statusCode)
{
// Arrange
var server = WireMockServer.Start();
server.Given(Request.Create().UsingPost().WithPath("/foo"))
.RespondWith(Response.Create()
.WithCallback(request => new ResponseMessage
{
StatusCode = statusCode
}));
// Act
using var httpClient = new HttpClient();
var response = await httpClient.PostAsync("http://localhost:" + server.Ports[0] + "/foo", new StringContent("dummy"));
// Assert
response.StatusCode.Should().Be(409);
}
}
}

View File

@@ -15,7 +15,7 @@ using Xunit;
namespace WireMock.Net.Tests
{
public class WireMockServerTests
public partial class WireMockServerTests
{
[Fact]
public async Task WireMockServer_Should_reset_requestlogs()