Compare commits

...

26 Commits

Author SHA1 Message Date
Stef Heyenrath
cdcaaa970a 1.0.2.13 2018-01-23 08:09:19 +01:00
Stef Heyenrath
d07a89c907 Merge remote-tracking branch 'origin/master' 2018-01-23 08:07:00 +01:00
Stef Heyenrath
141ed5d96c code update 2018-01-23 08:06:55 +01:00
vladimir-fed
6d60b3773a Fix missed content headers (#79) 2018-01-23 08:05:12 +01:00
Stef Heyenrath
e6af765777 1.0.2.12 2018-01-16 20:46:43 +01:00
Stef Heyenrath
97d80ada11 Fixed issue #76 (#77)
#76
2018-01-16 20:44:59 +01:00
Stef Heyenrath
51bd9ec186 Add WireMock.Net.WebApplication example (#75) 2018-01-11 19:38:58 +01:00
Stef Heyenrath
da798a59aa Fix wiki link to Stubbing & Request Matching 2018-01-10 16:33:32 +01:00
Stef Heyenrath
71196b51c9 Fixed issue with same Mapping Guid (#73) 2017-12-20 20:51:51 +01:00
Stef Heyenrath
d0fc889f42 Fix for url encoded path + params (1.0.2.10) - #72
Fix for url encoded path + params (1.0.2.10)
2017-12-12 18:18:04 +01:00
Stef Heyenrath
fd5bc203c3 1.0.2.9 2017-12-07 22:17:35 +01:00
Stef Heyenrath
601af2d6b2 Fixed restricted headers on response (#71)
* Fixed restricted headers on response

* appveyor
2017-12-07 22:16:19 +01:00
Stef Heyenrath
ea16ee866b 1.0.2.8 2017-11-23 20:54:30 +01:00
Stef Heyenrath
ee0cb6e670 Added unit-test for #68
Added unit-test for #68
2017-11-22 21:33:40 +01:00
Alastair Crabtree
798603118c bug: fix supporting the Patch method and logging the body (#67)
* bug: fix supporting the Patch method and logging the body

- Patch not configured to support Body
- Add a unit test

* chore: typo fixed

* Added / reordered tests for PATCH method
2017-11-20 19:32:36 +01:00
Alastair Crabtree
208303729e bug: Fix admin api client definition returning the wrong types (#65)
* bug: Fix admin api client definition returning the wrong types

- IFluentMockServerAdmin get, find and get all requests should return a log entry model
- Add tests for get and find using the rest ease api client

* Fix Build status and rename tests
2017-11-19 20:44:05 +01:00
Stef Heyenrath
d39e9ef7fa Fixed readme 2017-11-19 11:47:42 +01:00
Stef Heyenrath
431e5656ca <DebugType>full</DebugType> 2017-11-19 11:37:50 +01:00
Stef Heyenrath
fa919343ac <DebugType>portable</DebugType> 2017-11-19 11:32:39 +01:00
Stef Heyenrath
d0b48e2967 DebugType, IncludeSource and IncludeSymbols set to 'true' 2017-11-19 10:39:11 +01:00
Stef Heyenrath
018d2a904d 1.0.2.7 2017-11-18 13:49:22 +01:00
Stef Heyenrath
939a5a61ab 1.0.2.7 2017-11-18 13:48:12 +01:00
vladimir-fed
a15e6747b0 Fix issue with concurrent logging (#63)
* Fix issue with concurrent logging

* Fix namespace + code format/cleanup
2017-11-18 12:22:19 +01:00
Alastair Crabtree
6c38400827 Add the Host, Protocol, Port and Origin to the Request message so they can be used in templating (#62)
* feat: Add the Host, Protocol Port and Origin to the Request message

- Add new fields during request message creation, derived from the Uri object
- Allow the new fields to be accessed in the templating engine
- Add tests for the new fields

* source code file reformat

* appveyor
2017-11-18 12:03:13 +01:00
Stef Heyenrath
cb1117fdaa IHeadersAndCookiesRequestBuilder 2017-11-11 10:09:41 +01:00
Stef Heyenrath
e25c873765 Update ProxyAndRecord
ProxyAndRecord does not save query-parameters, headers and body (#57)
2017-11-07 21:52:30 +01:00
60 changed files with 1350 additions and 560 deletions

View File

@@ -3,9 +3,9 @@ A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) w
[![Build status](https://ci.appveyor.com/api/projects/status/b3n6q3ygbww4lyls?svg=true)](https://ci.appveyor.com/project/StefH/wiremock-net)
[![codecov](https://codecov.io/gh/WireMock-Net/WireMock.Net/branch/master/graph/badge.svg)](https://codecov.io/gh/WireMock-Net/WireMock.Net)
[![Coverage Status](https://coveralls.io/repos/github/StefH/WireMock.Net/badge.svg?branch=master)](https://coveralls.io/github/StefH/WireMock.Net?branch=master)
[![GitHub issues](https://img.shields.io/github/issues/StefH/WireMock.Net.svg)](https://github.com/StefH/WireMock.Net/issues)
[![GitHub stars](https://img.shields.io/github/stars/StefH/WireMock.Net.svg)](https://github.com/StefH/WireMock.Net/stargazers)
[![Coverage Status](https://coveralls.io/repos/github/WireMock-Net/WireMock.Net/badge.svg?branch=master)](https://coveralls.io/github/WireMock-Net/WireMock.Net?branch=master)
[![GitHub issues](https://img.shields.io/github/issues/WireMock-Net/WireMock.Net.svg)](https://github.com/WireMock-Net/WireMock.Net/issues)
[![GitHub stars](https://img.shields.io/github/stars/WireMock-Net/WireMock.Net.svg)](https://github.com/WireMock-Net/WireMock.Net/stargazers)
| Name | NuGet |
| ---- | ----- |
@@ -28,7 +28,7 @@ To build you need:
## Stubbing
A core feature of WireMock.Net is the ability to return canned/predefined HTTP responses for requests matching criteria, see [Wiki : Stubbing](https://github.com/StefH/WireMock.Net/wiki/Stubbing).
A core feature of WireMock.Net is the ability to return canned/predefined HTTP responses for requests matching criteria, see [Wiki : Stubbing & Request Matching](https://github.com/WireMock-Net/WireMock.Net/wiki/Stubbing-and-Request-Matching).
## Using WireMock in UnitTest framework
You can use your favorite test framework and use WireMock within your tests, see

View File

@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2005
VisualStudioVersion = 15.0.27130.2020
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EF242EDF-7133-4277-9A0C-18744DE08707}"
EndProject
@@ -14,9 +14,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{F0C22C47-DF71-463C-9B04-B4E0F3B8708A}"
ProjectSection(SolutionItems) = preProject
examples\WireMock.Net.Console.Record.NETCoreApp\__admin\mappings\ab38efae-4e4d-4f20-8afe-635533ec2535.json = examples\WireMock.Net.Console.Record.NETCoreApp\__admin\mappings\ab38efae-4e4d-4f20-8afe-635533ec2535.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{890A1DED-C229-4FA1-969E-AAC3BBFC05E5}"
EndProject
@@ -39,7 +36,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.StandAlone.Net
{B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {B6269AAC-170A-43D5-8B9A-579DED3D9A95}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.ConsoleApplication", "examples\WireMock.Net.ConsoleApplication\WireMock.Net.ConsoleApplication.csproj", "{668F689E-57B4-422E-8846-C0FF643CA268}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Console.NET452", "examples\WireMock.Net.ConsoleApplication\WireMock.Net.Console.NET452.csproj", "{668F689E-57B4-422E-8846-C0FF643CA268}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.WebApplication", "examples\WireMock.Net.WebApplication\WireMock.Net.WebApplication.csproj", "{049539C1-7A66-4559-AD7A-B1C73B97CBB0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -83,6 +82,10 @@ Global
{668F689E-57B4-422E-8846-C0FF643CA268}.Debug|Any CPU.Build.0 = Debug|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA268}.Release|Any CPU.ActiveCfg = Release|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA268}.Release|Any CPU.Build.0 = Release|Any CPU
{049539C1-7A66-4559-AD7A-B1C73B97CBB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{049539C1-7A66-4559-AD7A-B1C73B97CBB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{049539C1-7A66-4559-AD7A-B1C73B97CBB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{049539C1-7A66-4559-AD7A-B1C73B97CBB0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -97,6 +100,7 @@ Global
{10E16614-61CA-48D8-8BDD-664C13913DED} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{668F689E-57B4-422E-8846-C0FF643CA999} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{668F689E-57B4-422E-8846-C0FF643CA268} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{049539C1-7A66-4559-AD7A-B1C73B97CBB0} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BF428BCC-C837-433B-87D2-15C7014B73E9}

View File

@@ -21,7 +21,6 @@ environment:
before_build:
- dotnet restore .\src\WireMock.Net\WireMock.Net.csproj
- dotnet restore .\src\WireMock.Net.Standalone\WireMock.Net.Standalone.csproj
- nuget restore .\examples\WireMock.Net.ConsoleApplication\WireMock.Net.ConsoleApplication.csproj -PackagesDirectory packages
build_script:
# build WireMock.Net
@@ -39,6 +38,6 @@ test_script:
- nuget.exe install coveralls.net -ExcludeVersion
- pip install codecov
- cmd: '"OpenCover\tools\OpenCover.Console.exe" -register:user -target:dotnet.exe -targetargs:"test test\WireMock.Net.Tests\WireMock.Net.Tests.csproj --no-build" -returntargetcode -filter:"+[WireMock.Net]* -[WireMock.Net.Tests*]*" -output:coverage.xml -oldstyle -searchdirs:".\test\WireMock.Net.Tests\bin\%CONFIGURATION%\net452"'
- cmd: '"OpenCover\tools\OpenCover.Console.exe" -target:dotnet.exe -targetargs:"test test\WireMock.Net.Tests\WireMock.Net.Tests.csproj --no-build" -output:coverage.xml -returntargetcode -register:user -filter:"+[WireMock.Net]* -[WireMock.Net.Tests*]*" -nodefaultfilters -returntargetcode -oldstyle -searchdirs:".\test\WireMock.Net.Tests\bin\%CONFIGURATION%\net452"'
- codecov -f "coverage.xml"
- coveralls.net\tools\csmacnz.Coveralls.exe --opencover -i .\coverage.xml

View File

@@ -9,7 +9,7 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="RestEase" Version="1.4.3" />
<PackageReference Include="RestEase" Version="1.4.4" />
</ItemGroup>
<ItemGroup>

View File

@@ -12,12 +12,13 @@ namespace WireMock.Net.Console.Record.NETCoreApp
{
Urls = new[] { "http://localhost:9091/", "https://localhost:9443/" },
StartAdminInterface = true,
ReadStaticMappings = true,
ReadStaticMappings = false,
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = "https://www.google.com",
//X509Certificate2ThumbprintOrSubjectName = "www.yourclientcertname.com OR yourcertificatethumbprint (only if the service you're proxying to requires it)",
SaveMapping = true
SaveMapping = true,
SaveMappingToFile = false
}
});

View File

@@ -21,6 +21,10 @@ namespace WireMock.Net.ConsoleApplication
Urls = new[] { url1, url2, url3 },
StartAdminInterface = true,
ReadStaticMappings = true,
//ProxyAndRecordSettings = new ProxyAndRecordSettings
//{
// SaveMapping = true
//},
PreWireMockMiddlewareInit = app => { System.Console.WriteLine($"PreWireMockMiddlewareInit : {app.GetType()}"); },
PostWireMockMiddlewareInit = app => { System.Console.WriteLine($"PostWireMockMiddlewareInit : {app.GetType()}"); }
});
@@ -28,7 +32,22 @@ namespace WireMock.Net.ConsoleApplication
server.SetBasicAuthentication("a", "b");
// server.AllowPartialMapping();
server.AllowPartialMapping();
// .WithHeader("Stef", "Stef")
//server
// .Given(Request.Create().WithPath("*"))
// .RespondWith(Response.Create()
// .WithProxy("http://restcountries.eu"));
server
.Given(Request
.Create()
.WithPath(new WildcardMatcher("/navision/OData/Company('My Company')/School*", true))
.WithParam("$filter", "(substringof(Code, 'WA')")
.UsingGet())
.RespondWith(Response.Create()
.WithBody(@"{ ""result"": ""odata""}"));
server
.Given(Request.Create().WithPath("/headers", "/headers_test").UsingPost().WithHeader("Content-Type", "application/json*"))

View File

@@ -7,15 +7,15 @@ namespace WireMock.Net.StandAlone.NETCoreApp
class Program
{
private static int sleepTime = 30000;
private static FluentMockServer server;
private static FluentMockServer _server;
static void Main(string[] args)
{
server = StandAloneApp.Start(args);
_server = StandAloneApp.Start(args);
Console.WriteLine($"{DateTime.UtcNow} Press Ctrl+C to shut down");
System.Console.CancelKeyPress += (s,e) =>
Console.CancelKeyPress += (s, e) =>
{
Stop("CancelKeyPress");
};
@@ -25,7 +25,7 @@ namespace WireMock.Net.StandAlone.NETCoreApp
Stop("AssemblyLoadContext.Default.Unloading");
};
while(true)
while (true)
{
Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server running");
Thread.Sleep(sleepTime);
@@ -35,7 +35,7 @@ namespace WireMock.Net.StandAlone.NETCoreApp
private static void Stop(string why)
{
Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server stopping because '{why}'");
server.Stop();
_server.Stop();
Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server stopped");
}
}

View File

@@ -0,0 +1,22 @@
using Microsoft.Extensions.Logging;
namespace WireMock.Net.WebApplication
{
public class App
{
private readonly IWireMockService _service;
private readonly ILogger _logger;
public App(IWireMockService service, ILogger logger)
{
_service = service;
_logger = logger;
}
public void Run()
{
_logger.LogInformation("WireMock.Net App running");
_service.Run();
}
}
}

View File

@@ -0,0 +1,7 @@
namespace WireMock.Net.WebApplication
{
public interface IWireMockService
{
void Run();
}
}

View File

@@ -0,0 +1,57 @@
using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using WireMock.Settings;
namespace WireMock.Net.WebApplication
{
public class Program
{
public static void Main(string[] args)
{
// Create service collection
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
// Create service provider
var serviceProvider = serviceCollection.BuildServiceProvider();
// Run app
serviceProvider.GetService<App>().Run();
}
private static void ConfigureServices(IServiceCollection serviceCollection)
{
// Build configuration
var configuration = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables() // <-- this is needed to to override settings via the Azure Portal App Settings
.Build();
// Add LoggerFactory
var factory = new LoggerFactory();
serviceCollection.AddSingleton(factory
.AddConsole(configuration.GetSection("Logging"))
.AddDebug()
.AddAzureWebAppDiagnostics()
);
serviceCollection.AddSingleton(factory.CreateLogger("WireMock.Net Logger"));
// Add access to generic IConfigurationRoot
serviceCollection.AddSingleton(configuration);
// Add access to IFluentMockServerSettings
var settings = configuration.GetSection("FluentMockServerSettings").Get<FluentMockServerSettings>();
serviceCollection.AddSingleton<IFluentMockServerSettings>(settings);
// Add services
serviceCollection.AddTransient<IWireMockService, WireMockService>();
// Add app
serviceCollection.AddTransient<App>();
}
}
}

View File

@@ -0,0 +1,28 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:56513/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchUrl": "__admin/settings",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"WireMock.Net.WebApplication": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "__admin/settings",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:56514/"
}
}
}

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,37 @@
using System.Threading;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using WireMock.Net.StandAlone;
using WireMock.Settings;
namespace WireMock.Net.WebApplication
{
public class WireMockService : IWireMockService
{
private static int sleepTime = 30000;
private readonly ILogger _logger;
private readonly IFluentMockServerSettings _settings;
public WireMockService(ILogger logger, IFluentMockServerSettings settings)
{
_logger = logger;
_settings = settings;
}
public void Run()
{
_logger.LogInformation("WireMock.Net server starting");
StandAloneApp.Start(_settings);
_logger.LogInformation($"WireMock.Net server settings {JsonConvert.SerializeObject(_settings)}");
while (true)
{
_logger.LogInformation("WireMock.Net server running");
Thread.Sleep(sleepTime);
}
}
}
}

View File

@@ -0,0 +1,20 @@
{
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Debug"
}
},
"Console": {
"LogLevel": {
"Default": "Debug"
}
}
},
"FluentMockServerSettings": {
"AdminUsername": "a",
"AdminPassword": "a",
"StartAdminInterface": true
}
}

View File

@@ -18,7 +18,7 @@ namespace WireMock.Net.StandAlone
/// </summary>
/// <param name="settings">The FluentMockServerSettings</param>
[PublicAPI]
public static FluentMockServer Start([NotNull] FluentMockServerSettings settings)
public static FluentMockServer Start([NotNull] IFluentMockServerSettings settings)
{
Check.NotNull(settings, nameof(settings));
@@ -66,6 +66,7 @@ namespace WireMock.Net.StandAlone
{
Url = proxyURL,
SaveMapping = parser.GetBoolValue("SaveMapping"),
SaveMappingToFile = parser.GetBoolValue("SaveMappingToFile"),
X509Certificate2ThumbprintOrSubjectName = parser.GetStringValue("X509Certificate2ThumbprintOrSubjectName")
};
}

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<Description>Lightweight StandAlone Http Mocking Server for .Net.</Description>
<AssemblyTitle>WireMock.Net.StandAlone</AssemblyTitle>
<Version>1.0.2.6</Version>
<Version>1.0.2.13</Version>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

View File

@@ -55,6 +55,7 @@ namespace WireMock.Client
/// </summary>
/// <param name="mapping">MappingModel</param>
[Post("__admin/mappings")]
[Header("Content-Type", "application/json")]
Task<string> PostMappingAsync([Body] MappingModel mapping);
/// <summary>
@@ -103,7 +104,7 @@ namespace WireMock.Client
/// </summary>
/// <returns>LogRequestModels</returns>
[Get("__admin/requests")]
Task<IList<LogRequestModel>> GetRequestsAsync();
Task<IList<LogEntryModel>> GetRequestsAsync();
/// <summary>
/// Delete all requests.
@@ -123,7 +124,7 @@ namespace WireMock.Client
/// <param name="guid">The Guid</param>
/// <returns>MappingModel</returns>
[Get("__admin/requests/{guid}")]
Task<LogRequestModel> GetRequestAsync([Path] Guid guid);
Task<LogEntryModel> GetRequestAsync([Path] Guid guid);
/// <summary>
/// Delete a request based on the guid
@@ -137,7 +138,8 @@ namespace WireMock.Client
/// </summary>
/// <param name="model">The RequestModel</param>
[Post("__admin/requests/find")]
Task<IList<LogRequestModel>> FindRequestsAsync([Body] RequestModel model);
[Header("Content-Type", "application/json")]
Task<IList<LogEntryModel>> FindRequestsAsync([Body] RequestModel model);
/// <summary>
/// Get all scenarios

View File

@@ -42,10 +42,10 @@ namespace WireMock
internal class ProxyAsyncResponseProvider : IResponseProvider
{
private readonly Func<RequestMessage, ProxyAndRecordSettings, Task<ResponseMessage>> _responseMessageFunc;
private readonly ProxyAndRecordSettings _settings;
private readonly Func<RequestMessage, IProxyAndRecordSettings, Task<ResponseMessage>> _responseMessageFunc;
private readonly IProxyAndRecordSettings _settings;
public ProxyAsyncResponseProvider([NotNull] Func<RequestMessage, ProxyAndRecordSettings, Task<ResponseMessage>> responseMessageFunc, [NotNull] ProxyAndRecordSettings settings)
public ProxyAsyncResponseProvider([NotNull] Func<RequestMessage, IProxyAndRecordSettings, Task<ResponseMessage>> responseMessageFunc, [NotNull] IProxyAndRecordSettings settings)
{
Check.NotNull(responseMessageFunc, nameof(responseMessageFunc));
Check.NotNull(settings, nameof(settings));

View File

@@ -62,7 +62,7 @@ namespace WireMock.Http
var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url);
// Set Body if present
if (requestMessage.BodyAsBytes != null && requestMessage.BodyAsBytes.Length > 0)
if (requestMessage.BodyAsBytes != null)
{
httpRequestMessage.Content = new ByteArrayContent(requestMessage.BodyAsBytes);
}

View File

@@ -5,18 +5,15 @@ using System.Text.RegularExpressions;
namespace WireMock.Http
{
/// <summary>
/// Utility class
/// Port Utility class
/// </summary>
public static class PortUtil
{
private static readonly Regex UrlDetailsRegex = new Regex(@"^(?<proto>\w+)://[^/]+?(?<port>\d+)?/", RegexOptions.Compiled);
/// <summary>
/// The find free TCP port.
/// Finds a free TCP port.
/// </summary>
/// <returns>
/// The <see cref="int"/>.
/// </returns>
/// <remarks>see http://stackoverflow.com/questions/138043/find-the-next-tcp-port-in-net.</remarks>
public static int FindFreeTcpPort()
{

View File

@@ -13,25 +13,16 @@ namespace WireMock
/// <summary>
/// Gets the unique identifier.
/// </summary>
/// <value>
/// The unique identifier.
/// </value>
public Guid Guid { get; }
/// <summary>
/// Gets the unique title.
/// </summary>
/// <value>
/// The unique title.
/// </value>
public string Title { get; }
/// <summary>
/// Gets the priority.
/// </summary>
/// <value>
/// The priority.
/// </value>
public int Priority { get; }
/// <summary>

View File

@@ -25,7 +25,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class.
/// </summary>
/// <param name="clientIPs">The clientIPs.</param>
public RequestMessageClientIPMatcher([NotNull] params string[] clientIPs) : this(clientIPs.Select(ip => new WildcardMatcher(ip)).ToArray())
public RequestMessageClientIPMatcher([NotNull] params string[] clientIPs) : this(clientIPs.Select(ip => new WildcardMatcher(ip)).Cast<IMatcher>().ToArray())
{
}
@@ -49,14 +49,7 @@ namespace WireMock.Matchers.Request
Funcs = funcs;
}
/// <summary>
/// Determines whether the specified RequestMessage is match.
/// </summary>
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
/// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);

View File

@@ -10,6 +10,7 @@ namespace WireMock.Matchers.Request
/// <summary>
/// The request header matcher.
/// </summary>
/// <inheritdoc cref="IRequestMatcher"/>
public class RequestMessageHeaderMatcher : IRequestMatcher
{
/// <summary>
@@ -32,7 +33,7 @@ namespace WireMock.Matchers.Request
/// </summary>
/// <param name="name">The name.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">The ignoreCase.</param>
/// <param name="ignoreCase">if set to <c>true</c> [ignore case].</param>
public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] string pattern, bool ignoreCase = true)
{
Check.NotNull(name, nameof(name));
@@ -42,6 +43,21 @@ namespace WireMock.Matchers.Request
Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) };
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">if set to <c>true</c> [ignore case].</param>
public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] string[] patterns, bool ignoreCase = true)
{
Check.NotNull(name, nameof(name));
Check.NotNull(patterns, nameof(patterns));
Name = name;
Matchers = patterns.Select(pattern => new WildcardMatcher(pattern, ignoreCase)).Cast<IMatcher>().ToArray();
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary>
@@ -67,14 +83,7 @@ namespace WireMock.Matchers.Request
Funcs = funcs;
}
/// <summary>
/// Determines whether the specified RequestMessage is match.
/// </summary>
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
/// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);

View File

@@ -30,12 +30,8 @@ namespace WireMock.Matchers.Request
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
/// </summary>
/// <param name="key">
/// The key.
/// </param>
/// <param name="values">
/// The values.
/// </param>
/// <param name="key">The key.</param>
/// <param name="values">The values.</param>
public RequestMessageParamMatcher([NotNull] string key, [CanBeNull] IEnumerable<string> values)
{
Check.NotNull(key, nameof(key));
@@ -51,17 +47,11 @@ namespace WireMock.Matchers.Request
public RequestMessageParamMatcher([NotNull] params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs)
{
Check.NotNull(funcs, nameof(funcs));
Funcs = funcs;
}
/// <summary>
/// Determines whether the specified RequestMessage is match.
/// </summary>
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
/// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
@@ -71,7 +61,9 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage)
{
if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.Query != null && Funcs.Any(f => f(requestMessage.Query)));
}
List<string> values = requestMessage.GetParameter(Key);

View File

@@ -25,7 +25,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary>
/// <param name="paths">The paths.</param>
public RequestMessagePathMatcher([NotNull] params string[] paths) : this(paths.Select(path => new WildcardMatcher(path)).ToArray())
public RequestMessagePathMatcher([NotNull] params string[] paths) : this(paths.Select(path => new WildcardMatcher(path)).Cast<IMatcher>().ToArray())
{
}
@@ -49,14 +49,7 @@ namespace WireMock.Matchers.Request
Funcs = funcs;
}
/// <summary>
/// Determines whether the specified RequestMessage is match.
/// </summary>
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
/// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);

View File

@@ -25,7 +25,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary>
/// <param name="urls">The urls.</param>
public RequestMessageUrlMatcher([NotNull] params string[] urls) : this(urls.Select(url => new WildcardMatcher(url)).ToArray())
public RequestMessageUrlMatcher([NotNull] params string[] urls) : this(urls.Select(url => new WildcardMatcher(url)).Cast<IMatcher>().ToArray())
{
}
@@ -49,14 +49,7 @@ namespace WireMock.Matchers.Request
Funcs = funcs;
}
/// <summary>
/// Determines whether the specified RequestMessage is match.
/// </summary>
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
/// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);

View File

@@ -46,6 +46,7 @@ namespace WireMock.Owin
_host = new WebHostBuilder()
.Configure(appBuilder =>
{
appBuilder.UseMiddleware<GlobalExceptionMiddleware>();
_options.PreWireMockMiddlewareInit?.Invoke(appBuilder);
appBuilder.UseMiddleware<WireMockMiddleware>(_options);
_options.PostWireMockMiddlewareInit?.Invoke(appBuilder);

View File

@@ -0,0 +1,49 @@
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
#if !NETSTANDARD
using Microsoft.Owin;
#else
using Microsoft.AspNetCore.Http;
#endif
namespace WireMock.Owin
{
#if !NETSTANDARD
internal class GlobalExceptionMiddleware : OwinMiddleware
#else
internal class GlobalExceptionMiddleware
#endif
{
#if !NETSTANDARD
public GlobalExceptionMiddleware(OwinMiddleware next) : base(next) { }
#else
public GlobalExceptionMiddleware(RequestDelegate next)
{
Next = next;
}
#endif
#if NETSTANDARD
public RequestDelegate Next { get; }
#endif
private readonly OwinResponseMapper _responseMapper = new OwinResponseMapper();
#if !NETSTANDARD
public override async Task Invoke(IOwinContext ctx)
#else
public async Task Invoke(HttpContext ctx)
#endif
{
try
{
await Next?.Invoke(ctx);
}
catch (Exception ex)
{
await _responseMapper.MapAsync(new ResponseMessage { StatusCode = 500, Body = JsonConvert.SerializeObject(ex) }, ctx.Response);
}
}
}
}

View File

@@ -91,8 +91,9 @@ namespace WireMock.Owin
TRACE - Body not supported.
OPTIONS - Body supported but no semantics on usage (maybe in the future).
CONNECT - No defined body semantics
PATCH - Body supported.
*/
return new[] { "PUT", "POST", "OPTIONS" }.Contains(method.ToUpper());
return new[] { "PUT", "POST", "OPTIONS", "PATCH" }.Contains(method.ToUpper());
}
}
}

View File

@@ -1,8 +1,10 @@
using System.IO;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WireMock.Http;
using WireMock.Util;
#if !NETSTANDARD
using Microsoft.Owin;
#else
@@ -18,6 +20,19 @@ namespace WireMock.Owin
{
private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
// https://stackoverflow.com/questions/239725/cannot-set-some-http-headers-when-using-system-net-webrequest
#if !NETSTANDARD
private static readonly IDictionary<string, Action<IOwinResponse, WireMockList<string>>> RestrictedResponseHeaders = new Dictionary<string, Action<IOwinResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
#else
private static readonly IDictionary<string, Action<HttpResponse, WireMockList<string>>> RestrictedResponseHeaders = new Dictionary<string, Action<HttpResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
#endif
{ "Content-Length", null },
{ "Content-Type", (r, v) => r.ContentType = v.FirstOrDefault() },
{ "Keep-Alive", null },
{ "Transfer-Encoding", null },
{ "WWW-Authenticate", null }
};
/// <summary>
/// MapAsync ResponseMessage to OwinResponse
/// </summary>
@@ -33,18 +48,22 @@ namespace WireMock.Owin
{
response.StatusCode = responseMessage.StatusCode;
if (responseMessage.Headers.ContainsKey(HttpKnownHeaderNames.ContentType))
// Set headers
foreach (var pair in responseMessage.Headers)
{
response.ContentType = responseMessage.Headers[HttpKnownHeaderNames.ContentType].FirstOrDefault();
}
var headers = responseMessage.Headers.Where(h => h.Key != HttpKnownHeaderNames.ContentType).ToList();
if (RestrictedResponseHeaders.ContainsKey(pair.Key))
{
RestrictedResponseHeaders[pair.Key]?.Invoke(response, pair.Value);
}
else
{
#if !NETSTANDARD
headers.ForEach(pair => response.Headers.AppendValues(pair.Key, pair.Value.ToArray()));
response.Headers.AppendValues(pair.Key, pair.Value.ToArray());
#else
headers.ForEach(pair => response.Headers.Append(pair.Key, pair.Value.ToArray()));
response.Headers.Append(pair.Key, pair.Value.ToArray());
#endif
}
}
if (responseMessage.Body == null && responseMessage.BodyAsBytes == null && responseMessage.BodyAsFile == null)
{

View File

@@ -57,10 +57,11 @@ namespace WireMock.Owin
private void StartServers()
{
Console.WriteLine("WireMock.Net server using .net 4.5.x or .net 4.6.x");
Console.WriteLine("WireMock.Net server using .net 4.5.x or higher");
Action<IAppBuilder> startup = app =>
{
app.Use<GlobalExceptionMiddleware>();
_options.PreWireMockMiddlewareInit?.Invoke(app);
app.Use<WireMockMiddleware>(_options);
_options.PostWireMockMiddlewareInit?.Invoke(app);

View File

@@ -5,6 +5,7 @@ using WireMock.Matchers.Request;
using System.Linq;
using WireMock.Matchers;
using WireMock.Util;
using Newtonsoft.Json;
#if !NETSTANDARD
using Microsoft.Owin;
#else
@@ -124,7 +125,7 @@ namespace WireMock.Owin
}
catch (Exception ex)
{
response = new ResponseMessage { StatusCode = 500, Body = ex.ToString() };
response = new ResponseMessage { StatusCode = 500, Body = JsonConvert.SerializeObject(ex) };
}
finally
{

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Util;
#if !NETSTANDARD
using Owin;
#else
@@ -22,7 +23,7 @@ namespace WireMock.Owin
public IList<Mapping> Mappings { get; set; } = new List<Mapping>();
public ObservableCollection<LogEntry> LogEntries { get; } = new ObservableCollection<LogEntry>();
public ObservableCollection<LogEntry> LogEntries { get; } = new ConcurentObservableCollection<LogEntry>();
public int? RequestLogExpirationDuration { get; set; }

View File

@@ -12,7 +12,7 @@ namespace WireMock.RequestBuilders
public interface IHeadersAndCookiesRequestBuilder : IBodyRequestBuilder, IRequestMatcher, IParamsRequestBuilder
{
/// <summary>
/// The with header.
/// Add Header matching based on name, pattern and ignoreCase.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="pattern">The pattern.</param>
@@ -20,6 +20,15 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithHeader([NotNull] string name, string pattern, bool ignoreCase = true);
/// <summary>
/// Add Header matching based on name, patterns and ignoreCase.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">ignore Case</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithHeader([NotNull] string name, string[] patterns, bool ignoreCase = true);
/// <summary>
/// The with header.
/// </summary>

View File

@@ -7,6 +7,14 @@ namespace WireMock.RequestBuilders
/// </summary>
public interface IMethodRequestBuilder : IHeadersAndCookiesRequestBuilder
{
/// <summary>
/// The using delete.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
IRequestBuilder UsingDelete();
/// <summary>
/// The using get.
/// </summary>
@@ -15,6 +23,14 @@ namespace WireMock.RequestBuilders
/// </returns>
IRequestBuilder UsingGet();
/// <summary>
/// The using head.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
IRequestBuilder UsingHead();
/// <summary>
/// The using post.
/// </summary>
@@ -24,12 +40,12 @@ namespace WireMock.RequestBuilders
IRequestBuilder UsingPost();
/// <summary>
/// The using delete.
/// The using patch.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
IRequestBuilder UsingDelete();
IRequestBuilder UsingPatch();
/// <summary>
/// The using put.
@@ -39,14 +55,6 @@ namespace WireMock.RequestBuilders
/// </returns>
IRequestBuilder UsingPut();
/// <summary>
/// The using head.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
IRequestBuilder UsingHead();
/// <summary>
/// The using any verb.
/// </summary>

View File

@@ -171,70 +171,49 @@ namespace WireMock.RequestBuilders
return this;
}
/// <summary>
/// The using get.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
public IRequestBuilder UsingGet()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("get"));
return this;
}
/// <summary>
/// The using post.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
public IRequestBuilder UsingPost()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("post"));
return this;
}
/// <summary>
/// The using put.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
public IRequestBuilder UsingPut()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("put"));
return this;
}
/// <summary>
/// The using delete.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
/// <inheritdoc cref="IMethodRequestBuilder.UsingDelete"/>
public IRequestBuilder UsingDelete()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("delete"));
return this;
}
/// <summary>
/// The using head.
/// </summary>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
/// <inheritdoc cref="IMethodRequestBuilder.UsingGet"/>
public IRequestBuilder UsingGet()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("get"));
return this;
}
/// <inheritdoc cref="IMethodRequestBuilder.UsingHead"/>
public IRequestBuilder UsingHead()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("head"));
return this;
}
/// <summary>
/// The using any verb.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
/// <inheritdoc cref="IMethodRequestBuilder.UsingPost"/>
public IRequestBuilder UsingPost()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("post"));
return this;
}
/// <inheritdoc cref="IMethodRequestBuilder.UsingPatch"/>
public IRequestBuilder UsingPatch()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("patch"));
return this;
}
/// <inheritdoc cref="IMethodRequestBuilder.UsingPut"/>
public IRequestBuilder UsingPut()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("put"));
return this;
}
/// <inheritdoc cref="IMethodRequestBuilder.UsingAnyVerb"/>
public IRequestBuilder UsingAnyVerb()
{
var matchers = _requestMatchers.Where(m => m is RequestMessageMethodMatcher).ToList();
@@ -246,11 +225,7 @@ namespace WireMock.RequestBuilders
return this;
}
/// <summary>
/// The using verb.
/// </summary>
/// <param name="verbs">The verbs.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
/// <inheritdoc cref="IMethodRequestBuilder.UsingVerb"/>
public IRequestBuilder UsingVerb(params string[] verbs)
{
Check.NotEmpty(verbs, nameof(verbs));
@@ -359,13 +334,7 @@ namespace WireMock.RequestBuilders
return this;
}
/// <summary>
/// With header.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">if set to <c>true</c> [ignore case].</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
/// <inheritdoc cref="IHeadersAndCookiesRequestBuilder.WithHeader(string,string,bool)"/>
public IRequestBuilder WithHeader(string name, string pattern, bool ignoreCase = true)
{
Check.NotNull(name, nameof(name));
@@ -375,6 +344,16 @@ namespace WireMock.RequestBuilders
return this;
}
/// <inheritdoc cref="IHeadersAndCookiesRequestBuilder.WithHeader(string,string[],bool)"/>
public IRequestBuilder WithHeader(string name, string[] patterns, bool ignoreCase = true)
{
Check.NotNull(name, nameof(name));
Check.NotNull(patterns, nameof(patterns));
_requestMatchers.Add(new RequestMessageHeaderMatcher(name, patterns, ignoreCase));
return this;
}
/// <summary>
/// With header.
/// </summary>

