Compare commits

...

38 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
Stef Heyenrath
d83f308591 1.0.2.6 2017-10-30 08:49:16 +01:00
Oleksandr Liakhevych
c8c9ab99c5 Fix proxy headers handling (#60)
* Fix proxy headers handling

* Small refactor and moved proxy tests to new test-file.
2017-10-28 18:59:34 +02:00
Oleksandr Liakhevych
d134684bcb Add ability to provide multiple values for headers in response (#59)
* Add ability to provide multiple values for headers

* Updated json model
2017-10-27 21:49:03 +02:00
Stef Heyenrath
a96b7bca1e WithBodyFromFile (relative) 2017-10-27 12:12:13 +02:00
Stef Heyenrath
cbe6a0a2b4 WithBodyFromFile (#56) 2017-10-25 21:33:57 +02:00
Stef Heyenrath
15370a89ca 1.0.2.5 2017-10-24 18:12:39 +02:00
Stef Heyenrath
656f7f5432 HttpClientHelper : BodyAsBytes 2017-10-23 20:56:01 +02:00
deeptowncitizen
bcdc3d646a fix header (#55) 2017-10-23 20:25:06 +02:00
Stef Heyenrath
10350fac04 Merge branch 'appbuilder' 2017-10-18 20:19:03 +02:00
Stef Heyenrath
37244d5c2f PreWireMockMiddlewareInit / PostWireMockMiddlewareInit 2017-10-17 20:47:19 +02:00
Stef Heyenrath
07f03997c0 Fix issues with Bytes for Response 2017-10-14 10:48:58 +02:00
Stef Heyenrath
7c289d44a7 Update client interface for Scenarios 2017-10-10 18:21:22 +02:00
81 changed files with 2791 additions and 1307 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) [![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) [![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) [![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/StefH/WireMock.Net.svg)](https://github.com/StefH/WireMock.Net/issues) [![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/StefH/WireMock.Net.svg)](https://github.com/StefH/WireMock.Net/stargazers) [![GitHub stars](https://img.shields.io/github/stars/WireMock-Net/WireMock.Net.svg)](https://github.com/WireMock-Net/WireMock.Net/stargazers)
| Name | NuGet | | Name | NuGet |
| ---- | ----- | | ---- | ----- |
@@ -28,7 +28,7 @@ To build you need:
## Stubbing ## 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 ## Using WireMock in UnitTest framework
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

View File

@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.26430.13 VisualStudioVersion = 15.0.27130.2020
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EF242EDF-7133-4277-9A0C-18744DE08707}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EF242EDF-7133-4277-9A0C-18744DE08707}"
EndProject EndProject
@@ -21,11 +21,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net", "src\WireMoc
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Tests", "test\WireMock.Net.Tests\WireMock.Net.Tests.csproj", "{31DC2EF8-C3FE-467D-84BE-FB5D956E612E}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Tests", "test\WireMock.Net.Tests\WireMock.Net.Tests.csproj", "{31DC2EF8-C3FE-467D-84BE-FB5D956E612E}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Console.NETCoreApp", "examples\WireMock.Net.Console.NETCoreApp\WireMock.Net.Console.NETCoreApp.csproj", "{FE281639-B014-4C8A-96FA-141164A74713}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.NETCoreApp", "examples\WireMock.Net.Console.NETCoreApp\WireMock.Net.Console.NETCoreApp.csproj", "{FE281639-B014-4C8A-96FA-141164A74713}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.Record.NETCoreApp", "examples\WireMock.Net.Console.Record.NETCoreApp\WireMock.Net.Console.Record.NETCoreApp.csproj", "{1995E414-F197-4AB4-90C2-68D806B5AF59}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.Record.NETCoreApp", "examples\WireMock.Net.Console.Record.NETCoreApp\WireMock.Net.Console.Record.NETCoreApp.csproj", "{1995E414-F197-4AB4-90C2-68D806B5AF59}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Client", "examples\WireMock.Net.Client\WireMock.Net.Client.csproj", "{058D4B6C-C03E-49D0-91DB-A535B058FA0D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Client", "examples\WireMock.Net.Client\WireMock.Net.Client.csproj", "{058D4B6C-C03E-49D0-91DB-A535B058FA0D}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.StandAlone", "src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj", "{B6269AAC-170A-43D5-8B9A-579DED3D9A95}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.StandAlone", "src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj", "{B6269AAC-170A-43D5-8B9A-579DED3D9A95}"
EndProject EndProject
@@ -36,6 +36,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.StandAlone.Net
{B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {B6269AAC-170A-43D5-8B9A-579DED3D9A95} {B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {B6269AAC-170A-43D5-8B9A-579DED3D9A95}
EndProjectSection EndProjectSection
EndProject EndProject
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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -74,6 +78,14 @@ Global
{668F689E-57B4-422E-8846-C0FF643CA999}.Debug|Any CPU.Build.0 = Debug|Any CPU {668F689E-57B4-422E-8846-C0FF643CA999}.Debug|Any CPU.Build.0 = Debug|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA999}.Release|Any CPU.ActiveCfg = Release|Any CPU {668F689E-57B4-422E-8846-C0FF643CA999}.Release|Any CPU.ActiveCfg = Release|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA999}.Release|Any CPU.Build.0 = Release|Any CPU {668F689E-57B4-422E-8846-C0FF643CA999}.Release|Any CPU.Build.0 = Release|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA268}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -87,5 +99,10 @@ Global
{B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {EF242EDF-7133-4277-9A0C-18744DE08707} {B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {EF242EDF-7133-4277-9A0C-18744DE08707}
{10E16614-61CA-48D8-8BDD-664C13913DED} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A} {10E16614-61CA-48D8-8BDD-664C13913DED} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{668F689E-57B4-422E-8846-C0FF643CA999} = {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}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@@ -21,7 +21,6 @@ environment:
before_build: before_build:
- dotnet restore .\src\WireMock.Net\WireMock.Net.csproj - dotnet restore .\src\WireMock.Net\WireMock.Net.csproj
- dotnet restore .\src\WireMock.Net.Standalone\WireMock.Net.Standalone.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_script:
# build WireMock.Net # build WireMock.Net
@@ -39,6 +38,6 @@ test_script:
- nuget.exe install coveralls.net -ExcludeVersion - nuget.exe install coveralls.net -ExcludeVersion
- pip install codecov - 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" - codecov -f "coverage.xml"
- coveralls.net\tools\csmacnz.Coveralls.exe --opencover -i .\coverage.xml - coveralls.net\tools\csmacnz.Coveralls.exe --opencover -i .\coverage.xml

View File

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

View File

@@ -18,9 +18,6 @@
<Content Include="__admin\mappings\11111110-a633-40e8-a244-5cb80bc0ab66.json"> <Content Include="__admin\mappings\11111110-a633-40e8-a244-5cb80bc0ab66.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Include="__admin\mappings\826aff7c-6208-4a3c-923d-575248907db4.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -28,4 +25,13 @@
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Update="__admin\mappings\791a3f31-6946-4ce7-8e6f-0237c7443275.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\791a3f31-6946-4ce7-8e6f-0237c7443275.json">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project> </Project>

View File

@@ -14,8 +14,9 @@
}, },
"Response": { "Response": {
"BodyAsJson": { "body": "static mapping" }, "BodyAsJson": { "body": "static mapping" },
"Headers": { "Headers": {
"Content-Type": "application/json" "Content-Type": "application/json",
} "Test-X": [ "test 1", "test 2" ]
}
} }
} }

View File

@@ -0,0 +1,36 @@
{
"Guid": "791a3f31-6946-4ce7-8e6f-0237c7443275",
"Title": "",
"Priority": 0,
"Request": {
"Path": {
"Matchers": [
{
"Name": "WildcardMatcher",
"Pattern": "/proxy-google-test-post"
}
]
},
"Methods": [
"post"
],
"Body": {}
},
"Response": {
"StatusCode": 404,
"Body": "<!DOCTYPE html>\n<html lang=en>\n <meta charset=utf-8>\n <meta name=viewport content=\"initial-scale=1, minimum-scale=1, width=device-width\">\n <title>Error 404 (Not Found)!!1</title>\n <style>\n *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}\n </style>\n <a href=//www.google.com/><span id=logo aria-label=Google></span></a>\n <p><b>404.</b> <ins>Thats an error.</ins>\n <p>The requested URL <code>/proxy-google-test-post</code> was not found on this server. <ins>Thats all we know.</ins>\n",
"BodyAsBytes": "PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ZW4+CiAgPG1ldGEgY2hhcnNldD11dGYtOD4KICA8bWV0YSBuYW1lPXZpZXdwb3J0IGNvbnRlbnQ9ImluaXRpYWwtc2NhbGU9MSwgbWluaW11bS1zY2FsZT0xLCB3aWR0aD1kZXZpY2Utd2lkdGgiPgogIDx0aXRsZT5FcnJvciA0MDQgKE5vdCBGb3VuZCkhITE8L3RpdGxlPgogIDxzdHlsZT4KICAgICp7bWFyZ2luOjA7cGFkZGluZzowfWh0bWwsY29kZXtmb250OjE1cHgvMjJweCBhcmlhbCxzYW5zLXNlcmlmfWh0bWx7YmFja2dyb3VuZDojZmZmO2NvbG9yOiMyMjI7cGFkZGluZzoxNXB4fWJvZHl7bWFyZ2luOjclIGF1dG8gMDttYXgtd2lkdGg6MzkwcHg7bWluLWhlaWdodDoxODBweDtwYWRkaW5nOjMwcHggMCAxNXB4fSogPiBib2R5e2JhY2tncm91bmQ6dXJsKC8vd3d3Lmdvb2dsZS5jb20vaW1hZ2VzL2Vycm9ycy9yb2JvdC5wbmcpIDEwMCUgNXB4IG5vLXJlcGVhdDtwYWRkaW5nLXJpZ2h0OjIwNXB4fXB7bWFyZ2luOjExcHggMCAyMnB4O292ZXJmbG93OmhpZGRlbn1pbnN7Y29sb3I6Izc3Nzt0ZXh0LWRlY29yYXRpb246bm9uZX1hIGltZ3tib3JkZXI6MH1AbWVkaWEgc2NyZWVuIGFuZCAobWF4LXdpZHRoOjc3MnB4KXtib2R5e2JhY2tncm91bmQ6bm9uZTttYXJnaW4tdG9wOjA7bWF4LXdpZHRoOm5vbmU7cGFkZGluZy1yaWdodDowfX0jbG9nb3tiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9icmFuZGluZy9nb29nbGVsb2dvLzF4L2dvb2dsZWxvZ29fY29sb3JfMTUweDU0ZHAucG5nKSBuby1yZXBlYXQ7bWFyZ2luLWxlZnQ6LTVweH1AbWVkaWEgb25seSBzY3JlZW4gYW5kIChtaW4tcmVzb2x1dGlvbjoxOTJkcGkpeyNsb2dve2JhY2tncm91bmQ6dXJsKC8vd3d3Lmdvb2dsZS5jb20vaW1hZ2VzL2JyYW5kaW5nL2dvb2dsZWxvZ28vMngvZ29vZ2xlbG9nb19jb2xvcl8xNTB4NTRkcC5wbmcpIG5vLXJlcGVhdCAwJSAwJS8xMDAlIDEwMCU7LW1vei1ib3JkZXItaW1hZ2U6dXJsKC8vd3d3Lmdvb2dsZS5jb20vaW1hZ2VzL2JyYW5kaW5nL2dvb2dsZWxvZ28vMngvZ29vZ2xlbG9nb19jb2xvcl8xNTB4NTRkcC5wbmcpIDB9fUBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKC13ZWJraXQtbWluLWRldmljZS1waXhlbC1yYXRpbzoyKXsjbG9nb3tiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9icmFuZGluZy9nb29nbGVsb2dvLzJ4L2dvb2dsZWxvZ29fY29sb3JfMTUweDU0ZHAucG5nKSBuby1yZXBlYXQ7LXdlYmtpdC1iYWNrZ3JvdW5kLXNpemU6MTAwJSAxMDAlfX0jbG9nb3tkaXNwbGF5OmlubGluZS1ibG9jaztoZWlnaHQ6NTRweDt3aWR0aDoxNTBweH0KICA8L3N0eWxlPgogIDxhIGhyZWY9Ly93d3cuZ29vZ2xlLmNvbS8+PHNwYW4gaWQ9bG9nbyBhcmlhLWxhYmVsPUdvb2dsZT48L3NwYW4+PC9hPgogIDxwPjxiPjQwNC48L2I+IDxpbnM+VGhhdOKAmXMgYW4gZXJyb3IuPC9pbnM+CiAgPHA+VGhlIHJlcXVlc3RlZCBVUkwgPGNvZGU+L3Byb3h5LWdvb2dsZS10ZXN0LXBvc3Q8L2NvZGU+IHdhcyBub3QgZm91bmQgb24gdGhpcyBzZXJ2ZXIuICA8aW5zPlRoYXTigJlzIGFsbCB3ZSBrbm93LjwvaW5zPgo=",
"BodyEncoding": {
"CodePage": 65001,
"EncodingName": "Unicode (UTF-8)",
"WebName": "utf-8"
},
"UseTransformer": false,
"Headers": {
"Date": "Wed, 25 Oct 2017 18:57:40 GMT",
"Alt-Svc": "quic=\":443\"; ma=2592000; v=\"39,38,37,35\"",
"Referrer-Policy": "no-referrer",
"Connection": "close"
}
}
}

View File

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

View File

@@ -15,4 +15,8 @@
<PackageReference Include="Newtonsoft.Json" Version="10.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="10.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="__admin\mappings\" />
</ItemGroup>
</Project> </Project>

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.RequestBuilders; using WireMock.RequestBuilders;
@@ -21,13 +20,74 @@ namespace WireMock.Net.ConsoleApplication
{ {
Urls = new[] { url1, url2, url3 }, Urls = new[] { url1, url2, url3 },
StartAdminInterface = true, StartAdminInterface = true,
ReadStaticMappings = true ReadStaticMappings = true,
//ProxyAndRecordSettings = new ProxyAndRecordSettings
//{
// SaveMapping = true
//},
PreWireMockMiddlewareInit = app => { System.Console.WriteLine($"PreWireMockMiddlewareInit : {app.GetType()}"); },
PostWireMockMiddlewareInit = app => { System.Console.WriteLine($"PostWireMockMiddlewareInit : {app.GetType()}"); }
}); });
System.Console.WriteLine("FluentMockServer listening at {0}", string.Join(" and ", server.Urls)); System.Console.WriteLine("FluentMockServer listening at {0}", string.Join(" and ", server.Urls));
server.SetBasicAuthentication("a", "b"); 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*"))
.RespondWith(Response.Create()
.WithStatusCode(201)
.WithHeader("MyHeader", "application/json", "application/json2")
.WithBody(@"{ ""result"": ""data posted with 201""}"));
server
.Given(Request.Create().WithPath("/file").UsingGet())
.RespondWith(Response.Create()
.WithBodyFromFile(@"c:\temp\x.json", false)
);
server
.Given(Request.Create().WithPath("/filecache").UsingGet())
.RespondWith(Response.Create()
.WithBodyFromFile(@"c:\temp\x.json")
);
server
.Given(Request.Create().WithPath("/file_rel").UsingGet())
.RespondWith(Response.Create()
.WithBodyFromFile("Program.cs", false)
);
server
.Given(Request.Create().WithHeader("ProxyThis", "true")
.UsingGet())
.RespondWith(Response.Create()
.WithProxy("http://www.google.com")
);
server
.Given(Request.Create().WithPath("/bodyasbytes.png")
.UsingGet())
.RespondWith(Response.Create()
.WithHeader("Content-Type", "image/png")
.WithBody(Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTczbp9jAAAAJ0lEQVQoU2NgUPuPD6Hz0RCEAtJoiAxpCCBXGgmRIo0TofORkdp/AMiMdRVnV6O0AAAAAElFTkSuQmCC"))
);
server server
.Given(Request.Create().WithPath("/oauth2/access").UsingPost().WithBody("grant_type=password;username=u;password=p")) .Given(Request.Create().WithPath("/oauth2/access").UsingPost().WithBody("grant_type=password;username=u;password=p"))
@@ -58,13 +118,6 @@ namespace WireMock.Net.ConsoleApplication
.WithHeader("Content-Type", "application/json") .WithHeader("Content-Type", "application/json")
.WithBody(@"{ ""result"": ""data posted with FUNC 201""}")); .WithBody(@"{ ""result"": ""data posted with FUNC 201""}"));
server
.Given(Request.Create().WithPath("/data", "/ax").UsingPost().WithHeader("Content-Type", "application/json*"))
.RespondWith(Response.Create()
.WithStatusCode(201)
.WithHeader("Content-Type", "application/json")
.WithBody(@"{ ""result"": ""data posted with 201""}"));
server server
.Given(Request.Create().WithPath("/json").UsingPost().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]"))) .Given(Request.Create().WithPath("/json").UsingPost().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]")))
.RespondWith(Response.Create() .RespondWith(Response.Create()

View File

@@ -47,9 +47,6 @@
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="WireMock.Net">
<HintPath>..\..\src\WireMock.Net\bin\$(Configuration)\net45\WireMock.Net.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="MainApp.cs" /> <Compile Include="MainApp.cs" />
@@ -67,6 +64,16 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj">
<Project>{b6269aac-170a-43d5-8b9a-579ded3d9a95}</Project>
<Name>WireMock.Net.StandAlone</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj">
<Project>{d3804228-91f4-4502-9595-39584e5a01ad}</Project>
<Name>WireMock.Net</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -7,15 +7,15 @@ namespace WireMock.Net.StandAlone.NETCoreApp
class Program class Program
{ {
private static int sleepTime = 30000; private static int sleepTime = 30000;
private static FluentMockServer server; private static FluentMockServer _server;
static void Main(string[] args) static void Main(string[] args)
{ {
server = StandAloneApp.Start(args); _server = StandAloneApp.Start(args);
Console.WriteLine($"{DateTime.UtcNow} Press Ctrl+C to shut down"); Console.WriteLine($"{DateTime.UtcNow} Press Ctrl+C to shut down");
System.Console.CancelKeyPress += (s,e) => Console.CancelKeyPress += (s, e) =>
{ {
Stop("CancelKeyPress"); Stop("CancelKeyPress");
}; };
@@ -25,7 +25,7 @@ namespace WireMock.Net.StandAlone.NETCoreApp
Stop("AssemblyLoadContext.Default.Unloading"); Stop("AssemblyLoadContext.Default.Unloading");
}; };
while(true) while (true)
{ {
Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server running"); Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server running");
Thread.Sleep(sleepTime); Thread.Sleep(sleepTime);
@@ -35,7 +35,7 @@ namespace WireMock.Net.StandAlone.NETCoreApp
private static void Stop(string why) private static void Stop(string why)
{ {
Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server stopping because '{why}'"); Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server stopping because '{why}'");
server.Stop(); _server.Stop();
Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server stopped"); 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> /// </summary>
/// <param name="settings">The FluentMockServerSettings</param> /// <param name="settings">The FluentMockServerSettings</param>
[PublicAPI] [PublicAPI]
public static FluentMockServer Start([NotNull] FluentMockServerSettings settings) public static FluentMockServer Start([NotNull] IFluentMockServerSettings settings)
{ {
Check.NotNull(settings, nameof(settings)); Check.NotNull(settings, nameof(settings));
@@ -66,6 +66,7 @@ namespace WireMock.Net.StandAlone
{ {
Url = proxyURL, Url = proxyURL,
SaveMapping = parser.GetBoolValue("SaveMapping"), SaveMapping = parser.GetBoolValue("SaveMapping"),
SaveMappingToFile = parser.GetBoolValue("SaveMappingToFile"),
X509Certificate2ThumbprintOrSubjectName = parser.GetStringValue("X509Certificate2ThumbprintOrSubjectName") X509Certificate2ThumbprintOrSubjectName = parser.GetStringValue("X509Certificate2ThumbprintOrSubjectName")
}; };
} }

View File

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

View File

@@ -10,79 +10,71 @@ namespace WireMock.Admin.Mappings
/// <summary> /// <summary>
/// Gets or sets the HTTP status. /// Gets or sets the HTTP status.
/// </summary> /// </summary>
/// <value>
/// The HTTP status.
/// </value>
public int? StatusCode { get; set; } public int? StatusCode { get; set; }
/// <summary>
/// Gets or sets the body destination (SameAsSource, String or Bytes).
/// </summary>
public string BodyDestination { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body. /// Gets or sets the body.
/// </summary> /// </summary>
/// <value>
/// The body.
/// </value>
public string Body { get; set; } public string Body { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body. /// Gets or sets the body.
/// </summary> /// </summary>
/// <value> public string BodyFromBase64 { get; set; }
/// The body.
/// </value>
public string BodyAsBase64 { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body (as JSON object). /// Gets or sets the body (as JSON object).
/// </summary> /// </summary>
/// <value>
/// The body.
/// </value>
public object BodyAsJson { get; set; } public object BodyAsJson { get; set; }
/// <summary>
/// Gets or sets the body (as bytearray).
/// </summary>
public byte[] BodyAsBytes { get; set; }
/// <summary>
/// Gets or sets the body as a file.
/// </summary>
public string BodyAsFile { get; set; }
/// <summary>
/// Is the body as file cached?
/// </summary>
public bool? BodyAsFileIsCached { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body encoding. /// Gets or sets the body encoding.
/// </summary> /// </summary>
/// <value>
/// The body encoding.
/// </value>
public EncodingModel BodyEncoding { get; set; } public EncodingModel BodyEncoding { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether [use transformer]. /// Gets or sets a value indicating whether [use transformer].
/// </summary> /// </summary>
/// <value>
/// <c>true</c> if [use transformer]; otherwise, <c>false</c>.
/// </value>
public bool UseTransformer { get; set; } public bool UseTransformer { get; set; }
/// <summary> /// <summary>
/// Gets or sets the headers. /// Gets or sets the headers.
/// </summary> /// </summary>
/// <value> public IDictionary<string, object> Headers { get; set; }
/// The headers.
/// </value>
public IDictionary<string, string> Headers { get; set; }
/// <summary> /// <summary>
/// Gets or sets the Headers (Raw). /// Gets or sets the Headers (Raw).
/// </summary> /// </summary>
/// <value>
/// The Headers (Raw).
/// </value>
public string HeadersRaw { get; set; } public string HeadersRaw { get; set; }
/// <summary> /// <summary>
/// Gets or sets the delay in milliseconds. /// Gets or sets the delay in milliseconds.
/// </summary> /// </summary>
/// <value>
/// The delay in milliseconds.
/// </value>
public int? Delay { get; set; } public int? Delay { get; set; }
/// <summary> /// <summary>
/// Gets or sets the Proxy URL. /// Gets or sets the Proxy URL.
/// </summary> /// </summary>
/// <value>ProxyUrl</value>
public string ProxyUrl { get; set; } public string ProxyUrl { get; set; }
/// <summary> /// <summary>

View File

@@ -23,17 +23,11 @@ namespace WireMock.Admin.Requests
/// <summary> /// <summary>
/// Gets or sets the Path. /// Gets or sets the Path.
/// </summary> /// </summary>
/// <value>
/// The Path.
/// </value>
public string Path { get; set; } public string Path { get; set; }
/// <summary> /// <summary>
/// Gets or sets the absolete URL. /// Gets or sets the absolete URL.
/// </summary> /// </summary>
/// <value>
/// The absolute URL.
/// </value>
public string AbsoluteUrl { get; set; } public string AbsoluteUrl { get; set; }
/// <summary> /// <summary>
@@ -44,41 +38,26 @@ namespace WireMock.Admin.Requests
/// <summary> /// <summary>
/// Gets or sets the method. /// Gets or sets the method.
/// </summary> /// </summary>
/// <value>
/// The method.
/// </value>
public string Method { get; set; } public string Method { get; set; }
/// <summary> /// <summary>
/// Gets or sets the Headers. /// Gets or sets the Headers.
/// </summary> /// </summary>
/// <value> public IDictionary<string, WireMockList<string>> Headers { get; set; }
/// The Headers.
/// </value>
public IDictionary<string, string> Headers { get; set; }
/// <summary> /// <summary>
/// Gets or sets the Cookies. /// Gets or sets the Cookies.
/// </summary> /// </summary>
/// <value>
/// The Cookies.
/// </value>
public IDictionary<string, string> Cookies { get; set; } public IDictionary<string, string> Cookies { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body. /// Gets or sets the body.
/// </summary> /// </summary>
/// <value>
/// The body.
/// </value>
public string Body { get; set; } public string Body { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body encoding. /// Gets or sets the body encoding.
/// </summary> /// </summary>
/// <value>
/// The body encoding.
/// </value>
public EncodingModel BodyEncoding { get; set; } public EncodingModel BodyEncoding { get; set; }
} }
} }

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using WireMock.Admin.Mappings; using WireMock.Admin.Mappings;
using WireMock.Util;
namespace WireMock.Admin.Requests namespace WireMock.Admin.Requests
{ {
@@ -16,13 +17,33 @@ namespace WireMock.Admin.Requests
/// <summary> /// <summary>
/// Gets the headers. /// Gets the headers.
/// </summary> /// </summary>
public IDictionary<string, string> Headers { get; set; } public IDictionary<string, WireMockList<string>> Headers { get; set; }
/// <summary>
/// Gets or sets the body destination (SameAsSource, String or Bytes).
/// </summary>
public string BodyDestination { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body. /// Gets or sets the body.
/// </summary> /// </summary>
public string Body { get; set; } public string Body { get; set; }
/// <summary>
/// Gets or sets the body as bytes.
/// </summary>
public byte[] BodyAsBytes { get; set; }
/// <summary>
/// Gets or sets the body as file.
/// </summary>
public string BodyAsFile { get; set; }
/// <summary>
/// Is the body as file cached?
/// </summary>
public bool? BodyAsFileIsCached { get; set; }
/// <summary> /// <summary>
/// Gets or sets the original body. /// Gets or sets the original body.
/// </summary> /// </summary>

View File

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

View File

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

View File

@@ -1,22 +1,25 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks; using System.Threading.Tasks;
using WireMock.Validation;
namespace WireMock.Http namespace WireMock.Http
{ {
internal static class HttpClientHelper internal static class HttpClientHelper
{ {
public static HttpClient CreateHttpClient(string clientX509Certificate2ThumbprintOrSubjectName = null)
private static HttpClient CreateHttpClient(string clientX509Certificate2ThumbprintOrSubjectName = null)
{ {
if (!string.IsNullOrEmpty(clientX509Certificate2ThumbprintOrSubjectName)) HttpClientHandler handler;
if (string.IsNullOrEmpty(clientX509Certificate2ThumbprintOrSubjectName))
{
handler = new HttpClientHandler();
}
else
{ {
#if NETSTANDARD || NET46 #if NETSTANDARD || NET46
var handler = new HttpClientHandler handler = new HttpClientHandler
{ {
ClientCertificateOptions = ClientCertificateOption.Manual, ClientCertificateOptions = ClientCertificateOption.Manual,
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls, SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
@@ -25,63 +28,91 @@ namespace WireMock.Http
var x509Certificate2 = CertificateUtil.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName); var x509Certificate2 = CertificateUtil.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName);
handler.ClientCertificates.Add(x509Certificate2); handler.ClientCertificates.Add(x509Certificate2);
#else #else
var handler = new WebRequestHandler
var webRequestHandler = new WebRequestHandler
{ {
ClientCertificateOptions = ClientCertificateOption.Manual, ClientCertificateOptions = ClientCertificateOption.Manual,
ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true, ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate
}; };
var x509Certificate2 = CertificateUtil.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName); var x509Certificate2 = CertificateUtil.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName);
handler.ClientCertificates.Add(x509Certificate2); webRequestHandler.ClientCertificates.Add(x509Certificate2);
return new HttpClient(handler); handler = webRequestHandler;
#endif #endif
} }
return new HttpClient(); // For proxy we shouldn't follow auto redirects
handler.AllowAutoRedirect = false;
// If UseCookies enabled, httpClient ignores Cookie header
handler.UseCookies = false;
return new HttpClient(handler);
} }
public static async Task<ResponseMessage> SendAsync(RequestMessage requestMessage, string url, string clientX509Certificate2ThumbprintOrSubjectName = null) public static async Task<ResponseMessage> SendAsync(HttpClient client, RequestMessage requestMessage, string url)
{ {
var client = CreateHttpClient(clientX509Certificate2ThumbprintOrSubjectName); Check.NotNull(client, nameof(client));
var originalUri = new Uri(requestMessage.Url);
var requiredUri = new Uri(url);
var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url); var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url);
// Set Body if present
if (requestMessage.BodyAsBytes != null)
{
httpRequestMessage.Content = new ByteArrayContent(requestMessage.BodyAsBytes);
}
// Overwrite the host header // Overwrite the host header
httpRequestMessage.Headers.Host = new Uri(url).Authority; httpRequestMessage.Headers.Host = requiredUri.Authority;
// Set headers if present // Set headers if present
if (requestMessage.Headers != null) if (requestMessage.Headers != null)
{ {
foreach (var headerName in requestMessage.Headers.Keys.Where(k => k.ToUpper() != "HOST")) foreach (var header in requestMessage.Headers.Where(header => !string.Equals(header.Key, "HOST", StringComparison.OrdinalIgnoreCase)))
{ {
httpRequestMessage.Headers.Add(headerName, new[] { requestMessage.Headers[headerName] }); // Try to add to request headers. If failed - try to add to content headers
if (!httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value))
{
httpRequestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
} }
} }
// Set Body if present
if (requestMessage.BodyAsBytes != null && requestMessage.BodyAsBytes.Length > 0)
{
httpRequestMessage.Content = new ByteArrayContent(requestMessage.BodyAsBytes);
}
// Call the URL // Call the URL
var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead); var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead);
// Transform response // Transform response
var responseMessage = new ResponseMessage var responseMessage = new ResponseMessage
{ {
StatusCode = (int)httpResponseMessage.StatusCode, StatusCode = (int)httpResponseMessage.StatusCode,
BodyAsBytes = await httpResponseMessage.Content.ReadAsByteArrayAsync(),
Body = await httpResponseMessage.Content.ReadAsStringAsync() Body = await httpResponseMessage.Content.ReadAsStringAsync()
}; };
foreach (var header in httpResponseMessage.Headers) // Set both content and response headers, replacing URLs in values
var headers = httpResponseMessage.Content?.Headers.Union(httpResponseMessage.Headers);
foreach (var header in headers)
{ {
responseMessage.AddHeader(header.Key, header.Value.FirstOrDefault()); // if Location header contains absolute redirect URL, and base URL is one that we proxy to,
// we need to replace it to original one.
if (string.Equals(header.Key, "Location", StringComparison.OrdinalIgnoreCase)
&& Uri.TryCreate(header.Value.First(), UriKind.Absolute, out Uri absoluteLocationUri)
&& string.Equals(absoluteLocationUri.Host, requiredUri.Host, StringComparison.OrdinalIgnoreCase))
{
var replacedLocationUri = new Uri(originalUri, absoluteLocationUri.PathAndQuery);
responseMessage.AddHeader(header.Key, replacedLocationUri.ToString());
}
else
{
responseMessage.AddHeader(header.Key, header.Value.ToArray());
}
} }
return responseMessage; return responseMessage;

View File

@@ -0,0 +1,96 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace WireMock.Http
{
/// <summary>
/// Copied from https://raw.githubusercontent.com/dotnet/corefx/master/src/Common/src/System/Net/HttpKnownHeaderNames.cs
/// </summary>
internal static class HttpKnownHeaderNames
{
public const string Accept = "Accept";
public const string AcceptCharset = "Accept-Charset";
public const string AcceptEncoding = "Accept-Encoding";
public const string AcceptLanguage = "Accept-Language";
public const string AcceptPatch = "Accept-Patch";
public const string AcceptRanges = "Accept-Ranges";
public const string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";
public const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
public const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
public const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
public const string AccessControlExposeHeaders = "Access-Control-Expose-Headers";
public const string AccessControlMaxAge = "Access-Control-Max-Age";
public const string Age = "Age";
public const string Allow = "Allow";
public const string AltSvc = "Alt-Svc";
public const string Authorization = "Authorization";
public const string CacheControl = "Cache-Control";
public const string Connection = "Connection";
public const string ContentDisposition = "Content-Disposition";
public const string ContentEncoding = "Content-Encoding";
public const string ContentLanguage = "Content-Language";
public const string ContentLength = "Content-Length";
public const string ContentLocation = "Content-Location";
public const string ContentMD5 = "Content-MD5";
public const string ContentRange = "Content-Range";
public const string ContentSecurityPolicy = "Content-Security-Policy";
public const string ContentType = "Content-Type";
public const string Cookie = "Cookie";
public const string Cookie2 = "Cookie2";
public const string Date = "Date";
public const string ETag = "ETag";
public const string Expect = "Expect";
public const string Expires = "Expires";
public const string From = "From";
public const string Host = "Host";
public const string IfMatch = "If-Match";
public const string IfModifiedSince = "If-Modified-Since";
public const string IfNoneMatch = "If-None-Match";
public const string IfRange = "If-Range";
public const string IfUnmodifiedSince = "If-Unmodified-Since";
public const string KeepAlive = "Keep-Alive";
public const string LastModified = "Last-Modified";
public const string Link = "Link";
public const string Location = "Location";
public const string MaxForwards = "Max-Forwards";
public const string Origin = "Origin";
public const string P3P = "P3P";
public const string Pragma = "Pragma";
public const string ProxyAuthenticate = "Proxy-Authenticate";
public const string ProxyAuthorization = "Proxy-Authorization";
public const string ProxyConnection = "Proxy-Connection";
public const string PublicKeyPins = "Public-Key-Pins";
public const string Range = "Range";
public const string Referer = "Referer"; // NB: The spelling-mistake "Referer" for "Referrer" must be matched.
public const string RetryAfter = "Retry-After";
public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions";
public const string SecWebSocketKey = "Sec-WebSocket-Key";
public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
public const string SecWebSocketVersion = "Sec-WebSocket-Version";
public const string Server = "Server";
public const string SetCookie = "Set-Cookie";
public const string SetCookie2 = "Set-Cookie2";
public const string StrictTransportSecurity = "Strict-Transport-Security";
public const string TE = "TE";
public const string TSV = "TSV";
public const string Trailer = "Trailer";
public const string TransferEncoding = "Transfer-Encoding";
public const string Upgrade = "Upgrade";
public const string UpgradeInsecureRequests = "Upgrade-Insecure-Requests";
public const string UserAgent = "User-Agent";
public const string Vary = "Vary";
public const string Via = "Via";
public const string WWWAuthenticate = "WWW-Authenticate";
public const string Warning = "Warning";
public const string XAspNetVersion = "X-AspNet-Version";
public const string XContentDuration = "X-Content-Duration";
public const string XContentTypeOptions = "X-Content-Type-Options";
public const string XFrameOptions = "X-Frame-Options";
public const string XMSEdgeRef = "X-MSEdge-Ref";
public const string XPoweredBy = "X-Powered-By";
public const string XRequestID = "X-Request-ID";
public const string XUACompatible = "X-UA-Compatible";
}
}

View File

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

View File

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

View File

@@ -25,7 +25,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class.
/// </summary> /// </summary>
/// <param name="clientIPs">The clientIPs.</param> /// <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; Funcs = funcs;
} }
/// <summary> /// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
/// 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>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult) public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); double score = IsMatch(requestMessage);

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Util;
using WireMock.Validation; using WireMock.Validation;
namespace WireMock.Matchers.Request namespace WireMock.Matchers.Request
@@ -9,12 +10,13 @@ namespace WireMock.Matchers.Request
/// <summary> /// <summary>
/// The request header matcher. /// The request header matcher.
/// </summary> /// </summary>
/// <inheritdoc cref="IRequestMatcher"/>
public class RequestMessageHeaderMatcher : IRequestMatcher public class RequestMessageHeaderMatcher : IRequestMatcher
{ {
/// <summary> /// <summary>
/// The functions /// The functions
/// </summary> /// </summary>
public Func<IDictionary<string, string>, bool>[] Funcs { get; } public Func<IDictionary<string, string[]>, bool>[] Funcs { get; }
/// <summary> /// <summary>
/// The name /// The name
@@ -31,7 +33,7 @@ namespace WireMock.Matchers.Request
/// </summary> /// </summary>
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="pattern">The pattern.</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) public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] string pattern, bool ignoreCase = true)
{ {
Check.NotNull(name, nameof(name)); Check.NotNull(name, nameof(name));
@@ -41,6 +43,21 @@ namespace WireMock.Matchers.Request
Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) }; 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> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary> /// </summary>
@@ -59,21 +76,14 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary> /// </summary>
/// <param name="funcs">The funcs.</param> /// <param name="funcs">The funcs.</param>
public RequestMessageHeaderMatcher([NotNull] params Func<IDictionary<string, string>, bool>[] funcs) public RequestMessageHeaderMatcher([NotNull] params Func<IDictionary<string, string[]>, bool>[] funcs)
{ {
Check.NotNull(funcs, nameof(funcs)); Check.NotNull(funcs, nameof(funcs));
Funcs = funcs; Funcs = funcs;
} }
/// <summary> /// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
/// 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>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult) public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); double score = IsMatch(requestMessage);
@@ -86,7 +96,7 @@ namespace WireMock.Matchers.Request
return MatchScores.Mismatch; return MatchScores.Mismatch;
if (Funcs != null) if (Funcs != null)
return MatchScores.ToScore(Funcs.Any(f => f(requestMessage.Headers))); return MatchScores.ToScore(Funcs.Any(f => f(requestMessage.Headers.ToDictionary(entry => entry.Key, entry => entry.Value.ToArray()))));
if (Matchers == null) if (Matchers == null)
return MatchScores.Mismatch; return MatchScores.Mismatch;
@@ -94,8 +104,8 @@ namespace WireMock.Matchers.Request
if (!requestMessage.Headers.ContainsKey(Name)) if (!requestMessage.Headers.ContainsKey(Name))
return MatchScores.Mismatch; return MatchScores.Mismatch;
string value = requestMessage.Headers[Name]; WireMockList<string> list = requestMessage.Headers[Name];
return Matchers.Max(m => m.IsMatch(value)); return Matchers.Max(m => list.Max(value => m.IsMatch(value))); // TODO : is this correct ?
} }
} }
} }

View File

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

View File

@@ -25,7 +25,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary> /// </summary>
/// <param name="urls">The urls.</param> /// <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; Funcs = funcs;
} }
/// <summary> /// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
/// 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>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult) public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); double score = IsMatch(requestMessage);

View File

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

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

@@ -46,7 +46,7 @@ namespace WireMock.Owin
string bodyAsString = null; string bodyAsString = null;
byte[] body = null; byte[] body = null;
Encoding bodyEncoding = null; Encoding bodyEncoding = null;
if (request.Body != null) if (ParseBody(method) && request.Body != null)
{ {
using (var streamReader = new StreamReader(request.Body)) using (var streamReader = new StreamReader(request.Body))
{ {
@@ -57,18 +57,43 @@ namespace WireMock.Owin
body = bodyEncoding.GetBytes(bodyAsString); body = bodyEncoding.GetBytes(bodyAsString);
} }
var listenerHeaders = request.Headers; Dictionary<string, string[]> headers = null;
if (request.Headers.Any())
{
headers = new Dictionary<string, string[]>();
foreach (var header in request.Headers)
{
headers.Add(header.Key, header.Value);
}
}
var headers = new Dictionary<string, string>(); IDictionary<string, string> cookies = null;
foreach (var header in listenerHeaders) if (request.Cookies.Any())
headers.Add(header.Key, header.Value.FirstOrDefault()); {
cookies = new Dictionary<string, string>();
var cookies = new Dictionary<string, string>(); foreach (var cookie in request.Cookies)
{
foreach (var cookie in request.Cookies) cookies.Add(cookie.Key, cookie.Value);
cookies.Add(cookie.Key, cookie.Value); }
}
return new RequestMessage(url, method, clientIP, body, bodyAsString, bodyEncoding, headers, cookies) { DateTime = DateTime.Now }; return new RequestMessage(url, method, clientIP, body, bodyAsString, bodyEncoding, headers, cookies) { DateTime = DateTime.Now };
} }
private bool ParseBody(string method)
{
/*
HEAD - No defined body semantics.
GET - No defined body semantics.
PUT - Body supported.
POST - Body supported.
DELETE - No defined body semantics.
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", "PATCH" }.Contains(method.ToUpper());
}
} }
} }

View File

@@ -1,7 +1,10 @@
using System.IO; using System;
using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using WireMock.Util;
#if !NETSTANDARD #if !NETSTANDARD
using Microsoft.Owin; using Microsoft.Owin;
#else #else
@@ -17,6 +20,19 @@ namespace WireMock.Owin
{ {
private readonly Encoding _utf8NoBom = new UTF8Encoding(false); 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> /// <summary>
/// MapAsync ResponseMessage to OwinResponse /// MapAsync ResponseMessage to OwinResponse
/// </summary> /// </summary>
@@ -32,15 +48,47 @@ namespace WireMock.Owin
{ {
response.StatusCode = responseMessage.StatusCode; response.StatusCode = responseMessage.StatusCode;
responseMessage.Headers.ToList().ForEach(pair => response.Headers.Append(pair.Key, pair.Value)); // Set headers
foreach (var pair in responseMessage.Headers)
{
if (RestrictedResponseHeaders.ContainsKey(pair.Key))
{
RestrictedResponseHeaders[pair.Key]?.Invoke(response, pair.Value);
}
else
{
#if !NETSTANDARD
response.Headers.AppendValues(pair.Key, pair.Value.ToArray());
#else
response.Headers.Append(pair.Key, pair.Value.ToArray());
#endif
}
}
if (responseMessage.Body == null) if (responseMessage.Body == null && responseMessage.BodyAsBytes == null && responseMessage.BodyAsFile == null)
{
return; return;
}
if (responseMessage.BodyAsBytes != null)
{
await response.Body.WriteAsync(responseMessage.BodyAsBytes, 0, responseMessage.BodyAsBytes.Length);
return;
}
if (responseMessage.BodyAsFile != null)
{
byte[] bytes = File.ReadAllBytes(responseMessage.BodyAsFile);
await response.Body.WriteAsync(bytes, 0, bytes.Length);
return;
}
Encoding encoding = responseMessage.BodyEncoding ?? _utf8NoBom; Encoding encoding = responseMessage.BodyEncoding ?? _utf8NoBom;
using (var writer = new StreamWriter(response.Body, encoding)) using (var writer = new StreamWriter(response.Body, encoding))
{ {
await writer.WriteAsync(responseMessage.Body); await writer.WriteAsync(responseMessage.Body);
// TODO : response.ContentLength = responseMessage.Body.Length;
} }
} }
} }

View File

@@ -57,11 +57,14 @@ namespace WireMock.Owin
private void StartServers() private void StartServers()
{ {
System.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 => Action<IAppBuilder> startup = app =>
{ {
app.Use<GlobalExceptionMiddleware>();
_options.PreWireMockMiddlewareInit?.Invoke(app);
app.Use<WireMockMiddleware>(_options); app.Use<WireMockMiddleware>(_options);
_options.PostWireMockMiddlewareInit?.Invoke(app);
}; };
var servers = new List<IDisposable>(); var servers = new List<IDisposable>();

View File

@@ -4,6 +4,8 @@ using WireMock.Logging;
using WireMock.Matchers.Request; using WireMock.Matchers.Request;
using System.Linq; using System.Linq;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.Util;
using Newtonsoft.Json;
#if !NETSTANDARD #if !NETSTANDARD
using Microsoft.Owin; using Microsoft.Owin;
#else #else
@@ -50,7 +52,7 @@ namespace WireMock.Owin
RequestMatchResult requestMatchResult = null; RequestMatchResult requestMatchResult = null;
try try
{ {
foreach (var mapping in _options.Mappings.Where(m => m.Scenario != null)) foreach (var mapping in _options.Mappings.Where(m => m?.Scenario != null))
{ {
// Set start // Set start
if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState) if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState)
@@ -101,8 +103,8 @@ namespace WireMock.Owin
if (targetMapping.IsAdminInterface && _options.AuthorizationMatcher != null) if (targetMapping.IsAdminInterface && _options.AuthorizationMatcher != null)
{ {
bool present = request.Headers.TryGetValue("Authorization", out string authorization); bool present = request.Headers.TryGetValue("Authorization", out WireMockList<string> authorization);
if (!present || _options.AuthorizationMatcher.IsMatch(authorization) < MatchScores.Perfect) if (!present || _options.AuthorizationMatcher.IsMatch(authorization.ToString()) < MatchScores.Perfect)
{ {
response = new ResponseMessage { StatusCode = 401 }; response = new ResponseMessage { StatusCode = 401 };
return; return;
@@ -123,7 +125,7 @@ namespace WireMock.Owin
} }
catch (Exception ex) catch (Exception ex)
{ {
response = new ResponseMessage { StatusCode = 500, Body = ex.ToString() }; response = new ResponseMessage { StatusCode = 500, Body = JsonConvert.SerializeObject(ex) };
} }
finally finally
{ {

View File

@@ -4,6 +4,12 @@ using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using WireMock.Logging; using WireMock.Logging;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.Util;
#if !NETSTANDARD
using Owin;
#else
using Microsoft.AspNetCore.Builder;
#endif
namespace WireMock.Owin namespace WireMock.Owin
{ {
@@ -17,12 +23,22 @@ namespace WireMock.Owin
public IList<Mapping> Mappings { get; set; } = new List<Mapping>(); 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; } public int? RequestLogExpirationDuration { get; set; }
public int? MaxRequestLogCount { get; set; } public int? MaxRequestLogCount { get; set; }
public IDictionary<string, object> Scenarios { get; } = new ConcurrentDictionary<string, object>(); public IDictionary<string, object> Scenarios { get; } = new ConcurrentDictionary<string, object>();
#if !NETSTANDARD
public Action<IAppBuilder> PreWireMockMiddlewareInit { get; set; }
public Action<IAppBuilder> PostWireMockMiddlewareInit { get; set; }
#else
public Action<IApplicationBuilder> PreWireMockMiddlewareInit { get; set; }
public Action<IApplicationBuilder> PostWireMockMiddlewareInit { get; set; }
#endif
} }
} }

View File

@@ -12,7 +12,7 @@ namespace WireMock.RequestBuilders
public interface IHeadersAndCookiesRequestBuilder : IBodyRequestBuilder, IRequestMatcher, IParamsRequestBuilder public interface IHeadersAndCookiesRequestBuilder : IBodyRequestBuilder, IRequestMatcher, IParamsRequestBuilder
{ {
/// <summary> /// <summary>
/// The with header. /// Add Header matching based on name, pattern and ignoreCase.
/// </summary> /// </summary>
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
@@ -20,6 +20,15 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithHeader([NotNull] string name, string pattern, bool ignoreCase = true); 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> /// <summary>
/// The with header. /// The with header.
/// </summary> /// </summary>
@@ -33,7 +42,7 @@ namespace WireMock.RequestBuilders
/// </summary> /// </summary>
/// <param name="funcs">The headers funcs.</param> /// <param name="funcs">The headers funcs.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithHeader([NotNull] params Func<IDictionary<string, string>, bool>[] funcs); IRequestBuilder WithHeader([NotNull] params Func<IDictionary<string, string[]>, bool>[] funcs);
/// <summary> /// <summary>
/// The with cookie. /// The with cookie.

View File

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

View File

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

View File

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

@@ -0,0 +1,23 @@
namespace WireMock.ResponseBuilders
{
/// <summary>
/// Defines the BodyDestinationFormat
/// </summary>
public static class BodyDestinationFormat
{
/// <summary>
/// Same as source (no conversion)
/// </summary>
public const string SameAsSource = "SameAsSource";
/// <summary>
/// Convert to string
/// </summary>
public const string String = "String";
/// <summary>
/// Convert to bytes
/// </summary>
public const string Bytes = "Bytes";
}
}

View File

@@ -1,4 +1,5 @@
using System.Text; using System;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace WireMock.ResponseBuilders namespace WireMock.ResponseBuilders
@@ -9,15 +10,25 @@ namespace WireMock.ResponseBuilders
public interface IBodyResponseBuilder : ITransformResponseBuilder public interface IBodyResponseBuilder : ITransformResponseBuilder
{ {
/// <summary> /// <summary>
/// The with body. /// WithBody : Create a ... response based on a string.
/// </summary> /// </summary>
/// <param name="body">The body.</param> /// <param name="body">The body.</param>
/// <param name="destination">The Body Destination format (SameAsSource, String or Bytes).</param>
/// <param name="encoding">The body encoding.</param> /// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns> /// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBody([NotNull] string body, [CanBeNull] Encoding encoding = null); IResponseBuilder WithBody([NotNull] string body, [CanBeNull] string destination = BodyDestinationFormat.SameAsSource, [CanBeNull] Encoding encoding = null);
/// <summary> /// <summary>
/// The with body as Json. /// WithBody : Create a ... response based on a bytearray.
/// </summary>
/// <param name="body">The body.</param>
/// <param name="destination">The Body Destination format (SameAsSource, String or Bytes).</param>
/// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBody([NotNull] byte[] body, [CanBeNull] string destination = BodyDestinationFormat.SameAsSource, [CanBeNull] Encoding encoding = null);
/// <summary>
/// WithBody : Create a string response based on a object (which will be converted to a JSON string).
/// </summary> /// </summary>
/// <param name="body">The body.</param> /// <param name="body">The body.</param>
/// <param name="encoding">The body encoding.</param> /// <param name="encoding">The body encoding.</param>
@@ -25,11 +36,20 @@ namespace WireMock.ResponseBuilders
IResponseBuilder WithBodyAsJson([NotNull] object body, [CanBeNull] Encoding encoding = null); IResponseBuilder WithBodyAsJson([NotNull] object body, [CanBeNull] Encoding encoding = null);
/// <summary> /// <summary>
/// The with body as base64. /// WithBody : Create a string response based on a Base64 string (which will be decoded to a normal string).
/// </summary> /// </summary>
/// <param name="bodyAsbase64">The body asbase64.</param> /// <param name="bodyAsbase64">The body.</param>
/// <param name="encoding">The Encoding.</param> /// <param name="encoding">The Encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns> /// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBodyAsBase64([NotNull] string bodyAsbase64, [CanBeNull] Encoding encoding = null); [Obsolete]
IResponseBuilder WithBodyFromBase64([NotNull] string bodyAsbase64, [CanBeNull] Encoding encoding = null);
/// <summary>
/// WithBodyFromFile : Create a ... response based on a File.
/// </summary>
/// <param name="filename">The filename.</param>
/// <param name="cache">Defines if this file is cached in memory or retrieved from disk everytime the response is created.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBodyFromFile([NotNull] string filename, bool cache = true);
} }
} }

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Util;
namespace WireMock.ResponseBuilders namespace WireMock.ResponseBuilders
{ {
@@ -12,15 +13,29 @@ namespace WireMock.ResponseBuilders
/// The with header. /// The with header.
/// </summary> /// </summary>
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="value">The value.</param> /// <param name="values">The values.</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns> /// <returns>The <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithHeader([NotNull] string name, string value); IResponseBuilder WithHeader([NotNull] string name, params string[] values);
/// <summary> /// <summary>
/// The with headers. /// The with headers.
/// </summary> /// </summary>
/// <param name="headers">The headers.</param> /// <param name="headers">The headers.</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns> /// <returns>The <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithHeaders([NotNull] IDictionary<string,string> headers); IResponseBuilder WithHeaders([NotNull] IDictionary<string, string> headers);
/// <summary>
/// The with headers.
/// </summary>
/// <param name="headers">The headers.</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithHeaders([NotNull] IDictionary<string, string[]> headers);
/// <summary>
/// The with headers.
/// </summary>
/// <param name="headers">The headers.</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithHeaders([NotNull] IDictionary<string, WireMockList<string>> headers);
} }
} }

View File

@@ -1,13 +1,17 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Newtonsoft.Json; using Newtonsoft.Json;
using WireMock.Validation;
using WireMock.Http; using WireMock.Http;
using WireMock.Transformers; using WireMock.Transformers;
using WireMock.Util;
using WireMock.Validation;
namespace WireMock.ResponseBuilders namespace WireMock.ResponseBuilders
{ {
@@ -16,6 +20,8 @@ namespace WireMock.ResponseBuilders
/// </summary> /// </summary>
public class Response : IResponseBuilder public class Response : IResponseBuilder
{ {
private HttpClient _httpClientForProxy;
/// <summary> /// <summary>
/// The delay /// The delay
/// </summary> /// </summary>
@@ -125,53 +131,117 @@ namespace WireMock.ResponseBuilders
return WithStatusCode((int)HttpStatusCode.NotFound); return WithStatusCode((int)HttpStatusCode.NotFound);
} }
/// <summary> /// <inheritdoc cref="IHeadersResponseBuilder.WithHeader(string, string[])"/>
/// The with header. public IResponseBuilder WithHeader(string name, params string[] values)
/// </summary>
/// <param name="name">The name.</param>
/// <param name="value">The value.</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
public IResponseBuilder WithHeader(string name, string value)
{ {
Check.NotNull(name, nameof(name)); Check.NotNull(name, nameof(name));
ResponseMessage.AddHeader(name, value); ResponseMessage.AddHeader(name, values);
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IHeadersResponseBuilder.WithHeaders(IDictionary{string, string})"/>
/// The with headers.
/// </summary>
/// <param name="headers">The headers.</param>
/// <returns></returns>
public IResponseBuilder WithHeaders(IDictionary<string, string> headers) public IResponseBuilder WithHeaders(IDictionary<string, string> headers)
{
Check.NotNull(headers, nameof(headers));
ResponseMessage.Headers = headers.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
return this;
}
/// <inheritdoc cref="IHeadersResponseBuilder.WithHeaders(IDictionary{string, string[]})"/>
public IResponseBuilder WithHeaders(IDictionary<string, string[]> headers)
{
Check.NotNull(headers, nameof(headers));
ResponseMessage.Headers = headers.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
return this;
}
/// <inheritdoc cref="IHeadersResponseBuilder.WithHeaders(IDictionary{string, WireMockList{string}})"/>
public IResponseBuilder WithHeaders(IDictionary<string, WireMockList<string>> headers)
{ {
ResponseMessage.Headers = headers; ResponseMessage.Headers = headers;
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IBodyResponseBuilder.WithBody(byte[], string, Encoding)"/>
/// The with body. public IResponseBuilder WithBody(byte[] body, string destination, Encoding encoding = null)
/// </summary>
/// <param name="body">The body.</param>
/// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
public IResponseBuilder WithBody(string body, Encoding encoding = null)
{ {
Check.NotNull(body, nameof(body)); Check.NotNull(body, nameof(body));
ResponseMessage.Body = body; ResponseMessage.BodyDestination = destination;
ResponseMessage.BodyEncoding = encoding ?? Encoding.UTF8;
switch (destination)
{
case BodyDestinationFormat.String:
var enc = encoding ?? Encoding.UTF8;
ResponseMessage.BodyAsBytes = null;
ResponseMessage.Body = enc.GetString(body);
ResponseMessage.BodyEncoding = enc;
break;
default:
ResponseMessage.BodyAsBytes = body;
ResponseMessage.BodyEncoding = null;
break;
}
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IBodyResponseBuilder.WithBodyFromFile"/>
/// The with body (AsJson object). public IResponseBuilder WithBodyFromFile(string filename, bool cache = true)
/// </summary> {
/// <param name="body">The body.</param> Check.NotNull(filename, nameof(filename));
/// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns> ResponseMessage.BodyEncoding = null;
ResponseMessage.BodyAsFileIsCached = cache;
if (cache)
{
ResponseMessage.Body = null;
ResponseMessage.BodyAsBytes = File.ReadAllBytes(filename);
ResponseMessage.BodyAsFile = null;
}
else
{
ResponseMessage.Body = null;
ResponseMessage.BodyAsBytes = null;
ResponseMessage.BodyAsFile = filename;
}
return this;
}
/// <inheritdoc cref="IBodyResponseBuilder.WithBody(string, string, Encoding)"/>
public IResponseBuilder WithBody(string body, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null)
{
Check.NotNull(body, nameof(body));
encoding = encoding ?? Encoding.UTF8;
ResponseMessage.BodyDestination = destination;
switch (destination)
{
case BodyDestinationFormat.Bytes:
ResponseMessage.Body = null;
ResponseMessage.BodyAsBytes = encoding.GetBytes(body);
ResponseMessage.BodyEncoding = encoding;
break;
default:
ResponseMessage.Body = body;
ResponseMessage.BodyAsBytes = null;
ResponseMessage.BodyEncoding = encoding;
break;
}
return this;
}
/// <inheritdoc cref="IBodyResponseBuilder.WithBodyAsJson"/>
public IResponseBuilder WithBodyAsJson(object body, Encoding encoding = null) public IResponseBuilder WithBodyAsJson(object body, Encoding encoding = null)
{ {
Check.NotNull(body, nameof(body)); Check.NotNull(body, nameof(body));
@@ -184,58 +254,43 @@ namespace WireMock.ResponseBuilders
ResponseMessage.BodyEncoding = encoding; ResponseMessage.BodyEncoding = encoding;
} }
ResponseMessage.BodyDestination = null;
ResponseMessage.Body = jsonBody; ResponseMessage.Body = jsonBody;
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IBodyResponseBuilder.WithBodyFromBase64"/>
/// The with body as base64. public IResponseBuilder WithBodyFromBase64(string bodyAsbase64, Encoding encoding = null)
/// </summary>
/// <param name="bodyAsbase64">The body asbase64.</param>
/// <param name="encoding">The Encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
public IResponseBuilder WithBodyAsBase64(string bodyAsbase64, Encoding encoding = null)
{ {
Check.NotNull(bodyAsbase64, nameof(bodyAsbase64)); Check.NotNull(bodyAsbase64, nameof(bodyAsbase64));
encoding = encoding ?? Encoding.UTF8; encoding = encoding ?? Encoding.UTF8;
ResponseMessage.BodyDestination = null;
ResponseMessage.Body = encoding.GetString(Convert.FromBase64String(bodyAsbase64)); ResponseMessage.Body = encoding.GetString(Convert.FromBase64String(bodyAsbase64));
ResponseMessage.BodyEncoding = encoding; ResponseMessage.BodyEncoding = encoding;
return this; return this;
} }
/// <summary> /// <inheritdoc cref="ITransformResponseBuilder.WithTransformer"/>
/// The with transformer.
/// </summary>
/// <returns>
/// The <see cref="IResponseBuilder"/>.
/// </returns>
public IResponseBuilder WithTransformer() public IResponseBuilder WithTransformer()
{ {
UseTransformer = true; UseTransformer = true;
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IDelayResponseBuilder.WithDelay(TimeSpan)"/>
/// The with delay.
/// </summary>
/// <param name="delay">The TimeSpan to delay.</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
public IResponseBuilder WithDelay(TimeSpan delay) public IResponseBuilder WithDelay(TimeSpan delay)
{ {
Check.Condition(delay, d => d > TimeSpan.Zero, nameof(delay)); Check.Condition(delay, d => d > TimeSpan.Zero, nameof(delay));
Delay = delay; Delay = delay;
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IDelayResponseBuilder.WithDelay(int)"/>
/// The with delay.
/// </summary>
/// <param name="milliseconds">The milliseconds to delay.</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
public IResponseBuilder WithDelay(int milliseconds) public IResponseBuilder WithDelay(int milliseconds)
{ {
return WithDelay(TimeSpan.FromMilliseconds(milliseconds)); return WithDelay(TimeSpan.FromMilliseconds(milliseconds));
@@ -253,6 +308,7 @@ namespace WireMock.ResponseBuilders
ProxyUrl = proxyUrl; ProxyUrl = proxyUrl;
X509Certificate2ThumbprintOrSubjectName = clientX509Certificate2ThumbprintOrSubjectName; X509Certificate2ThumbprintOrSubjectName = clientX509Certificate2ThumbprintOrSubjectName;
_httpClientForProxy = HttpClientHelper.CreateHttpClient(clientX509Certificate2ThumbprintOrSubjectName);
return this; return this;
} }
@@ -266,14 +322,17 @@ namespace WireMock.ResponseBuilders
Check.NotNull(requestMessage, nameof(requestMessage)); Check.NotNull(requestMessage, nameof(requestMessage));
if (Delay != null) if (Delay != null)
{
await Task.Delay(Delay.Value); await Task.Delay(Delay.Value);
}
if (ProxyUrl != null) if (ProxyUrl != null && _httpClientForProxy != null)
{ {
var requestUri = new Uri(requestMessage.Url); var requestUri = new Uri(requestMessage.Url);
var proxyUri = new Uri(ProxyUrl); var proxyUri = new Uri(ProxyUrl);
var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery); var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery);
return await HttpClientHelper.SendAsync(requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri, X509Certificate2ThumbprintOrSubjectName);
return await HttpClientHelper.SendAsync(_httpClientForProxy, requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri);
} }
if (UseTransformer) if (UseTransformer)

View File

@@ -1,6 +1,9 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using WireMock.Util;
using WireMock.Validation;
namespace WireMock namespace WireMock
{ {
@@ -12,7 +15,7 @@ namespace WireMock
/// <summary> /// <summary>
/// Gets the headers. /// Gets the headers.
/// </summary> /// </summary>
public IDictionary<string, string> Headers { get; set; } = new ConcurrentDictionary<string, string>(); public IDictionary<string, WireMockList<string>> Headers { get; set; } = new ConcurrentDictionary<string, WireMockList<string>>();
/// <summary> /// <summary>
/// Gets or sets the status code. /// Gets or sets the status code.
@@ -25,27 +28,59 @@ namespace WireMock
public string BodyOriginal { get; set; } public string BodyOriginal { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body. /// Gets or sets the body destination (SameAsSource, String or Bytes).
/// </summary>
public string BodyDestination { get; set; }
/// <summary>
/// Gets or sets the body as a string.
/// </summary> /// </summary>
public string Body { get; set; } public string Body { get; set; }
/// <summary>
/// Gets or sets the body as bytes.
/// </summary>
public byte[] BodyAsBytes { get; set; }
/// <summary>
/// Gets or sets the body as a file.
/// </summary>
public string BodyAsFile { get; set; }
/// <summary>
/// Is the body as file cached?
/// </summary>
public bool? BodyAsFileIsCached { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body encoding. /// Gets or sets the body encoding.
/// </summary> /// </summary>
public Encoding BodyEncoding { get; set; } = new UTF8Encoding(false); public Encoding BodyEncoding { get; set; } = new UTF8Encoding(false);
/// <summary> /// <summary>
/// The add header. /// Adds the header.
/// </summary> /// </summary>
/// <param name="name"> /// <param name="name">The name.</param>
/// The name. /// <param name="value">The value.</param>
/// </param>
/// <param name="value">
/// The value.
/// </param>
public void AddHeader(string name, string value) public void AddHeader(string name, string value)
{ {
Headers.Add(name, value); Headers.Add(name, new WireMockList<string>(value));
}
/// <summary>
/// Adds the header.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="values">The values.</param>
public void AddHeader(string name, params string[] values)
{
Check.NotEmpty(values, nameof(values));
var newHeaderValues = Headers.TryGetValue(name, out WireMockList<string> existingValues)
? values.Union(existingValues).ToArray()
: values;
Headers[name] = new WireMockList<string>(newHeaderValues);
} }
} }
} }

View File

@@ -8,6 +8,7 @@ using WireMock.Matchers;
using WireMock.Matchers.Request; using WireMock.Matchers.Request;
using WireMock.RequestBuilders; using WireMock.RequestBuilders;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
using WireMock.Util;
namespace WireMock.Serialization namespace WireMock.Serialization
{ {
@@ -78,7 +79,7 @@ namespace WireMock.Serialization
Funcs = Map(pm.Funcs) Funcs = Map(pm.Funcs)
}).ToList() : null, }).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, Matcher = bodyMatcher != null ? Map(bodyMatcher.Matcher) : null,
Func = bodyMatcher != null ? Map(bodyMatcher.Func) : null, Func = bodyMatcher != null ? Map(bodyMatcher.Func) : null,
@@ -95,31 +96,58 @@ namespace WireMock.Serialization
{ {
mappingModel.Response.StatusCode = null; mappingModel.Response.StatusCode = null;
mappingModel.Response.Headers = null; mappingModel.Response.Headers = null;
mappingModel.Response.BodyDestination = null;
mappingModel.Response.Body = null; mappingModel.Response.Body = null;
mappingModel.Response.BodyAsBytes = null;
mappingModel.Response.BodyAsFile = null;
mappingModel.Response.BodyAsFileIsCached = null;
mappingModel.Response.UseTransformer = false; mappingModel.Response.UseTransformer = false;
mappingModel.Response.BodyEncoding = null; mappingModel.Response.BodyEncoding = null;
mappingModel.Response.ProxyUrl = response.ProxyUrl; mappingModel.Response.ProxyUrl = response.ProxyUrl;
} }
else else
{ {
mappingModel.Response.BodyDestination = response.ResponseMessage.BodyDestination;
mappingModel.Response.StatusCode = response.ResponseMessage.StatusCode; mappingModel.Response.StatusCode = response.ResponseMessage.StatusCode;
mappingModel.Response.Headers = response.ResponseMessage.Headers; mappingModel.Response.Headers = Map(response.ResponseMessage.Headers);
mappingModel.Response.Body = response.ResponseMessage.Body; mappingModel.Response.Body = response.ResponseMessage.Body;
mappingModel.Response.BodyAsBytes = response.ResponseMessage.BodyAsBytes;
mappingModel.Response.BodyAsFile = response.ResponseMessage.BodyAsFile;
mappingModel.Response.BodyAsFileIsCached = response.ResponseMessage.BodyAsFileIsCached;
mappingModel.Response.UseTransformer = response.UseTransformer; 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, EncodingName = response.ResponseMessage.BodyEncoding.EncodingName,
CodePage = response.ResponseMessage.BodyEncoding.CodePage, CodePage = response.ResponseMessage.BodyEncoding.CodePage,
WebName = response.ResponseMessage.BodyEncoding.WebName WebName = response.ResponseMessage.BodyEncoding.WebName
} };
: null; }
} }
return mappingModel; return mappingModel;
} }
public static MatcherModel[] Map([CanBeNull] IEnumerable<IMatcher> matchers) private static IDictionary<string, object> Map(IDictionary<string, WireMockList<string>> dictionary)
{
if (dictionary == null)
{
return null;
}
var newDictionary = new Dictionary<string, object>();
foreach (var entry in dictionary)
{
object value = entry.Value.Count == 1 ? (object)entry.Value.ToString() : entry.Value;
newDictionary.Add(entry.Key, value);
}
return newDictionary;
}
private static MatcherModel[] Map([CanBeNull] IEnumerable<IMatcher> matchers)
{ {
if (matchers == null || !matchers.Any()) if (matchers == null || !matchers.Any())
return null; return null;
@@ -127,7 +155,7 @@ namespace WireMock.Serialization
return matchers.Select(Map).Where(x => x != null).ToArray(); return matchers.Select(Map).Where(x => x != null).ToArray();
} }
public static MatcherModel Map([CanBeNull] IMatcher matcher) private static MatcherModel Map([CanBeNull] IMatcher matcher)
{ {
if (matcher == null) if (matcher == null)
return null; return null;
@@ -142,7 +170,7 @@ namespace WireMock.Serialization
}; };
} }
public static string[] Map<T>([CanBeNull] IEnumerable<Func<T, bool>> funcs) private static string[] Map<T>([CanBeNull] IEnumerable<Func<T, bool>> funcs)
{ {
if (funcs == null || !funcs.Any()) if (funcs == null || !funcs.Any())
return null; return null;
@@ -150,7 +178,7 @@ namespace WireMock.Serialization
return funcs.Select(Map).Where(x => x != null).ToArray(); return funcs.Select(Map).Where(x => x != null).ToArray();
} }
public static string Map<T>([CanBeNull] Func<T, bool> func) private static string Map<T>([CanBeNull] Func<T, bool> func)
{ {
return func?.ToString(); return func?.ToString();
} }

View File

@@ -2,23 +2,24 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Newtonsoft.Json; using Newtonsoft.Json;
using WireMock.Admin.Mappings; using WireMock.Admin.Mappings;
using WireMock.Admin.Requests; using WireMock.Admin.Requests;
using WireMock.Admin.Settings; using WireMock.Admin.Settings;
using WireMock.Http;
using WireMock.Logging; using WireMock.Logging;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.Matchers.Request; using WireMock.Matchers.Request;
using WireMock.RequestBuilders; using WireMock.RequestBuilders;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
using WireMock.Serialization;
using WireMock.Settings;
using WireMock.Util; using WireMock.Util;
using WireMock.Validation; using WireMock.Validation;
using WireMock.Http;
using System.Threading.Tasks;
using WireMock.Settings;
using WireMock.Serialization;
namespace WireMock.Server namespace WireMock.Server
{ {
@@ -28,6 +29,7 @@ namespace WireMock.Server
public partial class FluentMockServer public partial class FluentMockServer
{ {
private static readonly string AdminMappingsFolder = Path.Combine("__admin", "mappings"); private static readonly string AdminMappingsFolder = Path.Combine("__admin", "mappings");
private const string ContentTypeJson = "application/json";
private const string AdminMappings = "/__admin/mappings"; private const string AdminMappings = "/__admin/mappings";
private const string AdminRequests = "/__admin/requests"; private const string AdminRequests = "/__admin/requests";
private const string AdminSettings = "/__admin/settings"; private const string AdminSettings = "/__admin/settings";
@@ -85,12 +87,12 @@ namespace WireMock.Server
{ {
// __admin/settings // __admin/settings
Given(Request.Create().WithPath(AdminSettings).UsingGet()).RespondWith(new DynamicResponseProvider(SettingsGet)); 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 // __admin/mappings
Given(Request.Create().WithPath(AdminMappings).UsingGet()).RespondWith(new DynamicResponseProvider(MappingsGet)); 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)); Given(Request.Create().WithPath(AdminMappings).UsingDelete()).RespondWith(new DynamicResponseProvider(MappingsDelete));
// __admin/mappings/reset // __admin/mappings/reset
@@ -98,7 +100,7 @@ namespace WireMock.Server
// __admin/mappings/{guid} // __admin/mappings/{guid}
Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingGet()).RespondWith(new DynamicResponseProvider(MappingGet)); 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)); Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingDelete()).RespondWith(new DynamicResponseProvider(MappingDelete));
// __admin/mappings/save // __admin/mappings/save
@@ -129,23 +131,31 @@ namespace WireMock.Server
} }
#region Proxy and Record #region Proxy and Record
private void InitProxyAndRecord(ProxyAndRecordSettings settings) private HttpClient _httpClientForProxy;
private void InitProxyAndRecord(IProxyAndRecordSettings settings)
{ {
_httpClientForProxy = HttpClientHelper.CreateHttpClient(settings.X509Certificate2ThumbprintOrSubjectName);
Given(Request.Create().WithPath("/*").UsingAnyVerb()).RespondWith(new ProxyAsyncResponseProvider(ProxyAndRecordAsync, settings)); 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 requestUri = new Uri(requestMessage.Url);
var proxyUri = new Uri(settings.Url); var proxyUri = new Uri(settings.Url);
var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery); var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery);
var responseMessage = await HttpClientHelper.SendAsync(requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri, settings.X509Certificate2ThumbprintOrSubjectName); var responseMessage = await HttpClientHelper.SendAsync(_httpClientForProxy, requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri);
if (settings.SaveMapping) if (settings.SaveMapping)
{ {
var mapping = ToMapping(requestMessage, responseMessage); var mapping = ToMapping(requestMessage, responseMessage);
SaveMappingToFile(mapping); _options.Mappings.Add(mapping);
if (settings.SaveMappingToFile)
{
SaveMappingToFile(mapping);
}
} }
return responseMessage; return responseMessage;
@@ -153,11 +163,20 @@ namespace WireMock.Server
private Mapping ToMapping(RequestMessage requestMessage, ResponseMessage responseMessage) private Mapping ToMapping(RequestMessage requestMessage, ResponseMessage responseMessage)
{ {
var request = (Request)Request.Create(); var request = Request.Create();
request.WithPath(requestMessage.Path); request.WithPath(requestMessage.Path);
request.UsingVerb(requestMessage.Method); 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); return new Mapping(Guid.NewGuid(), string.Empty, request, response, 0, null, null, null);
} }
@@ -412,8 +431,12 @@ namespace WireMock.Server
Response = new LogResponseModel Response = new LogResponseModel
{ {
StatusCode = logEntry.ResponseMessage.StatusCode, StatusCode = logEntry.ResponseMessage.StatusCode,
BodyDestination = logEntry.ResponseMessage.BodyDestination,
Body = logEntry.ResponseMessage.Body, Body = logEntry.ResponseMessage.Body,
BodyAsBytes = logEntry.ResponseMessage.BodyAsBytes,
BodyOriginal = logEntry.ResponseMessage.BodyOriginal, BodyOriginal = logEntry.ResponseMessage.BodyOriginal,
BodyAsFile = logEntry.ResponseMessage.BodyAsFile,
BodyAsFileIsCached = logEntry.ResponseMessage.BodyAsFileIsCached,
Headers = logEntry.ResponseMessage.Headers, Headers = logEntry.ResponseMessage.Headers,
BodyEncoding = logEntry.ResponseMessage.BodyEncoding != null ? new EncodingModel BodyEncoding = logEntry.ResponseMessage.BodyEncoding != null ? new EncodingModel
{ {
@@ -464,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); return ToJson(result);
} }
@@ -515,12 +538,16 @@ namespace WireMock.Server
{ {
string path = requestModel.Path as string; string path = requestModel.Path as string;
if (path != null) if (path != null)
{
requestBuilder = requestBuilder.WithPath(path); requestBuilder = requestBuilder.WithPath(path);
}
else else
{ {
var pathModel = JsonUtils.ParseJTokenToObject<PathModel>(requestModel.Path); var pathModel = JsonUtils.ParseJTokenToObject<PathModel>(requestModel.Path);
if (pathModel?.Matchers != null) if (pathModel?.Matchers != null)
{
requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(MappingConverter.Map).ToArray()); requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(MappingConverter.Map).ToArray());
}
} }
} }
@@ -528,17 +555,23 @@ namespace WireMock.Server
{ {
string url = requestModel.Url as string; string url = requestModel.Url as string;
if (url != null) if (url != null)
{
requestBuilder = requestBuilder.WithUrl(url); requestBuilder = requestBuilder.WithUrl(url);
}
else else
{ {
var urlModel = JsonUtils.ParseJTokenToObject<UrlModel>(requestModel.Url); var urlModel = JsonUtils.ParseJTokenToObject<UrlModel>(requestModel.Url);
if (urlModel?.Matchers != null) if (urlModel?.Matchers != null)
{
requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(MappingConverter.Map).ToArray()); requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(MappingConverter.Map).ToArray());
}
} }
} }
if (requestModel.Methods != null) if (requestModel.Methods != null)
{
requestBuilder = requestBuilder.UsingVerb(requestModel.Methods); requestBuilder = requestBuilder.UsingVerb(requestModel.Methods);
}
if (requestModel.Headers != null) if (requestModel.Headers != null)
{ {
@@ -599,7 +632,12 @@ namespace WireMock.Server
if (responseModel.Headers != null) if (responseModel.Headers != null)
{ {
responseBuilder = responseBuilder.WithHeaders(responseModel.Headers); foreach (var entry in responseModel.Headers)
{
responseBuilder = entry.Value is string value ?
responseBuilder.WithHeader(entry.Key, value) :
responseBuilder.WithHeader(entry.Key, JsonUtils.ParseJTokenToObject<string[]>(entry.Value));
}
} }
else if (responseModel.HeadersRaw != null) else if (responseModel.HeadersRaw != null)
{ {
@@ -612,17 +650,21 @@ namespace WireMock.Server
} }
} }
if (responseModel.Body != null) if (responseModel.BodyAsBytes != null)
{ {
responseBuilder = responseBuilder.WithBody(responseModel.Body, ToEncoding(responseModel.BodyEncoding)); responseBuilder = responseBuilder.WithBody(responseModel.BodyAsBytes, responseModel.BodyDestination, ToEncoding(responseModel.BodyEncoding));
}
else if (responseModel.Body != null)
{
responseBuilder = responseBuilder.WithBody(responseModel.Body, responseModel.BodyDestination, ToEncoding(responseModel.BodyEncoding));
} }
else if (responseModel.BodyAsJson != null) else if (responseModel.BodyAsJson != null)
{ {
responseBuilder = responseBuilder.WithBodyAsJson(responseModel.BodyAsJson, ToEncoding(responseModel.BodyEncoding)); responseBuilder = responseBuilder.WithBodyAsJson(responseModel.BodyAsJson, ToEncoding(responseModel.BodyEncoding));
} }
else if (responseModel.BodyAsBase64 != null) else if (responseModel.BodyFromBase64 != null)
{ {
responseBuilder = responseBuilder.WithBodyAsBase64(responseModel.BodyAsBase64, ToEncoding(responseModel.BodyEncoding)); responseBuilder = responseBuilder.WithBodyFromBase64(responseModel.BodyFromBase64, ToEncoding(responseModel.BodyEncoding));
} }
if (responseModel.UseTransformer) if (responseModel.UseTransformer)
@@ -639,7 +681,7 @@ namespace WireMock.Server
{ {
Body = JsonConvert.SerializeObject(result, _settings), Body = JsonConvert.SerializeObject(result, _settings),
StatusCode = 200, StatusCode = 200,
Headers = new Dictionary<string, string> { { "Content-Type", "application/json" } } Headers = new Dictionary<string, WireMockList<string>> { { "Content-Type", new WireMockList<string>("application/json") } }
}; };
} }

View File

@@ -25,12 +25,15 @@ namespace WireMock.Server
private readonly IOwinSelfHost _httpServer; private readonly IOwinSelfHost _httpServer;
private readonly WireMockMiddlewareOptions _options = new WireMockMiddlewareOptions(); private readonly WireMockMiddlewareOptions _options = new WireMockMiddlewareOptions();
/// <summary>
/// Gets a value indicating whether this server is started.
/// </summary>
[PublicAPI]
public bool IsStarted { get; }
/// <summary> /// <summary>
/// Gets the ports. /// Gets the ports.
/// </summary> /// </summary>
/// <value>
/// The ports.
/// </value>
[PublicAPI] [PublicAPI]
public List<int> Ports { get; } public List<int> Ports { get; }
@@ -59,7 +62,7 @@ namespace WireMock.Server
/// <param name="settings">The FluentMockServerSettings.</param> /// <param name="settings">The FluentMockServerSettings.</param>
/// <returns>The <see cref="FluentMockServer"/>.</returns> /// <returns>The <see cref="FluentMockServer"/>.</returns>
[PublicAPI] [PublicAPI]
public static FluentMockServer Start(FluentMockServerSettings settings) public static FluentMockServer Start(IFluentMockServerSettings settings)
{ {
Check.NotNull(settings, nameof(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) if (settings.Urls != null)
{ {
@@ -162,11 +165,16 @@ namespace WireMock.Server
Urls = new[] { (settings.UseSSL == true ? "https" : "http") + "://localhost:" + port + "/" }; Urls = new[] { (settings.UseSSL == true ? "https" : "http") + "://localhost:" + port + "/" };
} }
_options.PreWireMockMiddlewareInit = settings.PreWireMockMiddlewareInit;
_options.PostWireMockMiddlewareInit = settings.PostWireMockMiddlewareInit;
#if NETSTANDARD #if NETSTANDARD
_httpServer = new AspNetCoreSelfHost(_options, Urls); _httpServer = new AspNetCoreSelfHost(_options, Urls);
#else #else
_httpServer = new OwinSelfHost(_options, Urls); _httpServer = new OwinSelfHost(_options, Urls);
#endif #endif
IsStarted = _httpServer.IsStarted;
Ports = _httpServer.Ports; Ports = _httpServer.Ports;
_httpServer.StartAsync(); _httpServer.StartAsync();
@@ -360,18 +368,18 @@ namespace WireMock.Server
return new RespondWithAProvider(RegisterMapping, requestMatcher); return new RespondWithAProvider(RegisterMapping, requestMatcher);
} }
/// <summary>
/// The register mapping.
/// </summary>
/// <param name="mapping">
/// The mapping.
/// </param>
private void RegisterMapping(Mapping mapping) private void RegisterMapping(Mapping mapping)
{ {
// Check a mapping exists with the same GUID, if so, remove it first. // Check a mapping exists with the same Guid, if so, replace it.
DeleteMapping(mapping.Guid); var existingMapping = _options.Mappings.FirstOrDefault(m => m.Guid == mapping.Guid);
if (existingMapping != null)
_options.Mappings.Add(mapping); {
_options.Mappings[_options.Mappings.IndexOf(existingMapping)] = mapping;
}
else
{
_options.Mappings.Add(mapping);
}
} }
} }
} }

View File

@@ -1,83 +1,68 @@
namespace WireMock.Settings using System;
using JetBrains.Annotations;
namespace WireMock.Settings
{ {
/// <summary> /// <summary>
/// FluentMockServerSettings /// FluentMockServerSettings
/// </summary> /// </summary>
public class FluentMockServerSettings public class FluentMockServerSettings : IFluentMockServerSettings
{ {
/// <summary> /// <inheritdoc cref="IFluentMockServerSettings.Port"/>
/// Gets or sets the port. [PublicAPI]
/// </summary>
/// <value>
/// The port.
/// </value>
public int? Port { get; set; } public int? Port { get; set; }
/// <summary> /// <inheritdoc cref="IFluentMockServerSettings.UseSSL"/>
/// Gets or sets the use SSL. [PublicAPI]
/// </summary>
/// <value>
/// The use SSL.
/// </value>
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
public bool? UseSSL { get; set; } public bool? UseSSL { get; set; }
/// <summary> /// <inheritdoc cref="IFluentMockServerSettings.StartAdminInterface"/>
/// Gets or sets the start admin interface. [PublicAPI]
/// </summary>
/// <value>
/// The start admin interface.
/// </value>
public bool? StartAdminInterface { get; set; } public bool? StartAdminInterface { get; set; }
/// <summary> /// <inheritdoc cref="IFluentMockServerSettings.ReadStaticMappings"/>
/// Gets or sets if the static mappings should be read at startup. [PublicAPI]
/// </summary>
/// <value>true/false</value>
public bool? ReadStaticMappings { get; set; } public bool? ReadStaticMappings { get; set; }
/// <summary> /// <inheritdoc cref="IFluentMockServerSettings.ProxyAndRecordSettings"/>
/// Gets or sets if the server should record and save requests and responses. [PublicAPI]
/// </summary> public IProxyAndRecordSettings ProxyAndRecordSettings { get; set; }
/// <value>true/false</value>
public ProxyAndRecordSettings ProxyAndRecordSettings { get; set; }
/// <summary> /// <inheritdoc cref="IFluentMockServerSettings.Urls"/>
/// Gets or sets the urls. [PublicAPI]
/// </summary>
/// <value>
/// The urls.
/// </value>
public string[] Urls { get; set; } public string[] Urls { get; set; }
/// <summary> /// <inheritdoc cref="IFluentMockServerSettings.StartTimeout"/>
/// StartTimeout [PublicAPI]
/// </summary>
public int StartTimeout { get; set; } = 10000; public int StartTimeout { get; set; } = 10000;
/// <summary> /// <inheritdoc cref="IFluentMockServerSettings.AllowPartialMapping"/>
/// Allow Partial Mapping (default set to false). [PublicAPI]
/// </summary>
public bool? AllowPartialMapping { get; set; } public bool? AllowPartialMapping { get; set; }
/// <summary> /// <inheritdoc cref="IFluentMockServerSettings.AdminUsername"/>
/// The username needed for __admin access. [PublicAPI]
/// </summary>
public string AdminUsername { get; set; } public string AdminUsername { get; set; }
/// <summary> /// <inheritdoc cref="IFluentMockServerSettings.AdminPassword"/>
/// The password needed for __admin access. [PublicAPI]
/// </summary>
public string AdminPassword { get; set; } public string AdminPassword { get; set; }
/// <summary> /// <inheritdoc cref="IFluentMockServerSettings.RequestLogExpirationDuration"/>
/// The RequestLog expiration in hours (optional). [PublicAPI]
/// </summary>
public int? RequestLogExpirationDuration { get; set; } public int? RequestLogExpirationDuration { get; set; }
/// <summary> /// <inheritdoc cref="IFluentMockServerSettings.MaxRequestLogCount"/>
/// The MaxRequestLog count (optional). [PublicAPI]
/// </summary>
public int? MaxRequestLogCount { get; set; } public int? MaxRequestLogCount { get; set; }
/// <inheritdoc cref="IFluentMockServerSettings.PreWireMockMiddlewareInit"/>
[PublicAPI]
public Action<object> PreWireMockMiddlewareInit { get; set; }
/// <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> /// <summary>
/// RecordAndSaveSettings /// RecordAndSaveSettings
/// </summary> /// </summary>
public class ProxyAndRecordSettings public class ProxyAndRecordSettings : IProxyAndRecordSettings
{ {
/// <summary> /// <inheritdoc cref="IProxyAndRecordSettings.Url"/>
/// The URL to proxy. [PublicAPI]
/// </summary>
public string Url { get; set; } public string Url { get; set; }
/// <summary> /// <inheritdoc cref="IProxyAndRecordSettings.SaveMapping"/>
/// Save the mapping for each request/response. [PublicAPI]
/// </summary>
public bool SaveMapping { get; set; } = true; public bool SaveMapping { get; set; } = true;
/// <summary> /// <inheritdoc cref="IProxyAndRecordSettings.SaveMappingToFile"/>
/// The clientCertificate thumbprint or subject name fragment to use. Example thumbprint : "D2DBF135A8D06ACCD0E1FAD9BFB28678DF7A9818". Example subject name: "www.google.com"" [PublicAPI]
/// </summary> public bool SaveMappingToFile { get; set; } = true;
/// <inheritdoc cref="IProxyAndRecordSettings.X509Certificate2ThumbprintOrSubjectName"/>
[PublicAPI]
public string X509Certificate2ThumbprintOrSubjectName { get; set; } public string X509Certificate2ThumbprintOrSubjectName { get; set; }
} }
} }

View File

@@ -1,5 +1,7 @@
using HandlebarsDotNet; using System.Collections.Generic;
using System.Collections.Generic; using System.Linq;
using HandlebarsDotNet;
using WireMock.Util;
namespace WireMock.Transformers namespace WireMock.Transformers
{ {
@@ -16,13 +18,16 @@ namespace WireMock.Transformers
responseMessage.Body = templateBody(template); responseMessage.Body = templateBody(template);
// Headers // Headers
var newHeaders = new Dictionary<string, string>(); var newHeaders = new Dictionary<string, WireMockList<string>>();
foreach (var header in original.Headers) foreach (var header in original.Headers)
{ {
var templateHeaderKey = Handlebars.Compile(header.Key); var templateHeaderKey = Handlebars.Compile(header.Key);
var templateHeaderValue = Handlebars.Compile(header.Value); var templateHeaderValues = header.Value
.Select(Handlebars.Compile)
.Select(func => func(template))
.ToArray();
newHeaders.Add(templateHeaderKey(template), templateHeaderValue(template)); newHeaders.Add(templateHeaderKey(template), new WireMockList<string>(templateHeaderValues));
} }
responseMessage.Headers = newHeaders; responseMessage.Headers = newHeaders;

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

@@ -7,13 +7,12 @@ namespace WireMock.Util
public static T ParseJTokenToObject<T>(object value) public static T ParseJTokenToObject<T>(object value)
{ {
if (value == null) if (value == null)
{
return default(T); return default(T);
}
JToken token = value as JToken; var token = value as JToken;
if (token == null) return token == null ? default(T) : token.ToObject<T>();
return default(T);
return token.ToObject<T>();
} }
} }
} }

View File

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

View File

@@ -36,9 +36,6 @@ namespace WireMock.Util
/// <summary> /// <summary>
/// Returns a <see cref="string" /> that represents this instance. /// Returns a <see cref="string" /> that represents this instance.
/// </summary> /// </summary>
/// <returns>
/// A <see cref="string" /> that represents this instance.
/// </returns>
public override string ToString() public override string ToString()
{ {
if (this != null && this.Any()) if (this != null && this.Any())

View File

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

@@ -0,0 +1,188 @@
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using NFluent;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using Xunit;
namespace WireMock.Net.Tests
{
public partial class FluentMockServerTests
{
private FluentMockServer _serverForProxyForwarding;
[Fact]
public async Task FluentMockServer_Should_proxy_responses()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy("http://www.google.com"));
// when
var result = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/search?q=test");
// then
Check.That(result).Contains("google");
}
[Fact]
public async Task FluentMockServer_Should_preserve_content_header_in_proxied_request()
{
// 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("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("stringContent");
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_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()
{
// given
_serverForProxyForwarding = FluentMockServer.Start();
_serverForProxyForwarding
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create()
.WithBody("body")
.WithHeader("Content-Type", "text/plain"));
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy(_serverForProxyForwarding.Urls[0]));
// when
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(_server.Urls[0])
};
var response = await new HttpClient().SendAsync(requestMessage);
// then
Check.That(await response.Content.ReadAsStringAsync()).IsEqualTo("body");
Check.That(response.Content.Headers.Contains("Content-Type")).IsTrue();
Check.That(response.Content.Headers.GetValues("Content-Type")).ContainsExactly("text/plain");
}
[Fact]
public async Task FluentMockServer_Should_change_absolute_location_header_in_proxied_response()
{
// given
_serverForProxyForwarding = FluentMockServer.Start();
_serverForProxyForwarding
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create()
.WithStatusCode(HttpStatusCode.Redirect)
.WithHeader("Location", _serverForProxyForwarding.Urls[0] + "testpath"));
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy(_serverForProxyForwarding.Urls[0]));
// when
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(_server.Urls[0])
};
var httpClientHandler = new HttpClientHandler { AllowAutoRedirect = false };
var response = await new HttpClient(httpClientHandler).SendAsync(requestMessage);
// then
Check.That(response.Headers.Contains("Location")).IsTrue();
Check.That(response.Headers.GetValues("Location")).ContainsExactly(_server.Urls[0] + "testpath");
}
[Fact]
public async Task FluentMockServer_Should_preserve_cookie_header_in_proxied_request()
{
// 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 requestUri = new Uri(_server.Urls[0]);
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = requestUri
};
var clientHandler = new HttpClientHandler();
clientHandler.CookieContainer.Add(requestUri, new Cookie("name", "value"));
await new HttpClient(clientHandler).SendAsync(requestMessage);
// then
var receivedRequest = _serverForProxyForwarding.LogEntries.First().RequestMessage;
Check.That(receivedRequest.Cookies).IsNotNull();
Check.That(receivedRequest.Cookies).ContainsPair("name", "value");
}
}
}

View File

@@ -1,417 +1,449 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using NFluent; using NFluent;
using Xunit; using WireMock.Matchers;
using WireMock.Matchers; using WireMock.RequestBuilders;
using WireMock.RequestBuilders; using WireMock.ResponseBuilders;
using WireMock.ResponseBuilders; using WireMock.Server;
using WireMock.Server; using Xunit;
namespace WireMock.Net.Tests namespace WireMock.Net.Tests
{ {
//[TestFixture] public partial class FluentMockServerTests : IDisposable
//[Timeout(5000)] {
public class FluentMockServerTests : IDisposable private FluentMockServer _server;
{
private FluentMockServer _server; // For for AppVeyor + OpenCover
private string GetCurrentFolder()
// For for AppVeyor + OpenCover {
private string GetCurrentFolder() string current = Directory.GetCurrentDirectory();
{ //if (!current.EndsWith("WireMock.Net.Tests"))
string current = Directory.GetCurrentDirectory(); // return Path.Combine(current, "test", "WireMock.Net.Tests");
//if (!current.EndsWith("WireMock.Net.Tests"))
// return Path.Combine(current, "test", "WireMock.Net.Tests"); return current;
return current;
}
[Fact]
public void FluentMockServer_StartStop()
{
var server1 = FluentMockServer.Start("http://localhost:9091/");
server1.Stop();
var server2 = FluentMockServer.Start("http://localhost:9091/");
server2.Stop();
}
[Fact]
public void FluentMockServer_ReadStaticMapping_WithNonGuidFilename()
{
var guid = Guid.Parse("04ee4872-9efd-4770-90d3-88d445265d0d");
string title = "documentdb_root_title";
_server = FluentMockServer.Start();
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings", "documentdb_root.json");
_server.ReadStaticMapping(folder);
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(1);
Check.That(mappings.First().RequestMatcher).IsNotNull();
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(guid);
Check.That(mappings.First().Title).Equals(title);
}
[Fact]
public void FluentMockServer_ReadStaticMapping_WithGuidFilename()
{
string guid = "00000002-ee28-4f29-ae63-1ac9b0802d86";
_server = FluentMockServer.Start();
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings", guid + ".json");
_server.ReadStaticMapping(folder);
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(1);
Check.That(mappings.First().RequestMatcher).IsNotNull();
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(Guid.Parse(guid));
Check.That(mappings.First().Title).IsNullOrEmpty();
}
[Fact]
public void FluentMockServer_ReadStaticMappings()
{
_server = FluentMockServer.Start();
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings");
_server.ReadStaticMappings(folder);
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
}
[Fact]
public void FluentMockServer_Admin_Mappings_Get()
{
var guid = Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05");
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/foo1").UsingGet())
.WithGuid(guid)
.RespondWith(Response.Create().WithStatusCode(201).WithBody("1"));
_server.Given(Request.Create().WithPath("/foo2").UsingGet())
.RespondWith(Response.Create().WithStatusCode(202).WithBody("2"));
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
Check.That(mappings.First().RequestMatcher).IsNotNull();
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(guid);
Check.That(mappings[1].Guid).Not.Equals(guid);
}
[Fact]
public void FluentMockServer_Admin_Mappings_Add_SameGuid()
{
var guid = Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05");
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/1").UsingGet())
.WithGuid(guid)
.RespondWith(Response.Create().WithStatusCode(500));
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(1);
Check.That(mappings.First().Guid).Equals(guid);
_server.Given(Request.Create().WithPath("/2").UsingGet())
.WithGuid(guid)
.RespondWith(Response.Create().WithStatusCode(500));
Check.That(mappings).HasSize(1);
Check.That(mappings.First().Guid).Equals(guid);
}
[Fact]
public async Task FluentMockServer_Admin_Mappings_AtPriority()
{
_server = FluentMockServer.Start();
// given
_server.Given(Request.Create().WithPath("/1").UsingGet())
.AtPriority(2)
.RespondWith(Response.Create().WithStatusCode(200));
_server.Given(Request.Create().WithPath("/1").UsingGet())
.AtPriority(1)
.RespondWith(Response.Create().WithStatusCode(400));
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
Check.That(mappings[0].Priority).Equals(2);
Check.That(mappings[1].Priority).Equals(1);
// when
var response = await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/1");
// then
Check.That((int)response.StatusCode).IsEqualTo(400);
}
[Fact]
public async Task FluentMockServer_Admin_Requests_Get()
{
// given
_server = FluentMockServer.Start();
// when
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(_server.LogEntries).HasSize(1);
var requestLogged = _server.LogEntries.First();
Check.That(requestLogged.RequestMessage.Method).IsEqualTo("get");
Check.That(requestLogged.RequestMessage.BodyAsBytes).IsEmpty();
}
[Fact]
public async Task Should_respond_to_request()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/foo")
.UsingGet())
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithBody(@"{ msg: ""Hello world!""}"));
// when
var response = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response).IsEqualTo(@"{ msg: ""Hello world!""}");
}
[Fact]
public async Task Should_respond_to_request_bodyAsBase64()
{
// given
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/foo").UsingGet()).RespondWith(Response.Create().WithBodyAsBase64("SGVsbG8gV29ybGQ/"));
// when
var response = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response).IsEqualTo("Hello World?");
}
[Fact]
public async Task Should_respond_404_for_unexpected_request()
{
// given
_server = FluentMockServer.Start();
// when
var response = await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response.StatusCode).IsEqualTo(HttpStatusCode.NotFound);
Check.That((int)response.StatusCode).IsEqualTo(404);
}
[Fact]
public async Task Should_find_a_request_satisfying_a_request_spec()
{
// given
_server = FluentMockServer.Start();
// when
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/bar");
// then
var result = _server.FindLogEntries(Request.Create().WithPath(new RegexMatcher("^/b.*"))).ToList();
Check.That(result).HasSize(1);
var requestLogged = result.First();
Check.That(requestLogged.RequestMessage.Path).IsEqualTo("/bar");
Check.That(requestLogged.RequestMessage.Url).IsEqualTo("http://localhost:" + _server.Ports[0] + "/bar");
}
[Fact]
public async Task Should_reset_requestlogs()
{
// given
_server = FluentMockServer.Start();
// when
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
_server.ResetLogEntries();
// then
Check.That(_server.LogEntries).IsEmpty();
}
[Fact]
public void Should_reset_mappings()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/foo")
.UsingGet())
.RespondWith(Response.Create()
.WithBody(@"{ msg: ""Hello world!""}"));
// when
_server.ResetMappings();
// then
Check.That(_server.Mappings).IsEmpty();
Check.ThatAsyncCode(() => new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo"))
.ThrowsAny();
}
[Fact]
public async Task Should_respond_a_redirect_without_body()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/foo")
.UsingGet())
.RespondWith(Response.Create()
.WithStatusCode(307)
.WithHeader("Location", "/bar"));
_server
.Given(Request.Create()
.WithPath("/bar")
.UsingGet())
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithBody("REDIRECT SUCCESSFUL"));
// when
var response = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response).IsEqualTo("REDIRECT SUCCESSFUL");
}
[Fact]
public async Task Should_delay_responses_for_a_given_route()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/*"))
.RespondWith(Response.Create()
.WithBody(@"{ msg: ""Hello world!""}")
.WithDelay(TimeSpan.FromMilliseconds(200)));
// when
var watch = new Stopwatch();
watch.Start();
await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
watch.Stop();
// then
Check.That(watch.ElapsedMilliseconds).IsStrictlyGreaterThan(200);
}
[Fact]
public async Task Should_delay_responses()
{
// given
_server = FluentMockServer.Start();
_server.AddGlobalProcessingDelay(TimeSpan.FromMilliseconds(200));
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithBody(@"{ msg: ""Hello world!""}"));
// when
var watch = new Stopwatch();
watch.Start();
await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
watch.Stop();
// then
Check.That(watch.ElapsedMilliseconds).IsStrictlyGreaterThan(200);
}
[Fact]
public async Task Should_proxy_responses()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy("http://www.google.com"));
// when
var result = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/search?q=test");
// then
Check.That(result).Contains("google");
}
//Leaving commented as this requires an actual certificate with password, along with a service that expects a client certificate
//[Fact]
//public async Task Should_proxy_responses_with_client_certificate()
//{
// // given
// _server = FluentMockServer.Start();
// _server
// .Given(Request.Create().WithPath("/*"))
// .RespondWith(Response.Create().WithProxy("https://server-that-expects-a-client-certificate", @"\\yourclientcertificatecontainingprivatekey.pfx", "yourclientcertificatepassword"));
// // when
// var result = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/someurl?someQuery=someValue");
// // then
// Check.That(result).Contains("google");
//}
[Fact]
public async Task FluentMockServer_Logging_SetMaxRequestLogCount()
{
// Assign
var client = new HttpClient();
// Act
_server = FluentMockServer.Start();
_server.SetMaxRequestLogCount(2);
await client.GetAsync("http://localhost:" + _server.Ports[0] + "/foo1");
await client.GetAsync("http://localhost:" + _server.Ports[0] + "/foo2");
await client.GetAsync("http://localhost:" + _server.Ports[0] + "/foo3");
// Assert
Check.That(_server.LogEntries).HasSize(2);
var requestLoggedA = _server.LogEntries.First();
Check.That(requestLoggedA.RequestMessage.Path).EndsWith("/foo2");
var requestLoggedB = _server.LogEntries.Last();
Check.That(requestLoggedB.RequestMessage.Path).EndsWith("/foo3");
} }
public void Dispose() [Fact]
{ public void FluentMockServer_StartStop()
_server?.Stop(); {
} var server1 = FluentMockServer.Start("http://localhost:9091/");
} server1.Stop();
var server2 = FluentMockServer.Start("http://localhost:9091/");
server2.Stop();
}
[Fact]
public void FluentMockServer_ReadStaticMapping_WithNonGuidFilename()
{
var guid = Guid.Parse("04ee4872-9efd-4770-90d3-88d445265d0d");
string title = "documentdb_root_title";
_server = FluentMockServer.Start();
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings", "documentdb_root.json");
_server.ReadStaticMapping(folder);
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(1);
Check.That(mappings.First().RequestMatcher).IsNotNull();
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(guid);
Check.That(mappings.First().Title).Equals(title);
}
[Fact]
public void FluentMockServer_ReadStaticMapping_WithGuidFilename()
{
string guid = "00000002-ee28-4f29-ae63-1ac9b0802d86";
_server = FluentMockServer.Start();
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings", guid + ".json");
_server.ReadStaticMapping(folder);
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(1);
Check.That(mappings.First().RequestMatcher).IsNotNull();
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(Guid.Parse(guid));
Check.That(mappings.First().Title).IsNullOrEmpty();
}
[Fact]
public void FluentMockServer_ReadStaticMappings()
{
_server = FluentMockServer.Start();
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings");
_server.ReadStaticMappings(folder);
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
}
[Fact]
public void FluentMockServer_Admin_Mappings_Get()
{
var guid = Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05");
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/foo1").UsingGet())
.WithGuid(guid)
.RespondWith(Response.Create().WithStatusCode(201).WithBody("1"));
_server.Given(Request.Create().WithPath("/foo2").UsingGet())
.RespondWith(Response.Create().WithStatusCode(202).WithBody("2"));
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
Check.That(mappings.First().RequestMatcher).IsNotNull();
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(guid);
Check.That(mappings[1].Guid).Not.Equals(guid);
}
[Fact]
public void FluentMockServer_Admin_Mappings_Add_SameGuid()
{
var guid = Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05");
_server = FluentMockServer.Start();
var response1 = Response.Create().WithStatusCode(500);
_server.Given(Request.Create().UsingGet())
.WithGuid(guid)
.RespondWith(response1);
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(response2);
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]
public async Task FluentMockServer_Admin_Mappings_AtPriority()
{
_server = FluentMockServer.Start();
// given
_server.Given(Request.Create().WithPath("/1").UsingGet())
.AtPriority(2)
.RespondWith(Response.Create().WithStatusCode(200));
_server.Given(Request.Create().WithPath("/1").UsingGet())
.AtPriority(1)
.RespondWith(Response.Create().WithStatusCode(400));
var mappings = _server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
Check.That(mappings[0].Priority).Equals(2);
Check.That(mappings[1].Priority).Equals(1);
// when
var response = await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/1");
// then
Check.That((int)response.StatusCode).IsEqualTo(400);
}
[Fact]
public async Task FluentMockServer_Admin_Requests_Get()
{
// given
_server = FluentMockServer.Start();
// when
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(_server.LogEntries).HasSize(1);
var requestLogged = _server.LogEntries.First();
Check.That(requestLogged.RequestMessage.Method).IsEqualTo("get");
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()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/foo")
.UsingGet())
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithBody("Hello world!"));
// when
var response = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response).IsEqualTo("Hello world!");
}
[Fact]
public async Task FluentMockServer_Should_respond_to_request_bodyAsBase64()
{
// given
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/foo").UsingGet()).RespondWith(Response.Create().WithBodyFromBase64("SGVsbG8gV29ybGQ/"));
// when
var response = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response).IsEqualTo("Hello World?");
}
[Fact]
public async Task FluentMockServer_Should_respond_to_request_bodyAsBytes()
{
// given
_server = FluentMockServer.Start();
_server.Given(Request.Create().WithPath("/foo").UsingGet()).RespondWith(Response.Create().WithBody(new byte[] { 48, 49 }));
// when
var responseAsString = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
var responseAsBytes = await new HttpClient().GetByteArrayAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(responseAsString).IsEqualTo("01");
Check.That(responseAsBytes).ContainsExactly(new byte[] { 48, 49 });
}
[Fact]
public async Task FluentMockServer_Should_respond_404_for_unexpected_request()
{
// given
_server = FluentMockServer.Start();
// when
var response = await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response.StatusCode).IsEqualTo(HttpStatusCode.NotFound);
Check.That((int)response.StatusCode).IsEqualTo(404);
}
[Fact]
public async Task FluentMockServer_Should_find_a_request_satisfying_a_request_spec()
{
// given
_server = FluentMockServer.Start();
// when
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/bar");
// then
var result = _server.FindLogEntries(Request.Create().WithPath(new RegexMatcher("^/b.*"))).ToList();
Check.That(result).HasSize(1);
var requestLogged = result.First();
Check.That(requestLogged.RequestMessage.Path).IsEqualTo("/bar");
Check.That(requestLogged.RequestMessage.Url).IsEqualTo("http://localhost:" + _server.Ports[0] + "/bar");
}
[Fact]
public async Task FluentMockServer_Should_reset_requestlogs()
{
// given
_server = FluentMockServer.Start();
// when
await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
_server.ResetLogEntries();
// then
Check.That(_server.LogEntries).IsEmpty();
}
[Fact]
public void FluentMockServer_Should_reset_mappings()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/foo")
.UsingGet())
.RespondWith(Response.Create()
.WithBody(@"{ msg: ""Hello world!""}"));
// when
_server.ResetMappings();
// then
Check.That(_server.Mappings).IsEmpty();
Check.ThatAsyncCode(() => new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo"))
.ThrowsAny();
}
[Fact]
public async Task FluentMockServer_Should_respond_a_redirect_without_body()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/foo")
.UsingGet())
.RespondWith(Response.Create()
.WithStatusCode(307)
.WithHeader("Location", "/bar"));
_server
.Given(Request.Create()
.WithPath("/bar")
.UsingGet())
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithBody("REDIRECT SUCCESSFUL"));
// when
var response = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
// then
Check.That(response).IsEqualTo("REDIRECT SUCCESSFUL");
}
[Fact]
public async Task FluentMockServer_Should_delay_responses_for_a_given_route()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create()
.WithPath("/*"))
.RespondWith(Response.Create()
.WithBody(@"{ msg: ""Hello world!""}")
.WithDelay(TimeSpan.FromMilliseconds(200)));
// when
var watch = new Stopwatch();
watch.Start();
await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
watch.Stop();
// then
Check.That(watch.ElapsedMilliseconds).IsStrictlyGreaterThan(200);
}
[Fact]
public async Task FluentMockServer_Should_delay_responses()
{
// given
_server = FluentMockServer.Start();
_server.AddGlobalProcessingDelay(TimeSpan.FromMilliseconds(200));
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithBody(@"{ msg: ""Hello world!""}"));
// when
var watch = new Stopwatch();
watch.Start();
await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo");
watch.Stop();
// then
Check.That(watch.ElapsedMilliseconds).IsStrictlyGreaterThan(200);
}
//Leaving commented as this requires an actual certificate with password, along with a service that expects a client certificate
//[Fact]
//public async Task Should_proxy_responses_with_client_certificate()
//{
// // given
// _server = FluentMockServer.Start();
// _server
// .Given(Request.Create().WithPath("/*"))
// .RespondWith(Response.Create().WithProxy("https://server-that-expects-a-client-certificate", @"\\yourclientcertificatecontainingprivatekey.pfx", "yourclientcertificatepassword"));
// // when
// var result = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/someurl?someQuery=someValue");
// // then
// Check.That(result).Contains("google");
//}
[Fact]
public async Task FluentMockServer_Logging_SetMaxRequestLogCount()
{
// Assign
var client = new HttpClient();
// Act
_server = FluentMockServer.Start();
_server.SetMaxRequestLogCount(2);
await client.GetAsync("http://localhost:" + _server.Ports[0] + "/foo1");
await client.GetAsync("http://localhost:" + _server.Ports[0] + "/foo2");
await client.GetAsync("http://localhost:" + _server.Ports[0] + "/foo3");
// Assert
Check.That(_server.LogEntries).HasSize(2);
var requestLoggedA = _server.LogEntries.First();
Check.That(requestLoggedA.RequestMessage.Path).EndsWith("/foo2");
var requestLoggedB = _server.LogEntries.Last();
Check.That(requestLoggedB.RequestMessage.Path).EndsWith("/foo3");
}
public void Dispose()
{
_server?.Stop();
_serverForProxyForwarding?.Stop();
}
}
} }

View File

@@ -1,5 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using NFluent; using NFluent;
using WireMock.RequestBuilders; using WireMock.RequestBuilders;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
@@ -8,7 +13,7 @@ using Xunit;
namespace WireMock.Net.Tests namespace WireMock.Net.Tests
{ {
public class ObservableLogEntriesTest: IDisposable public class ObservableLogEntriesTest : IDisposable
{ {
private FluentMockServer _server; private FluentMockServer _server;
@@ -35,6 +40,42 @@ namespace WireMock.Net.Tests
Check.That(count).Equals(1); 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() public void Dispose()
{ {
_server?.Dispose(); _server?.Dispose();

View File

@@ -8,13 +8,13 @@ namespace WireMock.Net.Tests
//[TestFixture] //[TestFixture]
public class RequestMessageTests public class RequestMessageTests
{ {
private const string clientIP = "::1"; private const string ClientIp = "::1";
[Fact] [Fact]
public void Should_handle_empty_query() public void Should_handle_empty_query()
{ {
// given // given
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", clientIP); var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp);
// then // then
Check.That(request.GetParameter("not_there")).IsNull(); Check.That(request.GetParameter("not_there")).IsNull();
@@ -26,7 +26,7 @@ namespace WireMock.Net.Tests
// given // given
string bodyAsString = "whatever"; string bodyAsString = "whatever";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost?foo=bar&multi=1&multi=2"), "POST", clientIP, body, bodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost?foo=bar&multi=1&multi=2"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8);
// then // then
Check.That(request.GetParameter("foo")).Contains("bar"); Check.That(request.GetParameter("foo")).Contains("bar");

View File

@@ -1,4 +1,3 @@
using System; using System;
using NFluent; using NFluent;
using WireMock.Matchers.Request; using WireMock.Matchers.Request;

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

@@ -12,7 +12,7 @@ namespace WireMock.Net.Tests
//[TestFixture] //[TestFixture]
public partial class RequestTests public partial class RequestTests
{ {
private const string clientIP = "::1"; private const string ClientIp = "::1";
[Fact] [Fact]
public void Should_specify_requests_matching_given_path() public void Should_specify_requests_matching_given_path()
@@ -21,7 +21,7 @@ namespace WireMock.Net.Tests
var spec = Request.Create().WithPath("/foo"); var spec = Request.Create().WithPath("/foo");
// when // when
var request = new RequestMessage(new Uri("http://localhost/foo"), "blabla", clientIP); var request = new RequestMessage(new Uri("http://localhost/foo"), "blabla", ClientIp);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -33,8 +33,8 @@ namespace WireMock.Net.Tests
{ {
var requestBuilder = Request.Create().WithPath("/x1", "/x2"); var requestBuilder = Request.Create().WithPath("/x1", "/x2");
var request1 = new RequestMessage(new Uri("http://localhost/x1"), "blabla", clientIP); var request1 = new RequestMessage(new Uri("http://localhost/x1"), "blabla", ClientIp);
var request2 = new RequestMessage(new Uri("http://localhost/x2"), "blabla", clientIP); var request2 = new RequestMessage(new Uri("http://localhost/x2"), "blabla", ClientIp);
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
Check.That(requestBuilder.GetMatchingScore(request1, requestMatchResult)).IsEqualTo(1.0); Check.That(requestBuilder.GetMatchingScore(request1, requestMatchResult)).IsEqualTo(1.0);
@@ -48,7 +48,7 @@ namespace WireMock.Net.Tests
var spec = Request.Create().WithPath(url => url.EndsWith("/foo")); var spec = Request.Create().WithPath(url => url.EndsWith("/foo"));
// when // when
var request = new RequestMessage(new Uri("http://localhost/foo"), "blabla", clientIP); var request = new RequestMessage(new Uri("http://localhost/foo"), "blabla", ClientIp);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -62,7 +62,7 @@ namespace WireMock.Net.Tests
var spec = Request.Create().WithPath(new RegexMatcher("^/foo")); var spec = Request.Create().WithPath(new RegexMatcher("^/foo"));
// when // when
var request = new RequestMessage(new Uri("http://localhost/foo/bar"), "blabla", clientIP); var request = new RequestMessage(new Uri("http://localhost/foo/bar"), "blabla", ClientIp);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -76,107 +76,7 @@ namespace WireMock.Net.Tests
var spec = Request.Create().WithPath("/foo"); var spec = Request.Create().WithPath("/foo");
// when // when
var request = new RequestMessage(new Uri("http://localhost/bar"), "blabla", clientIP); var request = new RequestMessage(new Uri("http://localhost/bar"), "blabla", ClientIp);
// then
var requestMatchResult = new RequestMatchResult();
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 // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -190,7 +90,7 @@ namespace WireMock.Net.Tests
var spec = Request.Create().WithPath("/bar").UsingPut(); var spec = Request.Create().WithPath("/bar").UsingPut();
// when // when
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", clientIP); var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -206,7 +106,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "whatever"; string bodyAsString = "whatever";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); 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", "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 // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -222,7 +122,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "whatever"; string bodyAsString = "whatever";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); 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", "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 // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -238,7 +138,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "whatever"; string bodyAsString = "whatever";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); 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", "ABC" } }); var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8, new Dictionary<string, string[]> { { "X-toto", new[] { "ABC" } } });
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -254,7 +154,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "whatever"; string bodyAsString = "whatever";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); 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", "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 // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -268,7 +168,7 @@ namespace WireMock.Net.Tests
var spec = Request.Create().UsingAnyVerb().WithCookie("session", "a*"); var spec = Request.Create().UsingAnyVerb().WithCookie("session", "a*");
// when // when
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", clientIP, null, null, null, null, new Dictionary<string, string> { { "session", "abc" } }); var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, null, null, null, null, new Dictionary<string, string> { { "session", "abc" } });
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -284,7 +184,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "Hello world!"; string bodyAsString = "Hello world!";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", clientIP, body, bodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -300,7 +200,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "cat"; string bodyAsString = "cat";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", clientIP, body, bodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -316,7 +216,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "cat"; string bodyAsString = "cat";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", clientIP, body, bodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -332,7 +232,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "caR"; string bodyAsString = "caR";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", clientIP, body, bodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -348,7 +248,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "The car drives in the street."; string bodyAsString = "The car drives in the street.";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", clientIP, body, bodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -364,7 +264,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "Hello"; string bodyAsString = "Hello";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", clientIP, body, bodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -380,7 +280,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "Hello world!"; string bodyAsString = "Hello world!";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); 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", "tatata" } }); var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8, new Dictionary<string, string[]> { { "X-toto", new[] { "tatata" } } });
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -396,7 +296,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "Hello world!"; string bodyAsString = "Hello world!";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", clientIP, body, bodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -417,7 +317,7 @@ namespace WireMock.Net.Tests
<todo-item id='a3'>xyz</todo-item> <todo-item id='a3'>xyz</todo-item>
</todo-list>"; </todo-list>";
byte[] body = Encoding.UTF8.GetBytes(xmlBodyAsString); byte[] body = Encoding.UTF8.GetBytes(xmlBodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", clientIP, body, xmlBodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, xmlBodyAsString, Encoding.UTF8);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -438,7 +338,7 @@ namespace WireMock.Net.Tests
<todo-item id='a3'>xyz</todo-item> <todo-item id='a3'>xyz</todo-item>
</todo-list>"; </todo-list>";
byte[] body = Encoding.UTF8.GetBytes(xmlBodyAsString); byte[] body = Encoding.UTF8.GetBytes(xmlBodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", clientIP, body, xmlBodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, xmlBodyAsString, Encoding.UTF8);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -454,7 +354,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "{ \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"Wiremock\" } ] }"; string bodyAsString = "{ \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"Wiremock\" } ] }";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", clientIP, body, bodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -470,7 +370,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "{ \"things\": { \"name\": \"Wiremock\" } }"; string bodyAsString = "{ \"things\": { \"name\": \"Wiremock\" } }";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", clientIP, body, bodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -486,7 +386,7 @@ namespace WireMock.Net.Tests
// when // when
string bodyAsString = "xxx"; string bodyAsString = "xxx";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); 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", "tatata" } }); var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8, new Dictionary<string, string[]> { { "X-toto", new[] { "tata" } } });
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -500,7 +400,7 @@ namespace WireMock.Net.Tests
var spec = Request.Create().WithParam("bar", "1", "2"); var spec = Request.Create().WithParam("bar", "1", "2");
// when // when
var request = new RequestMessage(new Uri("http://localhost/foo?bar=1&bar=2"), "PUT", clientIP); var request = new RequestMessage(new Uri("http://localhost/foo?bar=1&bar=2"), "PUT", ClientIp);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -514,7 +414,7 @@ namespace WireMock.Net.Tests
var spec = Request.Create().WithParam("bar"); var spec = Request.Create().WithParam("bar");
// when // when
var request = new RequestMessage(new Uri("http://localhost/foo?bar"), "PUT", clientIP); var request = new RequestMessage(new Uri("http://localhost/foo?bar"), "PUT", ClientIp);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -528,7 +428,7 @@ namespace WireMock.Net.Tests
var spec = Request.Create().UsingAnyVerb().WithParam(p => p.ContainsKey("bar")); var spec = Request.Create().UsingAnyVerb().WithParam(p => p.ContainsKey("bar"));
// when // when
var request = new RequestMessage(new Uri("http://localhost/foo?bar=1&bar=2"), "PUT", clientIP); var request = new RequestMessage(new Uri("http://localhost/foo?bar=1&bar=2"), "PUT", ClientIp);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
@@ -542,7 +442,7 @@ namespace WireMock.Net.Tests
var spec = Request.Create().WithParam("bar", "1"); var spec = Request.Create().WithParam("bar", "1");
// when // when
var request = new RequestMessage(new Uri("http://localhost/test=7"), "PUT", clientIP); var request = new RequestMessage(new Uri("http://localhost/test=7"), "PUT", ClientIp);
// then // then
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();

View File

@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using NFluent;
using WireMock.ResponseBuilders;
using Xunit;
namespace WireMock.Net.Tests
{
public partial class ResponseTests
{
[Fact]
public async Task Response_ProvideResponse_Handlebars_UrlPathVerb()
{
// given
string bodyAsString = "abc";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8);
var response = Response.Create()
.WithBody("test {{request.url}} {{request.path}} {{request.method}}")
.WithTransformer();
// act
var responseMessage = await response.ProvideResponseAsync(request);
// then
Check.That(responseMessage.Body).Equals("test http://localhost/foo /foo post");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_Query()
{
// given
string bodyAsString = "abc";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo?a=1&a=2&b=5"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8);
var response = Response.Create()
.WithBody("test keya={{request.query.a}} idx={{request.query.a.[0]}} idx={{request.query.a.[1]}} keyb={{request.query.b}}")
.WithTransformer();
// act
var responseMessage = await response.ProvideResponseAsync(request);
// then
Check.That(responseMessage.Body).Equals("test keya=1 idx=1 idx=2 keyb=5");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_Header()
{
// given
string bodyAsString = "abc";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8, new Dictionary<string, string[]> { { "Content-Type", new[] { "text/plain" } } });
var response = Response.Create().WithHeader("x", "{{request.headers.Content-Type}}").WithBody("test").WithTransformer();
// act
var responseMessage = await response.ProvideResponseAsync(request);
// then
Check.That(responseMessage.Body).Equals("test");
Check.That(responseMessage.Headers).ContainsKey("x");
Check.That(responseMessage.Headers["x"]).ContainsExactly("text/plain");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_Headers()
{
// given
string bodyAsString = "abc";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8, new Dictionary<string, string[]> { { "Content-Type", new[] { "text/plain" } } });
var response = Response.Create().WithHeader("x", "{{request.headers.Content-Type}}", "{{request.url}}").WithBody("test").WithTransformer();
// act
var responseMessage = await response.ProvideResponseAsync(request);
// then
Check.That(responseMessage.Body).Equals("test");
Check.That(responseMessage.Headers).ContainsKey("x");
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

@@ -1,83 +1,63 @@
using System; using System;
using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using NFluent; using NFluent;
using Xunit;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
using Xunit;
namespace WireMock.Net.Tests namespace WireMock.Net.Tests
{ {
//[TestFixture] public partial class ResponseTests
public class ResponseTests
{ {
private const string clientIP = "::1"; private const string ClientIp = "::1";
[Fact] [Fact]
public async Task Response_ProvideResponse_Handlebars_UrlPathVerb() public async Task Response_ProvideResponse_WithBody_Bytes_Encoding_Destination_String()
{ {
// given // given
string bodyAsString = "abc"; string bodyAsString = "abc";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", clientIP, body, bodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8);
var response = Response.Create() var response = Response.Create().WithBody(new byte[] { 48, 49 }, BodyDestinationFormat.String, Encoding.ASCII);
.WithBody("test {{request.url}} {{request.path}} {{request.method}}")
.WithTransformer();
// act // act
var responseMessage = await response.ProvideResponseAsync(request); var responseMessage = await response.ProvideResponseAsync(request);
// then // then
Check.That(responseMessage.Body).Equals("test http://localhost/foo /foo post"); Check.That(responseMessage.Body).Equals("01");
Check.That(responseMessage.BodyAsBytes).IsNull();
Check.That(responseMessage.BodyEncoding).Equals(Encoding.ASCII);
} }
[Fact] [Fact]
public async Task Response_ProvideResponse_Handlebars_Query() public async Task Response_ProvideResponse_WithBody_Bytes_Encoding_Destination_Bytes()
{ {
// given // given
string bodyAsString = "abc"; string bodyAsString = "abc";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo?a=1&a=2&b=5"), "POST", clientIP, body, bodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8);
var response = Response.Create() var response = Response.Create().WithBody(new byte[] { 48, 49 }, BodyDestinationFormat.SameAsSource, Encoding.ASCII);
.WithBody("test keya={{request.query.a}} idx={{request.query.a.[0]}} idx={{request.query.a.[1]}} keyb={{request.query.b}}")
.WithTransformer();
// act // act
var responseMessage = await response.ProvideResponseAsync(request); var responseMessage = await response.ProvideResponseAsync(request);
// then // then
Check.That(responseMessage.Body).Equals("test keya=1 idx=1 idx=2 keyb=5"); Check.That(responseMessage.BodyAsBytes).ContainsExactly(new byte[] { 48, 49 });
Check.That(responseMessage.Body).IsNull();
Check.That(responseMessage.BodyEncoding).IsNull();
} }
[Fact] [Fact]
public async Task Response_ProvideResponse_Handlebars_Headers() public async Task Response_ProvideResponse_WithBody_String_Encoding()
{ {
// given // given
string bodyAsString = "abc"; string bodyAsString = "abc";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", clientIP, body, bodyAsString, Encoding.UTF8, new Dictionary<string, string> { { "Content-Type", "text/plain" } }); var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8);
var response = Response.Create().WithHeader("x", "{{request.headers.Content-Type}}").WithBody("test").WithTransformer(); var response = Response.Create().WithBody("test", null, Encoding.ASCII);
// act
var responseMessage = await response.ProvideResponseAsync(request);
// then
Check.That(responseMessage.Body).Equals("test");
Check.That(responseMessage.Headers).Contains(new KeyValuePair<string, string>("x", "text/plain"));
}
[Fact]
public async Task Response_ProvideResponse_Encoding_Body()
{
// given
string bodyAsString = "abc";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", clientIP, body, bodyAsString, Encoding.UTF8);
var response = Response.Create().WithBody("test", Encoding.ASCII);
// act // act
var responseMessage = await response.ProvideResponseAsync(request); var responseMessage = await response.ProvideResponseAsync(request);
@@ -88,12 +68,12 @@ namespace WireMock.Net.Tests
} }
[Fact] [Fact]
public async Task Response_ProvideResponse_Encoding_JsonBody() public async Task Response_ProvideResponse_WithBody_Object_Encoding()
{ {
// given // given
string bodyAsString = "abc"; string bodyAsString = "abc";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString); byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", clientIP, body, bodyAsString, Encoding.UTF8); var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", ClientIp, body, bodyAsString, Encoding.UTF8);
var response = Response.Create().WithBodyAsJson(new { value = "test" }, Encoding.ASCII); var response = Response.Create().WithBodyAsJson(new { value = "test" }, Encoding.ASCII);

View File

@@ -7,7 +7,6 @@ using WireMock.RequestBuilders;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
using WireMock.Server; using WireMock.Server;
using Xunit; using Xunit;
using Xunit.Abstractions;
namespace WireMock.Net.Tests namespace WireMock.Net.Tests
{ {

View File

@@ -16,12 +16,12 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="Microsoft.Owin.Host.HttpListener" Version="3.1.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="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="NFluent" Version="2.0.0" /> <PackageReference Include="NFluent" Version="2.0.0" />
<PackageReference Include="OpenCover" Version="4.6.519" /> <PackageReference Include="OpenCover" Version="4.6.519" />
<PackageReference Include="ReportGenerator" Version="2.5.11" /> <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="System.Threading" Version="4.3.0" />
<PackageReference Include="xunit" Version="2.3.0-beta1-build3642" /> <PackageReference Include="xunit" Version="2.3.0-beta1-build3642" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0-beta1-build1309" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.3.0-beta1-build1309" />