mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-05-11 02:10:23 +02:00
Compare commits
5 Commits
1.5.28
...
stef-Ignor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dabe3a2a10 | ||
|
|
b609191095 | ||
|
|
b1ae9aaf46 | ||
|
|
ad3ef83c5e | ||
|
|
35ffbbc7d9 |
@@ -1,7 +1,3 @@
|
|||||||
# 1.5.28 (11 June 2023)
|
|
||||||
- [#948](https://github.com/WireMock-Net/WireMock.Net/pull/948) - WireMock.Net.Testcontainers [feature] contributed by [StefH](https://github.com/StefH)
|
|
||||||
- [#951](https://github.com/WireMock-Net/WireMock.Net/pull/951) - Allow setting the Content-Length header for a HTTP method HEAD [feature] contributed by [StefH](https://github.com/StefH)
|
|
||||||
|
|
||||||
# 1.5.27 (03 June 2023)
|
# 1.5.27 (03 June 2023)
|
||||||
- [#946](https://github.com/WireMock-Net/WireMock.Net/pull/946) - Add warning logging when sending a request to a Webhook does not return status 200 [feature] contributed by [StefH](https://github.com/StefH)
|
- [#946](https://github.com/WireMock-Net/WireMock.Net/pull/946) - Add warning logging when sending a request to a Webhook does not return status 200 [feature] contributed by [StefH](https://github.com/StefH)
|
||||||
- [#949](https://github.com/WireMock-Net/WireMock.Net/pull/949) - Add ".NET Framework 4.7" to WireMock.Net.FluentAssertions [feature] contributed by [StefH](https://github.com/StefH)
|
- [#949](https://github.com/WireMock-Net/WireMock.Net/pull/949) - Add ".NET Framework 4.7" to WireMock.Net.FluentAssertions [feature] contributed by [StefH](https://github.com/StefH)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<VersionPrefix>1.5.28</VersionPrefix>
|
<VersionPrefix>1.5.27</VersionPrefix>
|
||||||
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
|
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
|
||||||
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>
|
||||||
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
rem https://github.com/StefH/GitHubReleaseNotes
|
rem https://github.com/StefH/GitHubReleaseNotes
|
||||||
|
|
||||||
SET version=1.5.28
|
SET version=1.5.27
|
||||||
|
|
||||||
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc duplicate --version %version% --token %GH_TOKEN%
|
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc duplicate --version %version% --token %GH_TOKEN%
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# 1.5.28 (11 June 2023)
|
# 1.5.27 (03 June 2023)
|
||||||
- #948 WireMock.Net.Testcontainers [feature]
|
- #946 Add warning logging when sending a request to a Webhook does not return status 200 [feature]
|
||||||
- #951 Allow setting the Content-Length header for a HTTP method HEAD [feature]
|
- #949 Add ".NET Framework 4.7" to WireMock.Net.FluentAssertions [feature]
|
||||||
|
- #928 TypeLoadException when using WithHeader method. [bug]
|
||||||
|
- #945 Webhook logging [feature]
|
||||||
|
|
||||||
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md
|
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md
|
||||||
@@ -42,7 +42,6 @@ For more info, see also this WIKI page: [What is WireMock.Net](https://github.co
|
|||||||
| **WireMock.Net.OpenApiParser** | [](https://www.nuget.org/packages/WireMock.Net.OpenApiParser) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.OpenApiParser)
|
| **WireMock.Net.OpenApiParser** | [](https://www.nuget.org/packages/WireMock.Net.OpenApiParser) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.OpenApiParser)
|
||||||
| **WireMock.Net.RestClient** | [](https://www.nuget.org/packages/WireMock.Net.RestClient) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.RestClient)
|
| **WireMock.Net.RestClient** | [](https://www.nuget.org/packages/WireMock.Net.RestClient) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.RestClient)
|
||||||
| **WireMock.Net.xUnit** | [](https://www.nuget.org/packages/WireMock.Net.xUnit) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.xUnit)
|
| **WireMock.Net.xUnit** | [](https://www.nuget.org/packages/WireMock.Net.xUnit) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.xUnit)
|
||||||
| **WireMock.Net.Testcontainers** | [](https://www.nuget.org/packages/WireMock.Net.Testcontainers) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Testcontainers)
|
|
||||||
| **WireMock.Org.RestClient** | [](https://www.nuget.org/packages/WireMock.Org.RestClient) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Org.RestClient)
|
| **WireMock.Org.RestClient** | [](https://www.nuget.org/packages/WireMock.Org.RestClient) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Org.RestClient)
|
||||||
|
|
||||||
|
|
||||||
@@ -69,15 +68,13 @@ WireMock.Net can be used in several ways:
|
|||||||
You can use your favorite test framework and use WireMock within your tests, see
|
You can use your favorite test framework and use WireMock within your tests, see
|
||||||
[Wiki : UnitTesting](https://github.com/StefH/WireMock.Net/wiki/Using-WireMock-in-UnitTests).
|
[Wiki : UnitTesting](https://github.com/StefH/WireMock.Net/wiki/Using-WireMock-in-UnitTests).
|
||||||
|
|
||||||
### Unit/Integration Testing using Testcontainers.DotNet
|
|
||||||
You can use [Wiki : WireMock.Net.Testcontainers](https://github.com/WireMock-Net/WireMock.Net/wiki/Using-WireMock.Net.Testcontainers) to build a WireMock.Net Docker container which can be used in Unit/Integration testing.
|
|
||||||
|
|
||||||
### As a dotnet tool
|
### As a dotnet tool
|
||||||
It's simple to install WireMock.Net as (global) dotnet tool, see [Wiki : dotnet tool](https://github.com/StefH/WireMock.Net/wiki/WireMock-as-dotnet-tool).
|
It's simple to install WireMock.Net as (global) dotnet tool, see [Wiki : dotnet tool](https://github.com/StefH/WireMock.Net/wiki/WireMock-as-dotnet-tool).
|
||||||
|
|
||||||
### As standalone process / console application
|
### As standalone process / console application
|
||||||
This is quite straight forward to launch a mock server within a console application, see [Wiki : Standalone Process](https://github.com/StefH/WireMock.Net/wiki/WireMock-as-a-standalone-process).
|
This is quite straight forward to launch a mock server within a console application, see [Wiki : Standalone Process](https://github.com/StefH/WireMock.Net/wiki/WireMock-as-a-standalone-process).
|
||||||
|
|
||||||
|
|
||||||
### As a Windows Service
|
### As a Windows Service
|
||||||
You can also run WireMock.Net as a Windows Service, follow this [WireMock-as-a-Windows-Service](https://github.com/WireMock-Net/WireMock.Net/wiki/WireMock-as-a-Windows-Service).
|
You can also run WireMock.Net as a Windows Service, follow this [WireMock-as-a-Windows-Service](https://github.com/WireMock-Net/WireMock.Net/wiki/WireMock-as-a-Windows-Service).
|
||||||
|
|
||||||
|
|||||||
@@ -111,10 +111,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMockAzureQueueExample",
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMockAzureQueueProxy", "examples\WireMockAzureQueueProxy\WireMockAzureQueueProxy.csproj", "{ADB557D8-D66B-4387-912B-3F73E290B478}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMockAzureQueueProxy", "examples\WireMockAzureQueueProxy\WireMockAzureQueueProxy.csproj", "{ADB557D8-D66B-4387-912B-3F73E290B478}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Testcontainers", "src\WireMock.Net.Testcontainers\WireMock.Net.Testcontainers.csproj", "{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.TestcontainersExample", "examples\WireMock.Net.TestcontainersExample\WireMock.Net.TestcontainersExample.csproj", "{56A38798-C48B-4A4A-B805-071E05C02CE1}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -269,14 +265,6 @@ Global
|
|||||||
{ADB557D8-D66B-4387-912B-3F73E290B478}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{ADB557D8-D66B-4387-912B-3F73E290B478}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{ADB557D8-D66B-4387-912B-3F73E290B478}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{ADB557D8-D66B-4387-912B-3F73E290B478}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{ADB557D8-D66B-4387-912B-3F73E290B478}.Release|Any CPU.Build.0 = Release|Any CPU
|
{ADB557D8-D66B-4387-912B-3F73E290B478}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -321,8 +309,6 @@ Global
|
|||||||
{7C2A9DE8-C89F-4841-9058-6B9BF81E5E34} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{7C2A9DE8-C89F-4841-9058-6B9BF81E5E34} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
{BAA9EC2A-874B-45CE-8E51-A73622DC7F3D} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{BAA9EC2A-874B-45CE-8E51-A73622DC7F3D} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
{ADB557D8-D66B-4387-912B-3F73E290B478} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{ADB557D8-D66B-4387-912B-3F73E290B478} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
|
||||||
{56A38798-C48B-4A4A-B805-071E05C02CE1} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}
|
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MD/@EntryIndexedValue">MD5</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MD/@EntryIndexedValue">MD5</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OPTIONS/@EntryIndexedValue">OPTIONS</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OPTIONS/@EntryIndexedValue">OPTIONS</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OS/@EntryIndexedValue">OS</s:String>
|
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PATCH/@EntryIndexedValue">PATCH</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PATCH/@EntryIndexedValue">PATCH</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=POST/@EntryIndexedValue">POST</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=POST/@EntryIndexedValue">POST</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PUT/@EntryIndexedValue">PUT</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PUT/@EntryIndexedValue">PUT</s:String>
|
||||||
@@ -33,7 +32,6 @@
|
|||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Raml/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Raml/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=randomizer/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=randomizer/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Scriban/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Scriban/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=sheyenrath/@EntryIndexedValue">True</s:Boolean>
|
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sigil/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sigil/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Stef/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Stef/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=templated/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=templated/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using WireMock.Net.OpenApiParser.Types;
|
||||||
using WireMock.RequestBuilders;
|
using WireMock.RequestBuilders;
|
||||||
using WireMock.ResponseBuilders;
|
using WireMock.ResponseBuilders;
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ class Program
|
|||||||
private static void RunMockServerWithDynamicExampleGeneration()
|
private static void RunMockServerWithDynamicExampleGeneration()
|
||||||
{
|
{
|
||||||
// Run your mocking framework specifying your Example Values generator class.
|
// Run your mocking framework specifying your Example Values generator class.
|
||||||
var serverCustomer_V2_json = Run.RunServer(Path.Combine(Folder, "Swagger_Customer_V2.0.json"), "http://localhost:8090/", true, new DynamicDataGeneration(), Types.ExampleValueType.Value, Types.ExampleValueType.Value);
|
var serverCustomer_V2_json = Run.RunServer(Path.Combine(Folder, "Swagger_Customer_V2.0.json"), "http://localhost:8090/", true, new DynamicDataGeneration(), ExampleValueType.Value, ExampleValueType.Value);
|
||||||
Console.WriteLine("Press any key to stop the servers");
|
Console.WriteLine("Press any key to stop the servers");
|
||||||
|
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using Testcontainers.MsSql;
|
|
||||||
using WireMock.Net.Testcontainers;
|
|
||||||
|
|
||||||
namespace WireMock.Net.TestcontainersExample;
|
|
||||||
|
|
||||||
internal class Program
|
|
||||||
{
|
|
||||||
private static async Task Main(string[] args)
|
|
||||||
{
|
|
||||||
var container = new WireMockContainerBuilder()
|
|
||||||
.WithAdminUserNameAndPassword("x", "y")
|
|
||||||
.WithMappings(@"C:\Dev\GitHub\WireMock.Net\examples\WireMock.Net.Console.NET6\__admin\mappings")
|
|
||||||
.WithWatchStaticMappings(true)
|
|
||||||
.WithAutoRemove(true)
|
|
||||||
.WithCleanUp(true)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
await container.StartAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var logs = await container.GetLogsAsync(DateTime.Now.AddDays(-1)).ConfigureAwait(false);
|
|
||||||
Console.WriteLine("logs = " + logs.Stdout);
|
|
||||||
|
|
||||||
var restEaseApiClient = container.CreateWireMockAdminClient();
|
|
||||||
|
|
||||||
var settings = await restEaseApiClient.GetSettingsAsync();
|
|
||||||
Console.WriteLine("settings = " + JsonConvert.SerializeObject(settings, Formatting.Indented));
|
|
||||||
|
|
||||||
var mappings = await restEaseApiClient.GetMappingsAsync();
|
|
||||||
Console.WriteLine("mappings = " + JsonConvert.SerializeObject(mappings, Formatting.Indented));
|
|
||||||
|
|
||||||
var client = container.CreateClient();
|
|
||||||
var result = await client.GetStringAsync("/static/mapping");
|
|
||||||
Console.WriteLine("result = " + result);
|
|
||||||
|
|
||||||
await container.StopAsync();
|
|
||||||
|
|
||||||
var sql = new MsSqlBuilder()
|
|
||||||
.WithAutoRemove(true)
|
|
||||||
.WithCleanUp(true)
|
|
||||||
.Build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Testcontainers.MsSql" Version="3.2.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\src\WireMock.Net.Testcontainers\WireMock.Net.Testcontainers.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Update="873d495f-940e-4b86-a1f4-4f0fc7be8b8b.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -23,12 +23,14 @@ internal class OpenApiPathsMapper
|
|||||||
private const string HeaderContentType = "Content-Type";
|
private const string HeaderContentType = "Content-Type";
|
||||||
|
|
||||||
private readonly WireMockOpenApiParserSettings _settings;
|
private readonly WireMockOpenApiParserSettings _settings;
|
||||||
private readonly ExampleValueGenerator _exampleValueGenerator;
|
private readonly IExampleValueGenerator _exampleValueGenerator;
|
||||||
|
private readonly IExampleValueGenerator _regexExampleValueGenerator;
|
||||||
|
|
||||||
public OpenApiPathsMapper(WireMockOpenApiParserSettings settings)
|
public OpenApiPathsMapper(WireMockOpenApiParserSettings settings)
|
||||||
{
|
{
|
||||||
_settings = Guard.NotNull(settings);
|
_settings = Guard.NotNull(settings);
|
||||||
_exampleValueGenerator = new ExampleValueGenerator(settings);
|
_exampleValueGenerator = new ExampleValueGenerator(settings);
|
||||||
|
_regexExampleValueGenerator = new RegexExampleValueGenerator(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<MappingModel> ToMappingModels(OpenApiPaths? paths, IList<OpenApiServer> servers)
|
public IReadOnlyList<MappingModel> ToMappingModels(OpenApiPaths? paths, IList<OpenApiServer> servers)
|
||||||
@@ -37,18 +39,7 @@ internal class OpenApiPathsMapper
|
|||||||
.OrderBy(p => p.Key)
|
.OrderBy(p => p.Key)
|
||||||
.Select(p => MapPath(p.Key, p.Value, servers))
|
.Select(p => MapPath(p.Key, p.Value, servers))
|
||||||
.SelectMany(x => x)
|
.SelectMany(x => x)
|
||||||
.ToArray() ??
|
.ToArray() ?? Array.Empty<MappingModel>();
|
||||||
Array.Empty<MappingModel>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IReadOnlyList<MappingModel> MapPaths(OpenApiPaths? paths, IList<OpenApiServer> servers)
|
|
||||||
{
|
|
||||||
return paths?
|
|
||||||
.OrderBy(p => p.Key)
|
|
||||||
.Select(p => MapPath(p.Key, p.Value, servers))
|
|
||||||
.SelectMany(x => x)
|
|
||||||
.ToArray() ??
|
|
||||||
Array.Empty<MappingModel>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IReadOnlyList<MappingModel> MapPath(string path, OpenApiPathItem pathItem, IList<OpenApiServer> servers)
|
private IReadOnlyList<MappingModel> MapPath(string path, OpenApiPathItem pathItem, IList<OpenApiServer> servers)
|
||||||
@@ -280,41 +271,6 @@ internal class OpenApiPathsMapper
|
|||||||
return newPath;
|
return newPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string MapBasePath(IList<OpenApiServer>? servers)
|
|
||||||
{
|
|
||||||
if (servers == null || servers.Count == 0)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenApiServer server = servers.First();
|
|
||||||
if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out Uri uriResult))
|
|
||||||
{
|
|
||||||
return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JToken? MapOpenApiAnyToJToken(IOpenApiAny? any)
|
|
||||||
{
|
|
||||||
if (any == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var outputString = new StringWriter();
|
|
||||||
var writer = new OpenApiJsonWriter(outputString);
|
|
||||||
any.Write(writer, OpenApiSpecVersion.OpenApi3_0);
|
|
||||||
|
|
||||||
if (any.AnyType == AnyType.Array)
|
|
||||||
{
|
|
||||||
return JArray.Parse(outputString.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return JObject.Parse(outputString.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private IDictionary<string, object>? MapHeaders(string? responseContentType, IDictionary<string, OpenApiHeader>? headers)
|
private IDictionary<string, object>? MapHeaders(string? responseContentType, IDictionary<string, OpenApiHeader>? headers)
|
||||||
{
|
{
|
||||||
var mappedHeaders = headers?.ToDictionary(
|
var mappedHeaders = headers?.ToDictionary(
|
||||||
@@ -366,28 +322,38 @@ internal class OpenApiPathsMapper
|
|||||||
return list.Any() ? list : null;
|
return list.Any() ? list : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatcherModel GetExampleMatcherModel(OpenApiSchema? schema, ExampleValueType type)
|
private MatcherModel GetExampleMatcherModel(OpenApiSchema? schema, ExampleValueType exampleValueType)
|
||||||
{
|
{
|
||||||
return type switch
|
return exampleValueType switch
|
||||||
{
|
{
|
||||||
ExampleValueType.Value => new MatcherModel
|
ExampleValueType.Value => new MatcherModel
|
||||||
{
|
{
|
||||||
Name = "ExactMatcher",
|
Name = "ExactMatcher",
|
||||||
Pattern = GetExampleValueAsStringForSchemaType(schema),
|
Pattern = GetExampleValueAsStringForSchemaType(schema, exampleValueType),
|
||||||
|
IgnoreCase = _settings.IgnoreCaseExampleValues
|
||||||
|
},
|
||||||
|
|
||||||
|
ExampleValueType.Regex => new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "RegexMatcher",
|
||||||
|
Pattern = GetExampleValueAsStringForSchemaType(schema, exampleValueType),
|
||||||
IgnoreCase = _settings.IgnoreCaseExampleValues
|
IgnoreCase = _settings.IgnoreCaseExampleValues
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => new MatcherModel
|
_ => new MatcherModel
|
||||||
{
|
{
|
||||||
Name = "WildcardMatcher",
|
Name = "WildcardMatcher",
|
||||||
Pattern = "*"
|
Pattern = "*",
|
||||||
|
IgnoreCase = _settings.IgnoreCaseExampleValues
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetExampleValueAsStringForSchemaType(OpenApiSchema? schema)
|
private string GetExampleValueAsStringForSchemaType(OpenApiSchema? schema, ExampleValueType exampleValueType)
|
||||||
{
|
{
|
||||||
var value = _exampleValueGenerator.GetExampleValue(schema);
|
var value = exampleValueType == ExampleValueType.Regex ?
|
||||||
|
_regexExampleValueGenerator.GetExampleValue(schema) :
|
||||||
|
_exampleValueGenerator.GetExampleValue(schema);
|
||||||
|
|
||||||
return value switch
|
return value switch
|
||||||
{
|
{
|
||||||
@@ -396,4 +362,39 @@ internal class OpenApiPathsMapper
|
|||||||
_ => value.ToString(),
|
_ => value.ToString(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string MapBasePath(IList<OpenApiServer>? servers)
|
||||||
|
{
|
||||||
|
if (servers == null || servers.Count == 0)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var server = servers.First();
|
||||||
|
if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out Uri uriResult))
|
||||||
|
{
|
||||||
|
return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JToken? MapOpenApiAnyToJToken(IOpenApiAny? any)
|
||||||
|
{
|
||||||
|
if (any == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var outputString = new StringWriter();
|
||||||
|
var writer = new OpenApiJsonWriter(outputString);
|
||||||
|
any.Write(writer, OpenApiSpecVersion.OpenApi3_0);
|
||||||
|
|
||||||
|
if (any.AnyType == AnyType.Array)
|
||||||
|
{
|
||||||
|
return JArray.Parse(outputString.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return JObject.Parse(outputString.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace WireMock.Net.OpenApiParser.Types;
|
namespace WireMock.Net.OpenApiParser.Types;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The example value to use
|
/// The (example) value pattern to use.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum ExampleValueType
|
public enum ExampleValueType
|
||||||
{
|
{
|
||||||
@@ -12,6 +12,11 @@ public enum ExampleValueType
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Value,
|
Value,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build a Regex based on the SchemaType.
|
||||||
|
/// </summary>
|
||||||
|
Regex,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Just use a Wildcard (*) character.
|
/// Just use a Wildcard (*) character.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using WireMock.Net.OpenApiParser.Types;
|
|||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Utils;
|
namespace WireMock.Net.OpenApiParser.Utils;
|
||||||
|
|
||||||
internal class ExampleValueGenerator
|
internal class ExampleValueGenerator : IExampleValueGenerator
|
||||||
{
|
{
|
||||||
private readonly IWireMockOpenApiParserExampleValues _exampleValues;
|
private readonly IWireMockOpenApiParserExampleValues _exampleValues;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
|
||||||
|
namespace WireMock.Net.OpenApiParser.Utils;
|
||||||
|
|
||||||
|
internal interface IExampleValueGenerator
|
||||||
|
{
|
||||||
|
object GetExampleValue(OpenApiSchema? schema);
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Stef.Validation;
|
||||||
|
using WireMock.Net.OpenApiParser.Extensions;
|
||||||
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
|
using WireMock.Net.OpenApiParser.Types;
|
||||||
|
|
||||||
|
namespace WireMock.Net.OpenApiParser.Utils;
|
||||||
|
|
||||||
|
internal class RegexExampleValueGenerator : IExampleValueGenerator
|
||||||
|
{
|
||||||
|
public RegexExampleValueGenerator(WireMockOpenApiParserSettings settings)
|
||||||
|
{
|
||||||
|
Guard.NotNull(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetExampleValue(OpenApiSchema? schema)
|
||||||
|
{
|
||||||
|
switch (schema?.GetSchemaType())
|
||||||
|
{
|
||||||
|
case SchemaType.Boolean:
|
||||||
|
return @"(true|false)";
|
||||||
|
|
||||||
|
case SchemaType.Integer:
|
||||||
|
return @"-?\d+";
|
||||||
|
|
||||||
|
case SchemaType.Number:
|
||||||
|
return @"[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return schema?.GetSchemaFormat() switch
|
||||||
|
{
|
||||||
|
SchemaFormat.Date => @"(\d{4})-([01]\d)-([0-3]\d)",
|
||||||
|
SchemaFormat.DateTime => @"(\d{4})-([01]\d)-([0-3]\d)T([0-2]\d):([0-5]\d):([0-5]\d)(\.\d+)?(Z|[+-][0-2]\d:[0-5]\d)",
|
||||||
|
SchemaFormat.Byte => @"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)",
|
||||||
|
SchemaFormat.Binary => @"[a-zA-Z0-9\+/]*={0,3}",
|
||||||
|
_ => ".*"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ using RamlToOpenApiConverter;
|
|||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
using WireMock.Net.OpenApiParser.Mappers;
|
using WireMock.Net.OpenApiParser.Mappers;
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
|
using WireMock.Net.OpenApiParser.Types;
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser;
|
namespace WireMock.Net.OpenApiParser;
|
||||||
|
|
||||||
@@ -17,13 +18,20 @@ namespace WireMock.Net.OpenApiParser;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class WireMockOpenApiParser : IWireMockOpenApiParser
|
public class WireMockOpenApiParser : IWireMockOpenApiParser
|
||||||
{
|
{
|
||||||
|
private readonly WireMockOpenApiParserSettings _wireMockOpenApiParserSettings = new WireMockOpenApiParserSettings
|
||||||
|
{
|
||||||
|
HeaderPatternToUse = ExampleValueType.Regex,
|
||||||
|
QueryParameterPatternToUse = ExampleValueType.Regex,
|
||||||
|
PathPatternToUse = ExampleValueType.Regex
|
||||||
|
};
|
||||||
|
|
||||||
private readonly OpenApiStreamReader _reader = new();
|
private readonly OpenApiStreamReader _reader = new();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public IReadOnlyList<MappingModel> FromFile(string path, out OpenApiDiagnostic diagnostic)
|
public IReadOnlyList<MappingModel> FromFile(string path, out OpenApiDiagnostic diagnostic)
|
||||||
{
|
{
|
||||||
return FromFile(path, new WireMockOpenApiParserSettings(), out diagnostic);
|
return FromFile(path, _wireMockOpenApiParserSettings, out diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -49,7 +57,7 @@ public class WireMockOpenApiParser : IWireMockOpenApiParser
|
|||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public IReadOnlyList<MappingModel> FromDocument(OpenApiDocument openApiDocument, WireMockOpenApiParserSettings? settings = null)
|
public IReadOnlyList<MappingModel> FromDocument(OpenApiDocument openApiDocument, WireMockOpenApiParserSettings? settings = null)
|
||||||
{
|
{
|
||||||
return new OpenApiPathsMapper(settings ?? new WireMockOpenApiParserSettings()).ToMappingModels(openApiDocument.Paths, openApiDocument.Servers);
|
return new OpenApiPathsMapper(settings ?? _wireMockOpenApiParserSettings).ToMappingModels(openApiDocument.Paths, openApiDocument.Servers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace WireMock.Net.Testcontainers.Models;
|
|
||||||
|
|
||||||
internal record ContainerInfo
|
|
||||||
(
|
|
||||||
string Image,
|
|
||||||
string MappingsPath
|
|
||||||
);
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<Description>A fluent testcontainer builder for the Docker version of WireMock.Net</Description>
|
|
||||||
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
|
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
|
||||||
<PackageTags>wiremock;docker;testcontainer;testcontainers</PackageTags>
|
|
||||||
<ProjectGuid>{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}</ProjectGuid>
|
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
|
||||||
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
|
||||||
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
|
||||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
|
||||||
<LangVersion>10</LangVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="IsExternalInit" Version="1.0.3">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.9" />
|
|
||||||
<PackageReference Include="Stef.Validation" Version="0.1.1" />
|
|
||||||
<PackageReference Include="Testcontainers" Version="3.2.0" />
|
|
||||||
<PackageReference Include="JetBrains.Annotations" VersionOverride="2022.3.1" PrivateAssets="All" Version="2022.3.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\WireMock.Net.RestClient\WireMock.Net.RestClient.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
using Docker.DotNet.Models;
|
|
||||||
using DotNet.Testcontainers.Builders;
|
|
||||||
using DotNet.Testcontainers.Configurations;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
|
|
||||||
namespace WireMock.Net.Testcontainers;
|
|
||||||
|
|
||||||
/// <inheritdoc cref="ContainerConfiguration" />
|
|
||||||
[PublicAPI]
|
|
||||||
public sealed class WireMockConfiguration : ContainerConfiguration
|
|
||||||
{
|
|
||||||
#pragma warning disable CS1591
|
|
||||||
public string? Username { get; }
|
|
||||||
|
|
||||||
public string? Password { get; }
|
|
||||||
|
|
||||||
public bool HasBasicAuthentication => !string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password);
|
|
||||||
|
|
||||||
public WireMockConfiguration(
|
|
||||||
string? username = null,
|
|
||||||
string? password = null
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Username = username;
|
|
||||||
Password = password;
|
|
||||||
}
|
|
||||||
#pragma warning restore CS1591
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="WireMockConfiguration" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
|
|
||||||
public WireMockConfiguration(IResourceConfiguration<CreateContainerParameters> resourceConfiguration) : base(resourceConfiguration)
|
|
||||||
{
|
|
||||||
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="WireMockConfiguration" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
|
|
||||||
public WireMockConfiguration(IContainerConfiguration resourceConfiguration) : base(resourceConfiguration)
|
|
||||||
{
|
|
||||||
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="WireMockConfiguration" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
|
|
||||||
public WireMockConfiguration(WireMockConfiguration resourceConfiguration) : this(new WireMockConfiguration(), resourceConfiguration)
|
|
||||||
{
|
|
||||||
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="WireMockConfiguration" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="oldValue">The old Docker resource configuration.</param>
|
|
||||||
/// <param name="newValue">The new Docker resource configuration.</param>
|
|
||||||
public WireMockConfiguration(WireMockConfiguration oldValue, WireMockConfiguration newValue) : base(oldValue, newValue)
|
|
||||||
{
|
|
||||||
Username = BuildConfiguration.Combine(oldValue.Username, newValue.Username);
|
|
||||||
Password = BuildConfiguration.Combine(oldValue.Password, newValue.Password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Text;
|
|
||||||
using DotNet.Testcontainers.Containers;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using RestEase;
|
|
||||||
using Stef.Validation;
|
|
||||||
using WireMock.Client;
|
|
||||||
|
|
||||||
namespace WireMock.Net.Testcontainers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A container for running WireMock in a docker environment.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class WireMockContainer : DockerContainer
|
|
||||||
{
|
|
||||||
internal const int ContainerPort = 80;
|
|
||||||
|
|
||||||
private readonly WireMockConfiguration _configuration;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="WireMockContainer" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="configuration">The container configuration.</param>
|
|
||||||
/// <param name="logger">The logger.</param>
|
|
||||||
public WireMockContainer(WireMockConfiguration configuration, ILogger logger) : base(configuration, logger)
|
|
||||||
{
|
|
||||||
_configuration = Guard.NotNull(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the public Url.
|
|
||||||
/// </summary>
|
|
||||||
[PublicAPI]
|
|
||||||
public string GetPublicUrl() => GetPublicUri().ToString();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a RestEase Admin client which can be used to call the admin REST endpoint.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A <see cref="IWireMockAdminApi"/></returns>
|
|
||||||
[PublicAPI]
|
|
||||||
public IWireMockAdminApi CreateWireMockAdminClient()
|
|
||||||
{
|
|
||||||
ValidateIfRunning();
|
|
||||||
|
|
||||||
var api = RestClient.For<IWireMockAdminApi>(GetPublicUri());
|
|
||||||
|
|
||||||
if (_configuration.HasBasicAuthentication)
|
|
||||||
{
|
|
||||||
api.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{_configuration.Username}:{_configuration.Password}")));
|
|
||||||
}
|
|
||||||
|
|
||||||
return api;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a <see cref="HttpClient"/> which can be used to call this instance.
|
|
||||||
/// <param name="handlers">
|
|
||||||
/// An ordered list of System.Net.Http.DelegatingHandler instances to be invoked
|
|
||||||
/// as an System.Net.Http.HttpRequestMessage travels from the System.Net.Http.HttpClient
|
|
||||||
/// to the network and an System.Net.Http.HttpResponseMessage travels from the network
|
|
||||||
/// back to System.Net.Http.HttpClient. The handlers are invoked in a top-down fashion.
|
|
||||||
/// That is, the first entry is invoked first for an outbound request message but
|
|
||||||
/// last for an inbound response message.
|
|
||||||
/// </param>
|
|
||||||
/// </summary>
|
|
||||||
[PublicAPI]
|
|
||||||
public HttpClient CreateClient(params DelegatingHandler[] handlers)
|
|
||||||
{
|
|
||||||
ValidateIfRunning();
|
|
||||||
|
|
||||||
var client = HttpClientFactory.Create(handlers);
|
|
||||||
client.BaseAddress = GetPublicUri();
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a <see cref="HttpClient"/> (one for each URL) which can be used to call this instance.
|
|
||||||
/// <param name="innerHandler">The inner handler represents the destination of the HTTP message channel.</param>
|
|
||||||
/// <param name="handlers">
|
|
||||||
/// An ordered list of System.Net.Http.DelegatingHandler instances to be invoked
|
|
||||||
/// as an System.Net.Http.HttpRequestMessage travels from the System.Net.Http.HttpClient
|
|
||||||
/// to the network and an System.Net.Http.HttpResponseMessage travels from the network
|
|
||||||
/// back to System.Net.Http.HttpClient. The handlers are invoked in a top-down fashion.
|
|
||||||
/// That is, the first entry is invoked first for an outbound request message but
|
|
||||||
/// last for an inbound response message.
|
|
||||||
/// </param>
|
|
||||||
/// </summary>
|
|
||||||
[PublicAPI]
|
|
||||||
public HttpClient CreateClient(HttpMessageHandler innerHandler, params DelegatingHandler[] handlers)
|
|
||||||
{
|
|
||||||
ValidateIfRunning();
|
|
||||||
|
|
||||||
var client = HttpClientFactory.Create(innerHandler, handlers);
|
|
||||||
client.BaseAddress = GetPublicUri();
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ValidateIfRunning()
|
|
||||||
{
|
|
||||||
if (State != TestcontainersStates.Running)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Unable to create HttpClient because the WireMock.Net is not yet running.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Uri GetPublicUri() => new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(ContainerPort)).Uri;
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Docker.DotNet.Models;
|
|
||||||
using DotNet.Testcontainers.Builders;
|
|
||||||
using DotNet.Testcontainers.Configurations;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Stef.Validation;
|
|
||||||
using WireMock.Net.Testcontainers.Models;
|
|
||||||
|
|
||||||
namespace WireMock.Net.Testcontainers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An specific fluent Docker container builder for WireMock.Net
|
|
||||||
/// </summary>
|
|
||||||
public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContainerBuilder, WireMockContainer, WireMockConfiguration>
|
|
||||||
{
|
|
||||||
private readonly Dictionary<bool, ContainerInfo> _info = new()
|
|
||||||
{
|
|
||||||
{ false, new ContainerInfo("sheyenrath/wiremock.net:latest", "/app/__admin/mappings") },
|
|
||||||
{ true, new ContainerInfo("sheyenrath/wiremock.net-windows:latest", @"c:\app\__admin\mappings") }
|
|
||||||
};
|
|
||||||
|
|
||||||
private const string DefaultLogger = "WireMockConsoleLogger";
|
|
||||||
|
|
||||||
private readonly Lazy<Task<bool>> _isWindowsAsLazy = new(async () =>
|
|
||||||
{
|
|
||||||
using var dockerClientConfig = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientConfiguration();
|
|
||||||
using var dockerClient = dockerClientConfig.CreateClient();
|
|
||||||
|
|
||||||
var version = await dockerClient.System.GetVersionAsync();
|
|
||||||
return version.Os.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) > -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
|
|
||||||
/// </summary>
|
|
||||||
public WireMockContainerBuilder() : this(new WireMockConfiguration())
|
|
||||||
{
|
|
||||||
DockerResourceConfiguration = Init().DockerResourceConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Automatically set the correct image (Linux or Windows) for WireMock which to create the container.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
|
|
||||||
[PublicAPI]
|
|
||||||
public WireMockContainerBuilder WithImage()
|
|
||||||
{
|
|
||||||
var isWindows = _isWindowsAsLazy.Value.GetAwaiter().GetResult();
|
|
||||||
return WithImage(_info[isWindows].Image);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set the admin username and password for the container (basic authentication).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="username">The admin username.</param>
|
|
||||||
/// <param name="password">The admin password.</param>
|
|
||||||
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
|
|
||||||
public WireMockContainerBuilder WithAdminUserNameAndPassword(string username, string password)
|
|
||||||
{
|
|
||||||
Guard.NotNull(username);
|
|
||||||
Guard.NotNull(password);
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(username) && string.IsNullOrEmpty(password))
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Merge(DockerResourceConfiguration, new WireMockConfiguration(username, password))
|
|
||||||
.WithCommand($"--AdminUserName {username}", $"--AdminPassword {password}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Use the WireMockNullLogger.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
|
|
||||||
[PublicAPI]
|
|
||||||
public WireMockContainerBuilder WithNullLogger()
|
|
||||||
{
|
|
||||||
return WithCommand("--WireMockLogger WireMockNullLogger");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines if the static mappings should be read at startup (default set to false).
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
|
|
||||||
[PublicAPI]
|
|
||||||
public WireMockContainerBuilder WithReadStaticMappings()
|
|
||||||
{
|
|
||||||
return WithCommand("--ReadStaticMappings true");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Watch the static mapping files + folder for changes when running.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
|
|
||||||
[PublicAPI]
|
|
||||||
public WireMockContainerBuilder WithWatchStaticMappings(bool includeSubDirectories)
|
|
||||||
{
|
|
||||||
return WithCommand("--WatchStaticMappings true").WithCommand($"--WatchStaticMappingsInSubdirectories {includeSubDirectories}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies the path for the (static) mapping json files.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[PublicAPI]
|
|
||||||
public WireMockContainerBuilder WithMappings(string path)
|
|
||||||
{
|
|
||||||
Guard.NotNullOrEmpty(path);
|
|
||||||
|
|
||||||
var isWindows = _isWindowsAsLazy.Value.GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
return WithReadStaticMappings().WithBindMount(path, _info[isWindows].MappingsPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="WireMockContainerBuilder" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dockerResourceConfiguration">The Docker resource configuration.</param>
|
|
||||||
private WireMockContainerBuilder(WireMockConfiguration dockerResourceConfiguration) : base(dockerResourceConfiguration)
|
|
||||||
{
|
|
||||||
DockerResourceConfiguration = dockerResourceConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override WireMockConfiguration DockerResourceConfiguration { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override WireMockContainer Build()
|
|
||||||
{
|
|
||||||
Validate();
|
|
||||||
|
|
||||||
return new WireMockContainer(DockerResourceConfiguration, TestcontainersSettings.Logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override WireMockContainerBuilder Init()
|
|
||||||
{
|
|
||||||
var builder = base.Init();
|
|
||||||
|
|
||||||
// In case no image has been set, set the image using internal logic.
|
|
||||||
if (builder.DockerResourceConfiguration.Image == null)
|
|
||||||
{
|
|
||||||
builder = builder.WithImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
var isWindows = _isWindowsAsLazy.Value.GetAwaiter().GetResult();
|
|
||||||
var waitForContainerOS = isWindows ? Wait.ForWindowsContainer() : Wait.ForUnixContainer();
|
|
||||||
return builder
|
|
||||||
.WithPortBinding(WireMockContainer.ContainerPort, true)
|
|
||||||
.WithCommand($"--WireMockLogger {DefaultLogger}")
|
|
||||||
.WithWaitStrategy(waitForContainerOS.UntilMessageIsLogged("By Stef Heyenrath"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override WireMockContainerBuilder Clone(IContainerConfiguration resourceConfiguration)
|
|
||||||
{
|
|
||||||
return Merge(DockerResourceConfiguration, new WireMockConfiguration(resourceConfiguration));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override WireMockContainerBuilder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
|
|
||||||
{
|
|
||||||
return Merge(DockerResourceConfiguration, new WireMockConfiguration(resourceConfiguration));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override WireMockContainerBuilder Merge(WireMockConfiguration oldValue, WireMockConfiguration newValue)
|
|
||||||
{
|
|
||||||
return new WireMockContainerBuilder(new WireMockConfiguration(oldValue, newValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,18 +5,12 @@ using System.Net.Http;
|
|||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Constants;
|
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
|
|
||||||
namespace WireMock.Http;
|
namespace WireMock.Http;
|
||||||
|
|
||||||
internal static class HttpRequestMessageHelper
|
internal static class HttpRequestMessageHelper
|
||||||
{
|
{
|
||||||
private static readonly IDictionary<string, bool> ContentLengthHeaderAllowed = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase)
|
|
||||||
{
|
|
||||||
{ HttpRequestMethod.HEAD, true }
|
|
||||||
};
|
|
||||||
|
|
||||||
internal static HttpRequestMessage Create(IRequestMessage requestMessage, string url)
|
internal static HttpRequestMessage Create(IRequestMessage requestMessage, string url)
|
||||||
{
|
{
|
||||||
Guard.NotNull(requestMessage);
|
Guard.NotNull(requestMessage);
|
||||||
@@ -56,19 +50,7 @@ internal static class HttpRequestMessageHelper
|
|||||||
return httpRequestMessage;
|
return httpRequestMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
var excludeHeaders = new List<string> { HttpKnownHeaderNames.Host };
|
var excludeHeaders = new List<string> { HttpKnownHeaderNames.Host, HttpKnownHeaderNames.ContentLength };
|
||||||
|
|
||||||
var contentLengthHeaderAllowed = ContentLengthHeaderAllowed.TryGetValue(requestMessage.Method, out var allowed) && allowed;
|
|
||||||
if (contentLengthHeaderAllowed)
|
|
||||||
{
|
|
||||||
// Set Content to empty ByteArray to be able to set the Content-Length on the content in case of a HEAD method.
|
|
||||||
httpRequestMessage.Content ??= new ByteArrayContent(EmptyArray<byte>.Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
excludeHeaders.Add(HttpKnownHeaderNames.ContentLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contentType != null)
|
if (contentType != null)
|
||||||
{
|
{
|
||||||
// Content-Type should be set on the content
|
// Content-Type should be set on the content
|
||||||
|
|||||||
@@ -2,20 +2,39 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using WireMock.Net.OpenApiParser;
|
using WireMock.Net.OpenApiParser;
|
||||||
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
|
using WireMock.Net.OpenApiParser.Types;
|
||||||
|
using WireMock.Serialization;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace WireMock.Server;
|
namespace WireMock.Server;
|
||||||
|
|
||||||
public partial class WireMockServer
|
public partial class WireMockServer
|
||||||
{
|
{
|
||||||
|
#if OPENAPIPARSER
|
||||||
|
private readonly WireMockOpenApiParserSettings _openApiParserSettings = new WireMockOpenApiParserSettings
|
||||||
|
{
|
||||||
|
PathPatternToUse = ExampleValueType.Regex,
|
||||||
|
HeaderPatternToUse = ExampleValueType.Regex,
|
||||||
|
QueryParameterPatternToUse = ExampleValueType.Regex
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
private IResponseMessage OpenApiConvertToMappings(IRequestMessage requestMessage)
|
private IResponseMessage OpenApiConvertToMappings(IRequestMessage requestMessage)
|
||||||
{
|
{
|
||||||
#if OPENAPIPARSER
|
#if OPENAPIPARSER
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var mappingModels = new WireMockOpenApiParser().FromText(requestMessage.Body, out var diagnostic);
|
var mappingModels = new WireMockOpenApiParser().FromText(requestMessage.Body, out var diagnostic);
|
||||||
return diagnostic.Errors.Any() ? ToJson(diagnostic, false, HttpStatusCode.BadRequest) : ToJson(mappingModels);
|
if (diagnostic.Errors.Any())
|
||||||
|
{
|
||||||
|
var diagnosticAsJson = JsonConvert.SerializeObject(diagnostic, JsonSerializationConstants.JsonSerializerSettingsDefault);
|
||||||
|
_settings.Logger.Warn("OpenApiError(s) while converting OpenAPI specification to MappingModel(s) : {0}", diagnosticAsJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToJson(mappingModels);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -35,7 +54,8 @@ public partial class WireMockServer
|
|||||||
var mappingModels = new WireMockOpenApiParser().FromText(requestMessage.Body, out var diagnostic);
|
var mappingModels = new WireMockOpenApiParser().FromText(requestMessage.Body, out var diagnostic);
|
||||||
if (diagnostic.Errors.Any())
|
if (diagnostic.Errors.Any())
|
||||||
{
|
{
|
||||||
return ToJson(diagnostic, false, HttpStatusCode.BadRequest);
|
var diagnosticAsJson = JsonConvert.SerializeObject(diagnostic, JsonSerializationConstants.JsonSerializerSettingsDefault);
|
||||||
|
_settings.Logger.Warn("OpenApiError(s) while converting OpenAPI specification to MappingModel(s) : {0}", diagnosticAsJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConvertMappingsAndRegisterAsRespondProvider(mappingModels);
|
ConvertMappingsAndRegisterAsRespondProvider(mappingModels);
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
using NFluent;
|
using NFluent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FluentAssertions;
|
|
||||||
using WireMock.Http;
|
using WireMock.Http;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
@@ -162,29 +160,4 @@ public class HttpRequestMessageHelperTests
|
|||||||
// Assert
|
// Assert
|
||||||
Check.That(message.Content.Headers.GetValues("Content-Type")).ContainsExactly("application/xml; charset=Ascii");
|
Check.That(message.Content.Headers.GetValues("Content-Type")).ContainsExactly("application/xml; charset=Ascii");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData("HEAD", true)]
|
|
||||||
[InlineData("GET", false)]
|
|
||||||
[InlineData("PUT", false)]
|
|
||||||
[InlineData("POST", false)]
|
|
||||||
[InlineData("DELETE", false)]
|
|
||||||
[InlineData("TRACE", false)]
|
|
||||||
[InlineData("OPTIONS", false)]
|
|
||||||
[InlineData("CONNECT", false)]
|
|
||||||
[InlineData("PATCH", false)]
|
|
||||||
public void HttpRequestMessageHelper_Create_ContentLengthAllowedForMethod(string method, bool resultShouldBe)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var key = "Content-Length";
|
|
||||||
var value = 1234;
|
|
||||||
var headers = new Dictionary<string, string[]> { { key, new[] { "1234" } } };
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), method, ClientIp, null, headers);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var message = HttpRequestMessageHelper.Create(request, "http://url");
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
message.Content?.Headers.ContentLength.Should().Be(resultShouldBe ? value : null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user