View File

@@ -1,146 +1,177 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using WireMock.Util;
using WireMock.Validation;
using System.Text;
namespace WireMock
{
/// <summary>
/// The request.
/// </summary>
public class RequestMessage
{
/// <summary>
/// Gets the Client IP Address.
/// </summary>
public string ClientIP { get; }
/// <summary>
/// Gets the url.
/// </summary>
public string Url { get; }
/// <summary>
/// Gets the DateTime.
/// </summary>
public DateTime DateTime { get; set; }
/// <summary>
/// Gets the path.
/// </summary>
public string Path { get; }
/// <summary>
/// Gets the method.
/// </summary>
public string Method { get; }
/// <summary>
/// Gets the headers.
/// </summary>
public IDictionary<string, WireMockList<string>> Headers { get; }
/// <summary>
/// Gets the cookies.
/// </summary>
public IDictionary<string, string> Cookies { get; }
/// <summary>
/// Gets the query.
/// </summary>
public IDictionary<string, WireMockList<string>> Query { get; }
/// <summary>
/// Gets the bodyAsBytes.
/// </summary>
public byte[] BodyAsBytes { get; }
/// <summary>
/// Gets the body.
/// </summary>
public string Body { get; }
/// <summary>
/// Gets the body encoding.
/// </summary>
public Encoding BodyEncoding { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessage"/> class.
/// </summary>
/// <param name="url">The original url.</param>
/// <param name="method">The HTTP method.</param>
/// <param name="clientIP">The client IP Address.</param>
/// <param name="bodyAsBytes">The bodyAsBytes byte[].</param>
/// <param name="body">The body string.</param>
/// <param name="bodyEncoding">The body encoding</param>
/// <param name="headers">The headers.</param>
/// <param name="cookies">The cookies.</param>
public RequestMessage([NotNull] Uri url, [NotNull] string method, [NotNull] string clientIP, [CanBeNull] byte[] bodyAsBytes = null, [CanBeNull] string body = null, [CanBeNull] Encoding bodyEncoding = null, [CanBeNull] IDictionary<string, string[]> headers = null, [CanBeNull] IDictionary<string, string> cookies = null)
{
Check.NotNull(url, nameof(url));
Check.NotNull(method, nameof(method));
Check.NotNull(clientIP, nameof(clientIP));
Url = url.ToString();
Path = url.AbsolutePath;
Method = method.ToLower();
ClientIP = clientIP;
BodyAsBytes = bodyAsBytes;
Body = body;
BodyEncoding = bodyEncoding;
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
Cookies = cookies;
Query = ParseQuery(url.Query);
}
private IDictionary<string, WireMockList<string>> ParseQuery(string queryString)
{
if (string.IsNullOrEmpty(queryString))
{
return null;
}
if (queryString.StartsWith("?"))
{
queryString = queryString.Substring(1);
}
return queryString.Split('&').Aggregate(new Dictionary<string, WireMockList<string>>(),
(dict, term) =>
{
var parts = term.Split('=');
string key = parts[0];
if (!dict.ContainsKey(key))
{
dict.Add(key, new WireMockList<string>());
}
if (parts.Length == 2)
{
dict[key].Add(parts[1]);
}
return dict;
});
}
/// <summary>
/// The get a query parameter.
/// </summary>
/// <param name="key">The key.</param>
/// <returns>The query parameter.</returns>
public List<string> GetParameter(string key)
{
if (Query == null)
{
return null;
}
return Query.ContainsKey(key) ? Query[key] : null;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using JetBrains.Annotations;
using WireMock.Util;
using WireMock.Validation;
namespace WireMock
{
/// <summary>
/// The request.
/// </summary>
public class RequestMessage
{
/// <summary>
/// Gets the Client IP Address.
/// </summary>
public string ClientIP { get; }
/// <summary>
/// Gets the url.
/// </summary>
public string Url { get; }
/// <summary>
/// Gets the DateTime.
/// </summary>
public DateTime DateTime { get; set; }
/// <summary>
/// Gets the path.
/// </summary>
public string Path { get; }
/// <summary>
/// Gets the method.
/// </summary>
public string Method { get; }
/// <summary>
/// Gets the headers.
/// </summary>
public IDictionary<string, WireMockList<string>> Headers { get; }
/// <summary>
/// Gets the cookies.
/// </summary>
public IDictionary<string, string> Cookies { get; }
/// <summary>
/// Gets the query.
/// </summary>
public IDictionary<string, WireMockList<string>> Query { get; }
/// <summary>
/// Gets the raw query.
/// </summary>
public string RawQuery { get; }
/// <summary>
/// Gets the bodyAsBytes.
/// </summary>
public byte[] BodyAsBytes { get; }
/// <summary>
/// Gets the body.
/// </summary>
public string Body { get; }
/// <summary>
/// Gets the Host
/// </summary>
public string Host { get; }
/// <summary>
/// Gets the protocol
/// </summary>
public string Protocol { get; }
/// <summary>
/// Gets the port
/// </summary>
public int Port { get; }
/// <summary>
/// Gets the origin
/// </summary>
public string Origin { get; }
/// <summary>
/// Gets the body encoding.
/// </summary>
public Encoding BodyEncoding { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessage"/> class.
/// </summary>
/// <param name="url">The original url.</param>
/// <param name="method">The HTTP method.</param>
/// <param name="clientIP">The client IP Address.</param>
/// <param name="bodyAsBytes">The bodyAsBytes byte[].</param>
/// <param name="body">The body string.</param>
/// <param name="bodyEncoding">The body encoding</param>
/// <param name="headers">The headers.</param>
/// <param name="cookies">The cookies.</param>
public RequestMessage([NotNull] Uri url, [NotNull] string method, [NotNull] string clientIP, [CanBeNull] byte[] bodyAsBytes = null, [CanBeNull] string body = null, [CanBeNull] Encoding bodyEncoding = null, [CanBeNull] IDictionary<string, string[]> headers = null, [CanBeNull] IDictionary<string, string> cookies = null)
{
Check.NotNull(url, nameof(url));
Check.NotNull(method, nameof(method));
Check.NotNull(clientIP, nameof(clientIP));
Url = url.ToString();
Protocol = url.Scheme;
Host = url.Host;
Port = url.Port;
Origin = $"{url.Scheme}://{url.Host}:{url.Port}";
Path = WebUtility.UrlDecode(url.AbsolutePath);
Method = method.ToLower();
ClientIP = clientIP;
BodyAsBytes = bodyAsBytes;
Body = body;
BodyEncoding = bodyEncoding;
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
Cookies = cookies;
RawQuery = WebUtility.UrlDecode(url.Query);
Query = ParseQuery(RawQuery);
}
private static IDictionary<string, WireMockList<string>> ParseQuery(string queryString)
{
if (string.IsNullOrEmpty(queryString))
{
return null;
}
if (queryString.StartsWith("?"))
{
queryString = queryString.Substring(1);
}
return queryString.Split('&').Aggregate(new Dictionary<string, WireMockList<string>>(),
(dict, term) =>
{
var parts = term.Split('=');
string key = parts[0];
if (!dict.ContainsKey(key))
{
dict.Add(key, new WireMockList<string>());
}
if (parts.Length == 2)
{
dict[key].Add(parts[1]);
}
return dict;
});
}
/// <summary>
/// Get a query parameter.
/// </summary>
/// <param name="key">The key.</param>
/// <returns>The query parameter.</returns>
public List<string> GetParameter(string key)
{
if (Query == null)
{
return null;
}
return Query.ContainsKey(key) ? Query[key] : null;
}
}
}

View File

@@ -20,7 +20,7 @@ namespace WireMock.ResponseBuilders
/// </summary>
public class Response : IResponseBuilder
{
private HttpClient httpClientForProxy;
private HttpClient _httpClientForProxy;
/// <summary>
/// The delay
@@ -274,35 +274,23 @@ namespace WireMock.ResponseBuilders
return this;
}
/// <summary>
/// The with transformer.
/// </summary>
/// <returns>
/// The <see cref="IResponseBuilder"/>.
/// </returns>
/// <inheritdoc cref="ITransformResponseBuilder.WithTransformer"/>
public IResponseBuilder WithTransformer()
{
UseTransformer = true;
return this;
}
/// <summary>
/// The with delay.
/// </summary>
/// <param name="delay">The TimeSpan to delay.</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
/// <inheritdoc cref="IDelayResponseBuilder.WithDelay(TimeSpan)"/>
public IResponseBuilder WithDelay(TimeSpan delay)
{
Check.Condition(delay, d => d > TimeSpan.Zero, nameof(delay));
Delay = delay;
return this;
}
/// <summary>
/// The with delay.
/// </summary>
/// <param name="milliseconds">The milliseconds to delay.</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
/// <inheritdoc cref="IDelayResponseBuilder.WithDelay(int)"/>
public IResponseBuilder WithDelay(int milliseconds)
{
return WithDelay(TimeSpan.FromMilliseconds(milliseconds));
@@ -320,7 +308,7 @@ namespace WireMock.ResponseBuilders
ProxyUrl = proxyUrl;
X509Certificate2ThumbprintOrSubjectName = clientX509Certificate2ThumbprintOrSubjectName;
httpClientForProxy = HttpClientHelper.CreateHttpClient(clientX509Certificate2ThumbprintOrSubjectName);
_httpClientForProxy = HttpClientHelper.CreateHttpClient(clientX509Certificate2ThumbprintOrSubjectName);
return this;
}
@@ -334,14 +322,17 @@ namespace WireMock.ResponseBuilders
Check.NotNull(requestMessage, nameof(requestMessage));
if (Delay != null)
{
await Task.Delay(Delay.Value);
}
if (ProxyUrl != null && httpClientForProxy != null)
if (ProxyUrl != null && _httpClientForProxy != null)
{
var requestUri = new Uri(requestMessage.Url);
var proxyUri = new Uri(ProxyUrl);
var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery);
return await HttpClientHelper.SendAsync(httpClientForProxy, requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri);
return await HttpClientHelper.SendAsync(_httpClientForProxy, requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri);
}
if (UseTransformer)

View File

@@ -79,7 +79,7 @@ namespace WireMock.Serialization
Funcs = Map(pm.Funcs)
}).ToList() : null,
Body = methodMatcher?.Methods != null && methodMatcher.Methods.Count(m => m == "get") == 1 ? null : new BodyModel
Body = methodMatcher?.Methods != null && methodMatcher.Methods.Any(m => m == "get") ? null : new BodyModel
{
Matcher = bodyMatcher != null ? Map(bodyMatcher.Matcher) : null,
Func = bodyMatcher != null ? Map(bodyMatcher.Func) : null,
@@ -115,14 +115,16 @@ namespace WireMock.Serialization
mappingModel.Response.BodyAsFile = response.ResponseMessage.BodyAsFile;
mappingModel.Response.BodyAsFileIsCached = response.ResponseMessage.BodyAsFileIsCached;
mappingModel.Response.UseTransformer = response.UseTransformer;
mappingModel.Response.BodyEncoding = response.ResponseMessage.BodyEncoding != null
? new EncodingModel
if (response.ResponseMessage.BodyEncoding != null)
{
mappingModel.Response.BodyEncoding = new EncodingModel
{
EncodingName = response.ResponseMessage.BodyEncoding.EncodingName,
CodePage = response.ResponseMessage.BodyEncoding.CodePage,
WebName = response.ResponseMessage.BodyEncoding.WebName
}
: null;
};
}
}
return mappingModel;

View File

@@ -29,6 +29,7 @@ namespace WireMock.Server
public partial class FluentMockServer
{
private static readonly string AdminMappingsFolder = Path.Combine("__admin", "mappings");
private const string ContentTypeJson = "application/json";
private const string AdminMappings = "/__admin/mappings";
private const string AdminRequests = "/__admin/requests";
private const string AdminSettings = "/__admin/settings";
@@ -86,12 +87,12 @@ namespace WireMock.Server
{
// __admin/settings
Given(Request.Create().WithPath(AdminSettings).UsingGet()).RespondWith(new DynamicResponseProvider(SettingsGet));
Given(Request.Create().WithPath(AdminSettings).UsingVerb("PUT", "POST").WithHeader("Content-Type", "application/json")).RespondWith(new DynamicResponseProvider(SettingsUpdate));
Given(Request.Create().WithPath(AdminSettings).UsingVerb("PUT", "POST").WithHeader(HttpKnownHeaderNames.ContentType, ContentTypeJson)).RespondWith(new DynamicResponseProvider(SettingsUpdate));
// __admin/mappings
Given(Request.Create().WithPath(AdminMappings).UsingGet()).RespondWith(new DynamicResponseProvider(MappingsGet));
Given(Request.Create().WithPath(AdminMappings).UsingPost().WithHeader("Content-Type", "application/json")).RespondWith(new DynamicResponseProvider(MappingsPost));
Given(Request.Create().WithPath(AdminMappings).UsingPost().WithHeader(HttpKnownHeaderNames.ContentType, ContentTypeJson)).RespondWith(new DynamicResponseProvider(MappingsPost));
Given(Request.Create().WithPath(AdminMappings).UsingDelete()).RespondWith(new DynamicResponseProvider(MappingsDelete));
// __admin/mappings/reset
@@ -99,7 +100,7 @@ namespace WireMock.Server
// __admin/mappings/{guid}
Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingGet()).RespondWith(new DynamicResponseProvider(MappingGet));
Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingPut().WithHeader("Content-Type", "application/json")).RespondWith(new DynamicResponseProvider(MappingPut));
Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingPut().WithHeader(HttpKnownHeaderNames.ContentType, ContentTypeJson)).RespondWith(new DynamicResponseProvider(MappingPut));
Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingDelete()).RespondWith(new DynamicResponseProvider(MappingDelete));
// __admin/mappings/save
@@ -130,26 +131,31 @@ namespace WireMock.Server
}
#region Proxy and Record
private HttpClient httpClientForProxy;
private HttpClient _httpClientForProxy;
private void InitProxyAndRecord(ProxyAndRecordSettings settings)
private void InitProxyAndRecord(IProxyAndRecordSettings settings)
{
httpClientForProxy = HttpClientHelper.CreateHttpClient(settings.X509Certificate2ThumbprintOrSubjectName);
_httpClientForProxy = HttpClientHelper.CreateHttpClient(settings.X509Certificate2ThumbprintOrSubjectName);
Given(Request.Create().WithPath("/*").UsingAnyVerb()).RespondWith(new ProxyAsyncResponseProvider(ProxyAndRecordAsync, settings));
}
private async Task<ResponseMessage> ProxyAndRecordAsync(RequestMessage requestMessage, ProxyAndRecordSettings settings)
private async Task<ResponseMessage> ProxyAndRecordAsync(RequestMessage requestMessage, IProxyAndRecordSettings settings)
{
var requestUri = new Uri(requestMessage.Url);
var proxyUri = new Uri(settings.Url);
var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery);
var responseMessage = await HttpClientHelper.SendAsync(httpClientForProxy, requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri);
var responseMessage = await HttpClientHelper.SendAsync(_httpClientForProxy, requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri);
if (settings.SaveMapping)
{
var mapping = ToMapping(requestMessage, responseMessage);
SaveMappingToFile(mapping);
_options.Mappings.Add(mapping);
if (settings.SaveMappingToFile)
{
SaveMappingToFile(mapping);
}
}
return responseMessage;
@@ -157,11 +163,20 @@ namespace WireMock.Server
private Mapping ToMapping(RequestMessage requestMessage, ResponseMessage responseMessage)
{
var request = (Request)Request.Create();
var request = Request.Create();
request.WithPath(requestMessage.Path);
request.UsingVerb(requestMessage.Method);
var response = (Response)Response.Create(responseMessage);
requestMessage.Query.Loop((key, value) => request.WithParam(key, value.ToArray()));
requestMessage.Headers.Loop((key, value) => request.WithHeader(key, value.ToArray()));
requestMessage.Cookies.Loop((key, value) => request.WithCookie(key, value));
if (requestMessage.Body != null)
{
request.WithBody(new ExactMatcher(requestMessage.Body));
}
var response = Response.Create(responseMessage);
return new Mapping(Guid.NewGuid(), string.Empty, request, response, 0, null, null, null);
}
@@ -472,7 +487,7 @@ namespace WireMock.Server
}
}
var result = dict.OrderBy(x => x.Value.AverageTotalScore).Select(x => x.Key);
var result = dict.OrderBy(x => x.Value.AverageTotalScore).Select(x => x.Key).Select(ToLogEntryModel);
return ToJson(result);
}
@@ -530,8 +545,9 @@ namespace WireMock.Server
{
var pathModel = JsonUtils.ParseJTokenToObject<PathModel>(requestModel.Path);
if (pathModel?.Matchers != null)
requestBuilder =
requestBuilder.WithPath(pathModel.Matchers.Select(MappingConverter.Map).ToArray());
{
requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(MappingConverter.Map).ToArray());
}
}
}
@@ -546,8 +562,9 @@ namespace WireMock.Server
{
var urlModel = JsonUtils.ParseJTokenToObject<UrlModel>(requestModel.Url);
if (urlModel?.Matchers != null)
requestBuilder =
requestBuilder.WithUrl(urlModel.Matchers.Select(MappingConverter.Map).ToArray());
{
requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(MappingConverter.Map).ToArray());
}
}
}

View File

@@ -25,12 +25,15 @@ namespace WireMock.Server
private readonly IOwinSelfHost _httpServer;
private readonly WireMockMiddlewareOptions _options = new WireMockMiddlewareOptions();
/// <summary>
/// Gets a value indicating whether this server is started.
/// </summary>
[PublicAPI]
public bool IsStarted { get; }
/// <summary>
/// Gets the ports.
/// </summary>
/// <value>
/// The ports.
/// </value>
[PublicAPI]
public List<int> Ports { get; }
@@ -59,7 +62,7 @@ namespace WireMock.Server
/// <param name="settings">The FluentMockServerSettings.</param>
/// <returns>The <see cref="FluentMockServer"/>.</returns>
[PublicAPI]
public static FluentMockServer Start(FluentMockServerSettings settings)
public static FluentMockServer Start(IFluentMockServerSettings settings)
{
Check.NotNull(settings, nameof(settings));
@@ -150,7 +153,7 @@ namespace WireMock.Server
});
}
private FluentMockServer(FluentMockServerSettings settings)
private FluentMockServer(IFluentMockServerSettings settings)
{
if (settings.Urls != null)
{
@@ -170,6 +173,8 @@ namespace WireMock.Server
#else
_httpServer = new OwinSelfHost(_options, Urls);
#endif
IsStarted = _httpServer.IsStarted;
Ports = _httpServer.Ports;
_httpServer.StartAsync();
@@ -363,18 +368,18 @@ namespace WireMock.Server
return new RespondWithAProvider(RegisterMapping, requestMatcher);
}
/// <summary>
/// The register mapping.
/// </summary>
/// <param name="mapping">
/// The mapping.
/// </param>
private void RegisterMapping(Mapping mapping)
{
// Check a mapping exists with the same GUID, if so, remove it first.
DeleteMapping(mapping.Guid);
_options.Mappings.Add(mapping);
// Check a mapping exists with the same Guid, if so, replace it.
var existingMapping = _options.Mappings.FirstOrDefault(m => m.Guid == mapping.Guid);
if (existingMapping != null)
{
_options.Mappings[_options.Mappings.IndexOf(existingMapping)] = mapping;
}
else
{
_options.Mappings.Add(mapping);
}
}
}
}

View File

@@ -6,91 +6,62 @@ namespace WireMock.Settings
/// <summary>
/// FluentMockServerSettings
/// </summary>
public class FluentMockServerSettings
public class FluentMockServerSettings : IFluentMockServerSettings
{
/// <summary>
/// Gets or sets the port.
/// </summary>
/// <inheritdoc cref="IFluentMockServerSettings.Port"/>
[PublicAPI]
public int? Port { get; set; }
/// <summary>
/// Gets or sets the use SSL.
/// </summary>
// ReSharper disable once InconsistentNaming
/// <inheritdoc cref="IFluentMockServerSettings.UseSSL"/>
[PublicAPI]
// ReSharper disable once InconsistentNaming
public bool? UseSSL { get; set; }
/// <summary>
/// Gets or sets wether to start admin interface.
/// </summary>
/// <inheritdoc cref="IFluentMockServerSettings.StartAdminInterface"/>
[PublicAPI]
public bool? StartAdminInterface { get; set; }
/// <summary>
/// Gets or sets if the static mappings should be read at startup.
/// </summary>
/// <inheritdoc cref="IFluentMockServerSettings.ReadStaticMappings"/>
[PublicAPI]
public bool? ReadStaticMappings { get; set; }
/// <summary>
/// Gets or sets if the server should record and save requests and responses.
/// </summary>
/// <value>true/false</value>
/// <inheritdoc cref="IFluentMockServerSettings.ProxyAndRecordSettings"/>
[PublicAPI]
public ProxyAndRecordSettings ProxyAndRecordSettings { get; set; }
public IProxyAndRecordSettings ProxyAndRecordSettings { get; set; }
/// <summary>
/// Gets or sets the urls.
/// </summary>
/// <inheritdoc cref="IFluentMockServerSettings.Urls"/>
[PublicAPI]
public string[] Urls { get; set; }
/// <summary>
/// StartTimeout
/// </summary>
/// <inheritdoc cref="IFluentMockServerSettings.StartTimeout"/>
[PublicAPI]
public int StartTimeout { get; set; } = 10000;
/// <summary>
/// Allow Partial Mapping (default set to false).
/// </summary>
/// <inheritdoc cref="IFluentMockServerSettings.AllowPartialMapping"/>
[PublicAPI]
public bool? AllowPartialMapping { get; set; }
/// <summary>
/// The username needed for __admin access.
/// </summary>
/// <inheritdoc cref="IFluentMockServerSettings.AdminUsername"/>
[PublicAPI]
public string AdminUsername { get; set; }
/// <summary>
/// The password needed for __admin access.
/// </summary>
/// <inheritdoc cref="IFluentMockServerSettings.AdminPassword"/>
[PublicAPI]
public string AdminPassword { get; set; }
/// <summary>
/// The RequestLog expiration in hours (optional).
/// </summary>
/// <inheritdoc cref="IFluentMockServerSettings.RequestLogExpirationDuration"/>
[PublicAPI]
public int? RequestLogExpirationDuration { get; set; }
/// <summary>
/// The MaxRequestLog count (optional).
/// </summary>
/// <inheritdoc cref="IFluentMockServerSettings.MaxRequestLogCount"/>
[PublicAPI]
public int? MaxRequestLogCount { get; set; }
/// <summary>
/// Action which is called (with the IAppBuilder or IApplicationBuilder) before the internal WireMockMiddleware is initialized. [Optional]
/// </summary>
/// <inheritdoc cref="IFluentMockServerSettings.PreWireMockMiddlewareInit"/>
[PublicAPI]
public Action<object> PreWireMockMiddlewareInit { get; set; }
/// <summary>
/// Action which is called (with the IAppBuilder or IApplicationBuilder) after the internal WireMockMiddleware is initialized. [Optional]
/// </summary>
/// <inheritdoc cref="IFluentMockServerSettings.PostWireMockMiddlewareInit"/>
[PublicAPI]
public Action<object> PostWireMockMiddlewareInit { get; set; }
}

View File

@@ -0,0 +1,81 @@
using System;
namespace WireMock.Settings
{
/// <summary>
/// IFluentMockServerSettings
/// </summary>
public interface IFluentMockServerSettings
{
/// <summary>
/// Gets or sets the port.
/// </summary>
int? Port { get; set; }
/// <summary>
/// Gets or sets the use SSL.
/// </summary>
// ReSharper disable once InconsistentNaming
bool? UseSSL { get; set; }
/// <summary>
/// Gets or sets wether to start admin interface.
/// </summary>
bool? StartAdminInterface { get; set; }
/// <summary>
/// Gets or sets if the static mappings should be read at startup.
/// </summary>
bool? ReadStaticMappings { get; set; }
/// <summary>
/// Gets or sets if the proxy and record settings.
/// </summary>
IProxyAndRecordSettings ProxyAndRecordSettings { get; set; }
/// <summary>
/// Gets or sets the urls.
/// </summary>
string[] Urls { get; set; }
/// <summary>
/// StartTimeout
/// </summary>
int StartTimeout { get; set; }
/// <summary>
/// Allow Partial Mapping (default set to false).
/// </summary>
bool? AllowPartialMapping { get; set; }
/// <summary>
/// The username needed for __admin access.
/// </summary>
string AdminUsername { get; set; }
/// <summary>
/// The password needed for __admin access.
/// </summary>
string AdminPassword { get; set; }
/// <summary>
/// The RequestLog expiration in hours (optional).
/// </summary>
int? RequestLogExpirationDuration { get; set; }
/// <summary>
/// The MaxRequestLog count (optional).
/// </summary>
int? MaxRequestLogCount { get; set; }
/// <summary>
/// Action which is called (with the IAppBuilder or IApplicationBuilder) before the internal WireMockMiddleware is initialized. [Optional]
/// </summary>
Action<object> PreWireMockMiddlewareInit { get; set; }
/// <summary>
/// Action which is called (with the IAppBuilder or IApplicationBuilder) after the internal WireMockMiddleware is initialized. [Optional]
/// </summary>
Action<object> PostWireMockMiddlewareInit { get; set; }
}
}

View File

@@ -0,0 +1,28 @@
namespace WireMock.Settings
{
/// <summary>
/// IRecordAndSaveSettings
/// </summary>
public interface IProxyAndRecordSettings
{
/// <summary>
/// The URL to proxy.
/// </summary>
string Url { get; set; }
/// <summary>
/// Save the mapping for each request/response to the internal Mappings.
/// </summary>
bool SaveMapping { get; set; }
/// <summary>
/// Save the mapping for each request/response to also file. (Note that SaveMapping must also be set to true.)
/// </summary>
bool SaveMappingToFile { get; set; }
/// <summary>
/// The clientCertificate thumbprint or subject name fragment to use. Example thumbprint : "D2DBF135A8D06ACCD0E1FAD9BFB28678DF7A9818". Example subject name: "www.google.com""
/// </summary>
string X509Certificate2ThumbprintOrSubjectName { get; set; }
}
}

View File

@@ -1,23 +1,26 @@
namespace WireMock.Settings
using JetBrains.Annotations;
namespace WireMock.Settings
{
/// <summary>
/// RecordAndSaveSettings
/// </summary>
public class ProxyAndRecordSettings
public class ProxyAndRecordSettings : IProxyAndRecordSettings
{
/// <summary>
/// The URL to proxy.
/// </summary>
/// <inheritdoc cref="IProxyAndRecordSettings.Url"/>
[PublicAPI]
public string Url { get; set; }
/// <summary>
/// Save the mapping for each request/response.
/// </summary>
/// <inheritdoc cref="IProxyAndRecordSettings.SaveMapping"/>
[PublicAPI]
public bool SaveMapping { get; set; } = true;
/// <summary>
/// The clientCertificate thumbprint or subject name fragment to use. Example thumbprint : "D2DBF135A8D06ACCD0E1FAD9BFB28678DF7A9818". Example subject name: "www.google.com""
/// </summary>
/// <inheritdoc cref="IProxyAndRecordSettings.SaveMappingToFile"/>
[PublicAPI]
public bool SaveMappingToFile { get; set; } = true;
/// <inheritdoc cref="IProxyAndRecordSettings.X509Certificate2ThumbprintOrSubjectName"/>
[PublicAPI]
public string X509Certificate2ThumbprintOrSubjectName { get; set; }
}
}

View File

@@ -0,0 +1,77 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace WireMock.Util
{
/// <summary>
/// A special Collection that overrides methods of <see cref="ObservableCollection{T}"/> to make them thread safe
/// </summary>
/// <typeparam name="T">The type of elements in the collection.</typeparam>
/// <inheritdoc cref="ObservableCollection{T}" />
public class ConcurentObservableCollection<T> : ObservableCollection<T>
{
private readonly object _lockObject = new object();
/// <summary>
/// Initializes a new instance of the <see cref="T:WireMock.Util.ConcurentObservableCollection`1" /> class.
/// </summary>
public ConcurentObservableCollection() { }
/// <summary>
/// Initializes a new instance of the <see cref="ConcurentObservableCollection{T}"/> class that contains elements copied from the specified list.
/// </summary>
/// <param name="list">The list from which the elements are copied.</param>
public ConcurentObservableCollection(List<T> list) : base(list) { }
/// <summary>
/// Initializes a new instance of the <see cref="ConcurentObservableCollection{T}"/> class that contains elements copied from the specified collection.
/// </summary>
/// <param name="collection">The collection from which the elements are copied.</param>
public ConcurentObservableCollection(IEnumerable<T> collection) : base(collection) { }
/// <inheritdoc cref="ObservableCollection{T}.ClearItems"/>
protected override void ClearItems()
{
lock (_lockObject)
{
base.ClearItems();
}
}
/// <inheritdoc cref="ObservableCollection{T}.RemoveItem"/>
protected override void RemoveItem(int index)
{
lock (_lockObject)
{
base.RemoveItem(index);
}
}
/// <inheritdoc cref="ObservableCollection{T}.InsertItem"/>
protected override void InsertItem(int index, T item)
{
lock (_lockObject)
{
base.InsertItem(index, item);
}
}
/// <inheritdoc cref="ObservableCollection{T}.SetItem"/>
protected override void SetItem(int index, T item)
{
lock (_lockObject)
{
base.SetItem(index, item);
}
}
/// <inheritdoc cref="ObservableCollection{T}.MoveItem"/>
protected override void MoveItem(int oldIndex, int newIndex)
{
lock (_lockObject)
{
base.MoveItem(oldIndex, newIndex);
}
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using WireMock.Validation;
namespace WireMock.Util
{
/// <summary>
/// Some IDictionary Extensions
/// </summary>
public static class DictionaryExtensions
{
/// <summary>
/// Loops the dictionary and executes the specified action.
/// </summary>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <param name="dictionary">The dictionary to loop (can be null).</param>
/// <param name="action">The action.</param>
public static void Loop<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, [NotNull] Action<TKey, TValue> action)
{
Check.NotNull(action, nameof(action));
if (dictionary != null)
{
foreach (var entry in dictionary)
{
action(entry.Key, entry.Value);
}
}
}
}
}

View File

@@ -74,8 +74,7 @@ namespace WireMock.Util
public void RemoveLock(string name)
{
ReaderWriterLockSlim o;
_lockDict.TryRemove(name, out o);
_lockDict.TryRemove(name, out _);
}
}
}

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<Description>Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.</Description>
<AssemblyTitle>WireMock.Net</AssemblyTitle>
<Version>1.0.2.6</Version>
<Version>1.0.2.13</Version>
<Authors>Alexandre Victoor;Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -17,9 +17,11 @@
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/WireMock-Net/WireMock.Net</RepositoryUrl>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<DebugType>portable</DebugType>
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
<RootNamespace>WireMock</RootNamespace>
<DebugType>full</DebugType>
<IncludeSource>True</IncludeSource>
<IncludeSymbols>True</IncludeSymbols>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' or '$(TargetFramework)' == 'netstandard2.0'">
@@ -32,9 +34,9 @@
</PackageReference>
<PackageReference Include="Handlebars.Net" Version="1.9.0" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.1" />
<PackageReference Include="SimMetrics.Net" Version="1.0.3" />
<PackageReference Include="System.Net.Http" Version="4.3.2" />
<PackageReference Include="RestEase" Version="1.4.2" />
<PackageReference Include="SimMetrics.Net" Version="1.0.4" />
<PackageReference Include="System.Net.Http" Version="4.3.3" />
<PackageReference Include="RestEase" Version="1.4.4" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
@@ -49,7 +51,7 @@
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.5" />
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
<PackageReference Include="System.Xml.XPath.XmlDocument" Version="4.3.0" />
</ItemGroup>

View File

@@ -0,0 +1,48 @@
using System.Linq;
using System.Threading.Tasks;
using NFluent;
using RestEase;
using WireMock.Admin.Mappings;
using WireMock.Client;
using WireMock.Server;
using Xunit;
namespace WireMock.Net.Tests
{
public class ClientTests
{
[Fact]
public async Task Client_IFluentMockServerAdmin_PostMappingAsync()
{
// Assign
var server = FluentMockServer.StartWithAdminInterface();
var api = RestClient.For<IFluentMockServerAdmin>(server.Urls[0]);
// Act
var model = new MappingModel
{
Request = new RequestModel
{
Path = "/1"
},
Response = new ResponseModel
{
Body = "txt",
StatusCode = 200
},
Priority = 500,
Title = "test"
};
string result = await api.PostMappingAsync(model);
// Assert
Check.That(result).IsNotNull();
var mapping = server.Mappings.Single(m => m.Priority == 500);
Check.That(mapping).IsNotNull();
Check.That(mapping.Title).Equals("test");
server.Stop();
}
}
}

View File

@@ -0,0 +1,64 @@
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using NFluent;
using RestEase;
using WireMock.Admin.Mappings;
using WireMock.Client;
using WireMock.Server;
using WireMock.Settings;
using Xunit;
namespace WireMock.Net.Tests
{
public class FluentMockServerAdminRestClientTests : IDisposable
{
public void Dispose()
{
_server?.Stop();
}
private FluentMockServer _server;
[Fact]
public async Task IFluentMockServerAdmin_FindRequestsAsync()
{
// given
_server = FluentMockServer.Start(new FluentMockServerSettings { StartAdminInterface = true });
var serverUrl = "http://localhost:" + _server.Ports[0];
await new HttpClient().GetAsync(serverUrl + "/foo");
var api = RestClient.For<IFluentMockServerAdmin>(serverUrl);
// when
var requests = await api.FindRequestsAsync(new RequestModel { Methods = new[] { "get" } });
// then
Check.That(requests).HasSize(1);
var requestLogged = requests.First();
Check.That(requestLogged.Request.Method).IsEqualTo("get");
Check.That(requestLogged.Request.Body).IsNull();
Check.That(requestLogged.Request.Path).IsEqualTo("/foo");
}
[Fact]
public async Task IFluentMockServerAdmin_GetRequestsAsync()
{
// given
_server = FluentMockServer.Start(new FluentMockServerSettings { StartAdminInterface = true });
var serverUrl = "http://localhost:" + _server.Ports[0];
await new HttpClient().GetAsync(serverUrl + "/foo");
var api = RestClient.For<IFluentMockServerAdmin>(serverUrl);
// when
var requests = await api.GetRequestsAsync();
// then
Check.That(requests).HasSize(1);
var requestLogged = requests.First();
Check.That(requestLogged.Request.Method).IsEqualTo("get");
Check.That(requestLogged.Request.Body).IsNull();
Check.That(requestLogged.Request.Path).IsEqualTo("/foo");
}
}
}

View File

@@ -63,6 +63,37 @@ namespace WireMock.Net.Tests
Check.That(receivedRequest.Headers["Content-Type"]).ContainsExactly("text/plain");
}
[Fact]
public async Task FluentMockServer_Should_preserve_content_header_in_proxied_request_with_empty_content()
{
// given
_serverForProxyForwarding = FluentMockServer.Start();
_serverForProxyForwarding
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create());
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy(_serverForProxyForwarding.Urls[0]));
// when
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri(_server.Urls[0]),
Content = new StringContent("")
};
requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
await new HttpClient().SendAsync(requestMessage);
// then
var receivedRequest = _serverForProxyForwarding.LogEntries.First().RequestMessage;
Check.That(receivedRequest.Body).IsEqualTo("");
Check.That(receivedRequest.Headers).ContainsKey("Content-Type");
Check.That(receivedRequest.Headers["Content-Type"]).ContainsExactly("text/plain");
}
[Fact]
public async Task FluentMockServer_Should_preserve_content_header_in_proxied_response()
{

View File

@@ -117,20 +117,24 @@ namespace WireMock.Net.Tests
var guid = Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05");
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/1").UsingGet())
var response1 = Response.Create().WithStatusCode(500);
_server.Given(Request.Create().UsingGet())
.WithGuid(guid)
.RespondWith(Response.Create().WithStatusCode(500));
.RespondWith(response1);
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(1);
Check.That(mappings.First().Guid).Equals(guid);
var mappings1 = _server.Mappings.ToArray();
Check.That(mappings1).HasSize(1);
Check.That(mappings1.First().Guid).Equals(guid);
var response2 = Response.Create().WithStatusCode(400);
_server.Given(Request.Create().WithPath("/2").UsingGet())
.WithGuid(guid)
.RespondWith(Response.Create().WithStatusCode(500));
.RespondWith(response2);
Check.That(mappings).HasSize(1);
Check.That(mappings.First().Guid).Equals(guid);
var mappings2 = _server.Mappings.ToArray();
Check.That(mappings2).HasSize(1);
Check.That(mappings2.First().Guid).Equals(guid);
Check.That(mappings2.First().Provider).Equals(response2);
}
[Fact]
@@ -175,6 +179,34 @@ namespace WireMock.Net.Tests
Check.That(requestLogged.RequestMessage.BodyAsBytes).IsNull();
}
[Fact]
public async Task FluentMockServer_Should_respond_to_request_methodPatch()
{
// given
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/foo").UsingVerb("patch"))
.RespondWith(Response.Create().WithBody("hello patch"));
// when
var msg = new HttpRequestMessage(new HttpMethod("patch"), new Uri("http://localhost:" + _server.Ports[0] + "/foo"))
{
Content = new StringContent("{\"data\": {\"attr\":\"value\"}}")
};
var response = await new HttpClient().SendAsync(msg);
// then
Check.That(response.StatusCode).IsEqualTo(HttpStatusCode.OK);
var responseBody = await response.Content.ReadAsStringAsync();
Check.That(responseBody).IsEqualTo("hello patch");
Check.That(_server.LogEntries).HasSize(1);
var requestLogged = _server.LogEntries.First();
Check.That(requestLogged.RequestMessage.Method).IsEqualTo("patch");
Check.That(requestLogged.RequestMessage.Body).IsNotNull();
Check.That(requestLogged.RequestMessage.Body).IsEqualTo("{\"data\": {\"attr\":\"value\"}}");
}
[Fact]
public async Task FluentMockServer_Should_respond_to_request_bodyAsString()
{

View File

@@ -1,5 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using NFluent;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
@@ -8,7 +13,7 @@ using Xunit;
namespace WireMock.Net.Tests
{
public class ObservableLogEntriesTest: IDisposable
public class ObservableLogEntriesTest : IDisposable
{
private FluentMockServer _server;
@@ -35,6 +40,42 @@ namespace WireMock.Net.Tests
Check.That(count).Equals(1);
}
[Fact]
public async Task ParallelTest()
{
var expectedCount = 100;
// Assign
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/foo")
.UsingGet())
.RespondWith(Response.Create()
.WithDelay(6)
.WithSuccess());
int count = 0;
_server.LogEntriesChanged += (sender, args) => count++;
var http = new HttpClient();
// Act
var listOfTasks = new List<Task<HttpResponseMessage>>();
for (var i = 0; i < expectedCount; i++)
{
Thread.Sleep(3);
listOfTasks.Add(http.GetAsync(_server.Urls[0] + $"/foo"));
}
var responses = await Task.WhenAll(listOfTasks);
var countResponsesWithStatusNotOk = responses.Where(r => r.StatusCode != HttpStatusCode.OK).Count();
// Assert
Check.That(countResponsesWithStatusNotOk).Equals(0);
Check.That(count).Equals(expectedCount);
}
public void Dispose()
{
_server?.Dispose();

View File

@@ -0,0 +1,113 @@
using System;
using System.Text;
using NFluent;
using Xunit;
using WireMock.RequestBuilders;
using WireMock.Matchers.Request;
namespace WireMock.Net.Tests
{
//[TestFixture]
public partial class RequestTests
{
[Fact]
public void Should_specify_requests_matching_given_path_and_method_delete()
{
// given
var spec = Request.Create().WithPath("/foo").UsingDelete();
// when
string bodyAsString = "whatever";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "Delete", ClientIp, body, bodyAsString, Encoding.UTF8);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Should_specify_requests_matching_given_path_and_method_get()
{
// given
var spec = Request.Create().WithPath("/foo").UsingGet();
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "GET", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Should_specify_requests_matching_given_path_and_method_head()
{
// given
var spec = Request.Create().WithPath("/foo").UsingHead();
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "HEAD", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Should_specify_requests_matching_given_path_and_method_post()
{
// given
var spec = Request.Create().WithPath("/foo").UsingPost();
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Should_specify_requests_matching_given_path_and_method_put()
{
// given
var spec = Request.Create().WithPath("/foo").UsingPut();
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Should_specify_requests_matching_given_path_and_method_patch()
{
// given
var spec = Request.Create().WithPath("/foo").UsingPatch();
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "PATCH", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Should_exclude_requests_matching_given_path_but_not_http_method()
{
// given
var spec = Request.Create().WithPath("/foo").UsingPut();
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "HEAD", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using NFluent;
using WireMock.Matchers.Request;
using WireMock.RequestBuilders;
using Xunit;
namespace WireMock.Net.Tests
{
public partial class RequestTests
{
[Fact]
public void Should_specify_requests_matching_given_url_wildcard()
{
// given
var spec = Request.Create().WithUrl("*/foo");
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "blabla", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Should_specify_requests_matching_given_url_exact()
{
// given
var spec = Request.Create().WithUrl("http://localhost/foo");
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "blabla", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
}
}

View File

@@ -83,106 +83,6 @@ namespace WireMock.Net.Tests
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
}
[Fact]
public void Should_specify_requests_matching_given_url()
{
// given
var spec = Request.Create().WithUrl("*/foo");
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "blabla", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Should_specify_requests_matching_given_path_and_method_put()
{
// given
var spec = Request.Create().WithPath("/foo").UsingPut();
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Should_specify_requests_matching_given_path_and_method_post()
{
// given
var spec = Request.Create().WithPath("/foo").UsingPost();
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Should_specify_requests_matching_given_path_and_method_get()
{
// given
var spec = Request.Create().WithPath("/foo").UsingGet();
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "GET", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Should_specify_requests_matching_given_path_and_method_delete()
{
// given
var spec = Request.Create().WithPath("/foo").UsingDelete();
// when
string bodyAsString = "whatever";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "Delete", ClientIp, body, bodyAsString, Encoding.UTF8);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Should_specify_requests_matching_given_path_and_method_head()
{
// given
var spec = Request.Create().WithPath("/foo").UsingHead();
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "HEAD", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}
[Fact]
public void Should_exclude_requests_matching_given_path_but_not_http_method()
{
// given
var spec = Request.Create().WithPath("/foo").UsingPut();
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "HEAD", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
}
[Fact]
public void Should_exclude_requests_matching_given_http_method_but_not_url()
{
@@ -206,7 +106,7 @@ namespace WireMock.Net.Tests
// when
string bodyAsString = "whatever";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8, new Dictionary<string, string[]> { { "X-toto", new [] { "tata" } } });
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8, new Dictionary<string, string[]> { { "X-toto", new[] { "tata" } } });
// then
var requestMatchResult = new RequestMatchResult();

View File

@@ -86,5 +86,24 @@ namespace WireMock.Net.Tests
Check.That(responseMessage.Headers["x"]).Contains("text/plain");
Check.That(responseMessage.Headers["x"]).Contains("http://localhost/foo");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_Origin_Port_Protocol_Host()
{
// given
string bodyAsString = "abc";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost:1234"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8);
var response = Response.Create()
.WithBody("test {{request.origin}} {{request.port}} {{request.protocol}} {{request.host}}")
.WithTransformer();
// act
var responseMessage = await response.ProvideResponseAsync(request);
// then
Check.That(responseMessage.Body).Equals("test http://localhost:1234 1234 http localhost");
}
}
}

View File

@@ -16,12 +16,12 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="Microsoft.Owin.Host.HttpListener" Version="3.1.0" />
<PackageReference Include="Moq" Version="4.7.99" />
<PackageReference Include="Moq" Version="4.8.1" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="NFluent" Version="2.0.0" />
<PackageReference Include="OpenCover" Version="4.6.519" />
<PackageReference Include="ReportGenerator" Version="2.5.11" />
<PackageReference Include="SimMetrics.Net" Version="1.0.3" />
<PackageReference Include="SimMetrics.Net" Version="1.0.4" />
<PackageReference Include="System.Threading" Version="4.3.0" />
<PackageReference Include="xunit" Version="2.3.0-beta1-build3642" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0-beta1-build1309" />