Compare commits

...

45 Commits
1.3.6 ... 1.4.0

Author SHA1 Message Date
Stef Heyenrath
73e73cebb7 1.4.0 2021-01-12 15:58:37 +00:00
Stef Heyenrath
92923a12ae Move CSharpCodeMatcher to a new project (#548)
* matcher

* wip

* fix

* <VersionPrefix>1.4.0</VersionPrefix>

* .

* x

* ?

* netstandard2.1

* {}

* test

* Fix: Assembly with same name is already loaded

* _format file

* AssemblyFile = $"WireMock.CodeHelper.Class{Guid.NewGuid()}"

* AssemblyFile = $"WireMock.CodeHelper.Class{Guid.NewGuid().ToString().Replace("-", "")}"

* GC

* x

* remove load ex

* ret

* readme

* no GC

* GetImplementationTypeByInterface

* ``

* PluginLoader

* type
2021-01-12 16:56:03 +01:00
Stef Heyenrath
d4da8dc15d 1.3.10 2020-12-23 07:50:01 +00:00
Stef Heyenrath
f104b24f66 Update comment for SaveMappingToFile (#553) 2020-12-23 08:46:24 +01:00
Stef Heyenrath
a228cdcb7c Do not save "admin" mappings when running in Proxy - mode (#561)
* wip

* .

* .
2020-12-23 08:46:07 +01:00
Stef Heyenrath
fae27f9dc7 Add more tests for Proxy with Authorization (#555)
* WireMockServer_Proxy_Should_preserve_Authorization_header_in_proxied_request

* !admin

* x

* .
2020-12-16 22:14:53 +01:00
Stef Heyenrath
fa08d0e617 1.3.9 2020-12-08 08:38:53 +00:00
Stef Heyenrath
65e7dbfbd3 [Obsolete("This class will be moved to a separate NuGet package 'WireMock.Net.Matchers.CSharpCode'")] (#551) 2020-12-08 09:32:33 +01:00
Stef Heyenrath
35565f6aa8 WithProxy(...) also use all proxy settings (#550) 2020-12-08 08:21:00 +01:00
Stef Heyenrath
04d55b00a7 NuGet build use: windows-2019 2020-12-03 09:07:44 +00:00
Stef Heyenrath
63f2715db3 1.3.8 2020-12-03 08:40:13 +00:00
Stef Heyenrath
3dfee689b5 Fix Proxying with SSL and NetCoreApp3.1 (#547)
* Fix Proxying with SSL and NetCoreApp3.1

* add test

* ServicePointManager.ServerCertificateValidationCallback = (message, cert, chain, errors) => true;

* dotnet dev-certs https

* x

* .
2020-12-03 09:36:42 +01:00
Stef Heyenrath
933bd7d046 remove branch name from "SonarCloudPrepare" 2020-12-02 22:39:04 +01:00
Stef Heyenrath
fd62c52669 Update README.md 2020-11-30 16:28:41 +01:00
Stef Heyenrath
db2caadf70 Fix SonarCloud OpenCover (coverlet-coverage) (#545) 2020-11-30 15:48:17 +01:00
Stef Heyenrath
3e0c6cce5f RUN_SONAR_CMD_OPENCOVER 2020-11-28 19:14:56 +01:00
Stef Heyenrath
8861b8a3f0 s 2020-11-28 19:12:06 +01:00
Stef Heyenrath
2363cc1311 Build - arguments: '--configuration Debug --framework netcoreapp3.1' 2020-11-28 18:59:00 +01:00
Stef Heyenrath
1f99834ae3 - task: DotNetCoreCLI@2 2020-11-28 18:51:50 +01:00
Stef Heyenrath
8659b352a3 VSTest@2 2020-11-28 18:48:54 +01:00
Stef Heyenrath
8f3aa12086 Codecov 2020-11-28 18:30:17 +01:00
Stef Heyenrath
9b64dbcae3 RUN_SONAR_CMD 2020-11-28 18:20:34 +01:00
Stef Heyenrath
33fd383612 projects: './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj' 2020-11-28 18:02:15 +01:00
Stef Heyenrath
01d8dc6b86 SonarCloud 2020-11-28 17:57:08 +01:00
Stef Heyenrath
6af127e9f2 RUN_TEST_NET452 2020-11-28 15:27:32 +01:00
Stef Heyenrath
a3629a4147 using var 2020-11-28 15:21:18 +01:00
Stef Heyenrath
e222a0a9c3 netcoreapp3.1 (with coverage) 2020-11-28 15:15:01 +01:00
Stef Heyenrath
00a6fec7b4 wiremock-net 2020-11-28 15:04:00 +01:00
Stef Heyenrath
47b1d1ab43 SonarCloud - WireMock-Net_WireMock.Net 2020-11-28 14:54:05 +01:00
Stef Heyenrath
e7b6e12855 SonarCloud - WireMock-Net_WireMock.Net 2020-11-28 14:51:53 +01:00
Stef Heyenrath
94e5e99207 Use JDK11 by default 2020-11-28 13:50:52 +01:00
Stef Heyenrath
37a89cbaa4 **\ 2020-11-28 13:33:44 +01:00
Stef Heyenrath
323d0f9dae coverage.netcoreapp3.1.opencover.xml 2020-11-28 13:21:17 +01:00
Stef Heyenrath
16e939746a <TargetFrameworks>net452;netcoreapp3.1</TargetFrameworks> 2020-11-28 13:11:20 +01:00
Stef Heyenrath
85dabc7638 BUILD_SOLUTION_AS_DEBUG 2020-11-28 13:10:33 +01:00
Stef Heyenrath
f0bddf0604 SonarCloud 2020-11-28 13:00:04 +01:00
Stef Heyenrath
3829a5a7f9 Use Java 11 in Azure Pipelines (needed for SonarCloud) (#544)
* Install Java 11

* jdkSourceOption: 'PreInstalled'

* nuget

* 1.12.3
2020-11-28 12:13:56 +01:00
Stef Heyenrath
37d81aabad .NET 5 (#543) 2020-11-28 11:03:55 +01:00
Stef Heyenrath
d1afba5058 Update README.md 2020-11-25 23:32:11 +01:00
Stef Heyenrath
bc19a1c6b9 changelog 2020-11-25 14:38:52 +00:00
Stef Heyenrath
45713eb0d9 Create dotnet-wiremock tool (#542)
* dotnet tool

* .

* c

* x

* ### As a dotnet tool

* help

* v
2020-11-25 15:36:01 +01:00
Stef Heyenrath
4fb455a1b1 Add more info to IWireMockServer 2020-11-24 11:15:52 +00:00
Stef Heyenrath
bde3126f81 Add wiki link 2020-11-21 09:16:34 +01:00
Stef Heyenrath
0d7de47848 1.3.7 2020-11-17 17:50:45 +00:00
Gleb Osokin
548fc2c2c8 Support for partial JSON matching (#539)
* support Json partial match with JsonPartialMatcher

* fix erroneous filenames

* add newline

* newlines fix

* add JsonPartialMatcher to mapper

* curly braces for ifs

* fix JToken type comparison

* more test cases

* rename AreEqual -> IsMatch + more test cases

* separate tests for JPath matcher values

Co-authored-by: Gleb Osokin <gleb.osokin@avira.com>
2020-11-17 17:18:58 +01:00
91 changed files with 3148 additions and 1381 deletions

3
.gitignore vendored
View File

@@ -252,3 +252,6 @@ paket-files/
*.sln.iml
./report/coverlet/
/test/WireMock.Net.Tests/coverage.opencover.xml
/test/WireMock.Net.Tests/coverage.netcoreapp3.1.opencover.xml
/test/WireMock.Net.Tests/coverage.net5.0.opencover.xml

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
</PropertyGroup>
<PropertyGroup>
<VersionPrefix>1.3.6</VersionPrefix>
<VersionPrefix>1.4.0</VersionPrefix>
<PackageReleaseNotes>See CHANGELOG.md</PackageReleaseNotes>
<PackageIconUrl>https://raw.githubusercontent.com/WireMock-Net/WireMock.Net/master/WireMock.Net-Logo.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>

View File

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

View File

@@ -1,6 +1,8 @@
# WireMock.Net
A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) which mimics the functionality from the JAVA based [WireMock.org](http://WireMock.org).
For more info, see also this WIKI page: [What is WireMock.Net](https://github.com/WireMock-Net/WireMock.Net/wiki/What-Is-WireMock.Net).
## Key Features
* HTTP response stubbing, matchable on URL/Path, headers, cookies and body content patterns
* Library can be used in unit tests and integration tests
@@ -10,7 +12,7 @@ A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) w
* Per-request conditional proxying
* Stateful behaviour simulation
* Response templating / transformation using Handlebars and extensions
* Can be used locally or in CI/CD scenarios.
* Can be used locally or in CI/CD scenarios
## Info
| | |
@@ -21,9 +23,9 @@ A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) w
| | |
| ***Quality*** | &nbsp; |
| &nbsp;&nbsp;**Build Azure** | [![Build Status Azure](https://stef.visualstudio.com/WireMock.Net/_apis/build/status/WireMock.Net)](https://stef.visualstudio.com/WireMock.Net/_build/latest?definitionId=7) |
| &nbsp;&nbsp;**Quality** | [![Sonar Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=wiremock&metric=alert_status)](https://sonarcloud.io/project/issues?id=wiremock) [![CodeFactor](https://www.codefactor.io/repository/github/wiremock-net/wiremock.net/badge)](https://www.codefactor.io/repository/github/wiremock-net/wiremock.net) |
| &nbsp;&nbsp;**Sonar Bugs** | [![Sonar Bugs](https://sonarcloud.io/api/project_badges/measure?project=wiremock&metric=bugs)](https://sonarcloud.io/project/issues?id=wiremock&resolved=false&types=BUG) [![Sonar Code Smells](https://sonarcloud.io/api/project_badges/measure?project=wiremock&metric=code_smells)](https://sonarcloud.io/project/issues?id=wiremock&resolved=false&types=CODE_SMELL) |
| &nbsp;&nbsp;**Coverage** | [![Sonar Coverage](https://sonarcloud.io/api/project_badges/measure?project=wiremock&metric=coverage)](https://sonarcloud.io/component_measures?id=wiremock&metric=coverage) [![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/WireMock-Net/WireMock.Net/badge.svg?branch=master)](https://coveralls.io/github/WireMock-Net/WireMock.Net?branch=master) |
| &nbsp;&nbsp;**Quality** | [![Sonar Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=WireMock-Net_WireMock.Net&metric=alert_status)](https://sonarcloud.io/project/issues?id=WireMock-Net_WireMock.Net) [![CodeFactor](https://www.codefactor.io/repository/github/wiremock-net/wiremock.net/badge)](https://www.codefactor.io/repository/github/wiremock-net/wiremock.net) |
| &nbsp;&nbsp;**Sonar Bugs** | [![Sonar Bugs](https://sonarcloud.io/api/project_badges/measure?project=WireMock-Net_WireMock.Net&metric=bugs)](https://sonarcloud.io/project/issues?id=WireMock-Net_WireMock.Net&resolved=false&types=BUG) [![Sonar Code Smells](https://sonarcloud.io/api/project_badges/measure?project=WireMock-Net_WireMock.Net&metric=code_smells)](https://sonarcloud.io/project/issues?id=WireMock-Net_WireMock.Net&resolved=false&types=CODE_SMELL) |
| &nbsp;&nbsp;**Coverage** | [![Sonar Coverage](https://sonarcloud.io/api/project_badges/measure?project=WireMock-Net_WireMock.Net&metric=coverage)](https://sonarcloud.io/component_measures?id=WireMock-Net_WireMock.Net&metric=coverage) [![codecov](https://codecov.io/gh/WireMock-Net/WireMock.Net/branch/master/graph/badge.svg)](https://codecov.io/gh/WireMock-Net/WireMock.Net)|
### NuGet packages
@@ -33,6 +35,7 @@ A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) w
| &nbsp;&nbsp;**WireMock.Net.StandAlone** | [![NuGet Badge WireMock.Net](https://buildstats.info/nuget/WireMock.Net.StandAlone)](https://www.nuget.org/packages/WireMock.Net.StandAlone) | [![MyGet Badge WireMock.Net.StandAlone](https://buildstats.info/myget/wiremock-net/WireMock.Net.StandAlone?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.StandAlone)
| &nbsp;&nbsp;**WireMock.Net.FluentAssertions** | [![NuGet Badge WireMock.Net.FluentAssertions](https://buildstats.info/nuget/WireMock.Net.FluentAssertions)](https://www.nuget.org/packages/WireMock.Net.FluentAssertions) | [![MyGet Badge WireMock.Net.FluentAssertions](https://buildstats.info/myget/wiremock-net/WireMock.Net.FluentAssertions?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.FluentAssertions)
| &nbsp;&nbsp;**WireMock.Net.RestClient** | [![NuGet Badge WireMock.Net.RestClient](https://buildstats.info/nuget/WireMock.Net.RestClient)](https://www.nuget.org/packages/WireMock.Net.RestClient) | [![MyGet Badge WireMock.Net.RestClient](https://buildstats.info/myget/wiremock-net/WireMock.Net.RestClient?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.RestClient)
| &nbsp;&nbsp;**WireMock.Net.Matchers.CSharpCode** | [![NuGet Badge WireMock.Net.Matchers.CSharpCode](https://buildstats.info/nuget/WireMock.Net.Matchers.CSharpCode)](https://www.nuget.org/packages/WireMock.Net.Matchers.CSharpCode) | [![MyGet Badge WireMock.Net.Matchers.CSharpCode](https://buildstats.info/myget/wiremock-net/WireMock.Net.Matchers.CSharpCode?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Matchers.CSharpCode)
## Development
For the supported frameworks and build information, see [this](https://github.com/WireMock-Net/WireMock.Net/wiki/Development-Information) page.
@@ -57,9 +60,13 @@ WireMock.Net can be used in several ways:
You can use your favorite test framework and use WireMock within your tests, see
[Wiki : UnitTesting](https://github.com/StefH/WireMock.Net/wiki/Using-WireMock-in-UnitTests).
### As a dotnet tool
It's simple to install WireMock.Net as (global) dotnet tool, see [Wiki : dotnet tool](https://github.com/StefH/WireMock.Net/wiki/WireMock-as-dotnet-tool).
### As standalone process / console application
This is quite straight forward to launch a mock server within a console application, see [Wiki : Standalone Process](https://github.com/StefH/WireMock.Net/wiki/WireMock-as-a-standalone-process).
### As a Windows Service
You can also run WireMock.Net as a Windows Service, follow this [WireMock-as-a-Windows-Service](https://github.com/WireMock-Net/WireMock.Net/wiki/WireMock-as-a-Windows-Service).

View File

@@ -30,6 +30,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
CHANGELOG.md = CHANGELOG.md
Directory.Build.props = Directory.Build.props
GitHubReleaseNotes.txt = GitHubReleaseNotes.txt
nuget.config = nuget.config
README.md = README.md
EndProjectSection
EndProject
@@ -71,7 +72,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.WebApplication
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.WebApplication.NETCore3", "examples\WireMock.Net.WebApplication.NETCore3\WireMock.Net.WebApplication.NETCore3.csproj", "{E1C56967-3DC7-46CB-A1DF-B13167A0D9D4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Console.NETCoreApp3WithCertificate", "examples\WireMock.Net.Console.NETCoreApp3WithCertificate\WireMock.Net.Console.NETCoreApp3WithCertificate.csproj", "{925E421A-1B3F-4202-B48F-734743573A4B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.NETCoreApp3WithCertificate", "examples\WireMock.Net.Console.NETCoreApp3WithCertificate\WireMock.Net.Console.NETCoreApp3WithCertificate.csproj", "{925E421A-1B3F-4202-B48F-734743573A4B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-WireMock", "src\dotnet-WireMock.Net\dotnet-WireMock.csproj", "{40BF24B5-12E6-4610-9489-138798632E28}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.NET5", "examples\WireMock.Net.Console.NET5\WireMock.Net.Console.NET5.csproj", "{3F8CF0AE-5F24-4A54-89E7-A3EE829DB5F8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Matchers.CSharpCode", "src\WireMock.Net.Matchers.CSharpCode\WireMock.Net.Matchers.CSharpCode.csproj", "{6437CE56-8AB9-4D6D-90F1-70CC5BBE1572}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -179,6 +186,18 @@ Global
{925E421A-1B3F-4202-B48F-734743573A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{925E421A-1B3F-4202-B48F-734743573A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{925E421A-1B3F-4202-B48F-734743573A4B}.Release|Any CPU.Build.0 = Release|Any CPU
{40BF24B5-12E6-4610-9489-138798632E28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{40BF24B5-12E6-4610-9489-138798632E28}.Debug|Any CPU.Build.0 = Debug|Any CPU
{40BF24B5-12E6-4610-9489-138798632E28}.Release|Any CPU.ActiveCfg = Release|Any CPU
{40BF24B5-12E6-4610-9489-138798632E28}.Release|Any CPU.Build.0 = Release|Any CPU
{3F8CF0AE-5F24-4A54-89E7-A3EE829DB5F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F8CF0AE-5F24-4A54-89E7-A3EE829DB5F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F8CF0AE-5F24-4A54-89E7-A3EE829DB5F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F8CF0AE-5F24-4A54-89E7-A3EE829DB5F8}.Release|Any CPU.Build.0 = Release|Any CPU
{6437CE56-8AB9-4D6D-90F1-70CC5BBE1572}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6437CE56-8AB9-4D6D-90F1-70CC5BBE1572}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6437CE56-8AB9-4D6D-90F1-70CC5BBE1572}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6437CE56-8AB9-4D6D-90F1-70CC5BBE1572}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -209,6 +228,9 @@ Global
{6F38CB3A-6DA1-408A-AECD-E434523C2838} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{E1C56967-3DC7-46CB-A1DF-B13167A0D9D4} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{925E421A-1B3F-4202-B48F-734743573A4B} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{40BF24B5-12E6-4610-9489-138798632E28} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{3F8CF0AE-5F24-4A54-89E7-A3EE829DB5F8} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{6437CE56-8AB9-4D6D-90F1-70CC5BBE1572} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}

View File

@@ -1,5 +1,5 @@
pool:
vmImage: 'Ubuntu 16.04'
vmImage: 'Ubuntu-latest'
variables:
buildConfiguration: 'Release'

View File

@@ -1,91 +1,136 @@
pool:
vmImage: 'windows-2019'
variables:
Prerelease: 'ci'
buildId: "1$(Build.BuildId)"
buildProjects: '**/src/**/*.csproj'
steps:
# Print buildId
- script: |
echo "BuildId = $(buildId)"
displayName: 'Print buildId'
jobs:
- job: Linux_Build_Test_SonarCloud
# Install Tools (SonarScanner)
- script: |
dotnet tool install --global dotnet-sonarscanner
displayName: Install Tools (SonarScanner)
pool:
vmImage: 'Ubuntu-latest'
# Begin SonarScanner
# See also
# - https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools, else you get this error: `Since you just installed the .NET Core SDK, you will need to reopen the Command Prompt window before running the tool you installed.`
# - https://github.com/dotnet/cli/issues/8368
# - https://github.com/Microsoft/vsts-tasks/issues/8291
#
- script: |
%USERPROFILE%\.dotnet\tools\dotnet-sonarscanner begin /k:"wiremock" /o:"stefh-github" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.login="$(SONAR_TOKEN)" /v:"$(buildId)" /d:sonar.cs.opencover.reportsPaths="**\coverage.opencover.xml"
displayName: Begin SonarScanner
condition: and(succeeded(), eq(variables['RUN_SONAR'], 'yes'))
steps:
- script: |
echo "BuildId = $(buildId)"
displayName: 'Print buildId'
# Build source, tests and run tests for net452 and netcoreapp3.1 (with coverage)
- script: |
dotnet test ./test/WireMock.Net.Tests/WireMock.Net.Tests.csproj --configuration Debug --framework net452
dotnet test ./test/WireMock.Net.Tests/WireMock.Net.Tests.csproj --configuration Debug --framework netcoreapp3.1 --logger trx /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
displayName: 'Build source, tests and run tests for net452 and netcoreapp3.1 (with coverage)'
- task: PowerShell@2
displayName: "Use JDK11 by default"
inputs:
targetType: 'inline'
script: |
$jdkPath = $env:JAVA_HOME_11_X64
Write-Host "##vso[task.setvariable variable=JAVA_HOME]$jdkPath"
# End SonarScanner
- script: |
%USERPROFILE%\.dotnet\tools\dotnet-sonarscanner end /d:sonar.login="$(SONAR_TOKEN)"
displayName: End SonarScanner
condition: and(succeeded(), eq(variables['RUN_SONAR'], 'yes'))
- script: |
dotnet dev-certs https --trust || true
displayName: 'dotnet dev-certs https'
- task: SonarCloudPrepare@1
displayName: 'Prepare analysis on SonarCloud'
inputs:
SonarCloud: SonarCloud
organization: wiremock-net
projectKey: 'WireMock-Net_WireMock.Net'
projectName: 'WireMock.Net'
extraProperties: |
sonar.cs.opencover.reportsPaths=**/coverage.netcoreapp3.1.opencover.xml
- task: DotNetCoreCLI@2
displayName: 'Build Unit tests'
inputs:
command: 'build'
projects: './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj'
arguments: '--configuration Debug --framework netcoreapp3.1'
- task: DotNetCoreCLI@2
displayName: 'Execute Unit tests'
inputs:
command: 'test'
projects: './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj'
arguments: '--no-build --configuration Debug --framework netcoreapp3.1 --collect:"XPlat Code Coverage" --logger trx /p:CollectCoverage=true /p:CoverletOutputFormat=opencover'
- task: SonarCloudAnalyze@1
displayName: 'SonarCloud: Run Code Analysis'
- task: SonarCloudPublish@1
displayName: 'SonarCloud: Publish Quality Gate Result'
- task: whitesource.ws-bolt.bolt.wss.WhiteSource Bolt@19
displayName: 'WhiteSource Bolt'
condition: and(succeeded(), eq(variables['RUN_WHITESOURCE'], 'yes'))
- script: |
bash <(curl https://codecov.io/bash) -t $(CODECOV_TOKEN) -f ./test/WireMock.Net.Tests/coverage.netcoreapp3.1.opencover.xml
displayName: 'codecov'
- task: PublishTestResults@2
condition: and(succeeded(), eq(variables['PUBLISH_TESTRESULTS'], 'yes'))
inputs:
testRunner: VSTest
testResultsFiles: '**/*.trx'
- task: PublishBuildArtifacts@1
displayName: Publish coverage file
inputs:
PathtoPublish: '/home/vsts/work/1/s/test/WireMock.Net.Tests/coverage.netcoreapp3.1.opencover.xml'
- task: whitesource.ws-bolt.bolt.wss.WhiteSource Bolt@19
displayName: 'WhiteSource Bolt'
condition: and(succeeded(), eq(variables['RUN_WHITESOURCE'], 'yes'))
- job: Windows_Build_Test
dependsOn: Linux_Build_Test_SonarCloud
# Upload coverage to codecov.io
- script: |
%USERPROFILE%\.nuget\packages\codecov\1.10.0\tools\codecov.exe -f "./test/WireMock.Net.Tests/coverage.opencover.xml" -t $(CODECOV_TOKEN)
displayName: Upload coverage to codecov.io
pool:
vmImage: 'windows-2019'
# https://github.com/microsoft/azure-pipelines-tasks/issues/12212
- task: PublishTestResults@2
condition: and(succeeded(), eq(variables['PUBLISH_TESTRESULTS'], 'yes'))
inputs:
testRunner: VSTest
testResultsFiles: '**/*.trx'
steps:
- task: DotNetCoreCLI@2
displayName: 'Build Unit tests'
inputs:
command: 'build'
projects: './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj'
arguments: '--configuration Debug --framework netcoreapp3.1'
- task: DotNetCoreCLI@2
displayName: 'Execute Unit tests'
inputs:
command: 'test'
projects: './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj'
arguments: '--no-build --configuration Debug --framework netcoreapp3.1 --collect:"XPlat Code Coverage" --logger trx /p:CollectCoverage=true /p:CoverletOutputFormat=opencover'
- job: Windows_Release_to_MyGet
dependsOn: Windows_Build_Test
# Based on https://whereslou.com/2018/09/versioning-and-publishing-nuget-packages-automatically-using-azure-devops-pipelines/
- task: DotNetCoreCLI@2
displayName: Build Release
inputs:
command: 'build'
arguments: /p:Configuration=Release # https://github.com/MicrosoftDocs/vsts-docs/issues/1976
projects: $(buildProjects)
pool:
vmImage: 'windows-2019'
- task: DotNetCoreCLI@2
displayName: Pack
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
command: pack
configuration: 'Release'
packagesToPack: $(buildProjects)
nobuild: true
packDirectory: '$(Build.ArtifactStagingDirectory)/packages'
verbosityPack: 'normal'
steps:
- task: DotNetCoreCLI@2
displayName: Build Release
inputs:
command: 'build'
arguments: /p:Configuration=Release
projects: $(buildProjects)
- task: PublishBuildArtifacts@1
displayName: Publish Artifacts
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
# https://github.com/NuGet/Home/issues/8148
- task: DotNetCoreCLI@2
displayName: Push to MyGet
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
command: custom
custom: nuget
arguments: push $(Build.ArtifactStagingDirectory)\packages\*.nupkg -n true -s https://www.myget.org/F/wiremock-net/api/v3/index.json -k $(MyGetKey)
- task: DotNetCoreCLI@2
displayName: Pack
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
command: pack
configuration: 'Release'
packagesToPack: $(buildProjects)
nobuild: true
packDirectory: '$(Build.ArtifactStagingDirectory)/packages'
verbosityPack: 'normal'
- task: PublishBuildArtifacts@1
displayName: Publish Artifacts
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
- task: DotNetCoreCLI@2
displayName: Push to MyGet
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
command: custom
custom: nuget
arguments: push $(Build.ArtifactStagingDirectory)\packages\*.nupkg -n true -s https://www.myget.org/F/wiremock-net/api/v3/index.json -k $(MyGetKey)

View File

@@ -1,5 +1,5 @@
pool:
vmImage: 'vs2017-win2016'
vmImage: 'windows-2019'
variables:
Prerelease: ''

View File

@@ -0,0 +1,55 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\WireMock.Net.Console.Net452.Classic\MainApp.cs" Link="MainApp.cs" />
<Compile Include="..\WireMock.Net.Console.Net452.Classic\CustomFileSystemFileHandler.cs" Link="CustomFileSystemFileHandler.cs" />
<Compile Include="..\WireMock.Net.Console.NETCoreApp\Program.cs" Link="Program.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="__admin\mappings\*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Compile Remove="__admin\mappings\1.cs" />
</ItemGroup>
<ItemGroup>
<None Remove="__admin\mappings\array.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
<PackageReference Include="Handlebars.Net.Helpers" Version="1.1.0" />
<PackageReference Include="log4net" Version="2.0.8" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<!--<PackageReference Include="Microsoft.CodeAnalysis.Scripting.Common" Version="3.4.0" />-->
</ItemGroup>
<ItemGroup>
<None Update="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="nlog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<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>
<None Update="__admin\mappings\MyXmlResponse.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1 @@
// C# Hello

View File

@@ -0,0 +1,22 @@
{
"Request": {
"Path": {
"Matchers": [
{
"Name": "WildcardMatcher",
"Pattern": "/static/mapping"
}
]
},
"Methods": [
"get"
]
},
"Response": {
"BodyAsJson": { "body": "static mapping" },
"Headers": {
"Content-Type": "application/json",
"Test-X": [ "test 1", "test 2" ]
}
}
}

View File

@@ -0,0 +1,29 @@
{
"Guid": "791a3f31-6946-4ce7-8e6f-0237c7443275",
"Title": "",
"Priority": 0,
"Request": {
"Path": "/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, 27 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

@@ -0,0 +1,19 @@
{
"Guid": "873d495f-940e-4b86-a1f4-4f0fc7be8b8b",
"Priority": 4,
"Request": {
"Path": {},
"Methods": [
"get"
]
},
"Response": {
"StatusCode": 200,
"BodyDestination": "SameAsSource",
"Body": "NO PATH OR URL",
"UseTransformer": false,
"Headers": {
"Content-Type": "application/json"
}
}
}

View File

@@ -0,0 +1,22 @@
{
"Request": {
"Path": {
"Matchers": [
{
"Name": "WildcardMatcher",
"Pattern": "/bodyasfilexmltest",
"IgnoreCase": false
}
]
},
"Methods": [
"get"
]
},
"Response": {
"StatusCode": 200,
"Headers": {"Content-Type": "application/xml"},
"BodyAsFile": "MyXmlResponse.xml",
"UseTransformer": false
}
}

View File

@@ -0,0 +1,3 @@
<xml>
<hello>world</hello>
</xml>

View File

@@ -0,0 +1,46 @@
[
{
"Title": "1",
"Request": {
"Path": {
"Matchers": [
{
"Name": "WildcardMatcher",
"Pattern": "/mappings_static_1"
}
]
},
"Methods": [
"get"
]
},
"Response": {
"BodyAsJson": { "result": "mappings static_1" },
"Headers": {
"Content-Type": "application/json"
}
}
},
{
"Title": "2",
"Request": {
"Path": {
"Matchers": [
{
"Name": "WildcardMatcher",
"Pattern": "/mappings_static_2"
}
]
},
"Methods": [
"get"
]
},
"Response": {
"BodyAsJson": { "result": "mappings static_2" },
"Headers": {
"Content-Type": "application/json"
}
}
}
]

View File

@@ -3,6 +3,7 @@ using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using WireMock.Logging;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
@@ -14,9 +15,6 @@ namespace WireMock.Net.Console.Proxy.NETCoreApp2
{
static void Main(string[] args)
{
RunTestDifferentPort().Wait(20000); // prints "1"
RunTestDifferentPort().Wait(20000); // prints "1"
var server = WireMockServer.Start(new WireMockServerSettings
{
Urls = new[] { "http://localhost:9091", "https://localhost:9443" },
@@ -29,34 +27,18 @@ namespace WireMock.Net.Console.Proxy.NETCoreApp2
SaveMapping = true,
SaveMappingToFile = false,
ExcludedHeaders = new[] { "dnt", "Content-Length" }
}
},
Logger= new WireMockConsoleLogger()
});
server.LogEntriesChanged += (sender, eventRecordArgs) =>
{
System.Console.WriteLine(JsonConvert.SerializeObject(eventRecordArgs.NewItems, Formatting.Indented));
};
//server.LogEntriesChanged += (sender, eventRecordArgs) =>
//{
// System.Console.WriteLine(JsonConvert.SerializeObject(eventRecordArgs.NewItems, Formatting.Indented));
//};
System.Console.WriteLine("Press any key to stop the server");
System.Console.ReadKey();
server.Stop();
}
private static async Task RunTestDifferentPort()
{
var server = WireMockServer.Start();
server.Given(Request.Create().WithPath("/").UsingGet())
.RespondWith(Response.Create().WithStatusCode(200).WithBody("Hello"));
Thread.Sleep(1000);
var response = await new HttpClient().GetAsync(server.Urls[0]);
response.EnsureSuccessStatusCode();
System.Console.WriteLine("RunTestDifferentPort - server.LogEntries.Count() = " + server.LogEntries.Count());
server.Stop();
}
}
}

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;net5.0</TargetFrameworks>
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>

View File

@@ -1,4 +1,6 @@
using Newtonsoft.Json;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using WireMock.Settings;
@@ -13,16 +15,26 @@ namespace WireMock.Net.Console.Proxy.NETCoreApp
Urls = new[] { "http://localhost:9091/", "https://localhost:9443/" },
StartAdminInterface = true,
ReadStaticMappings = false,
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = "https://www.google.com",
//ClientX509Certificate2ThumbprintOrSubjectName = "www.yourclientcertname.com OR yourcertificatethumbprint (only if the service you're proxying to requires it)",
SaveMapping = true,
SaveMappingToFile = false,
ExcludedHeaders = new [] { "dnt", "Content-Length" }
}
//ProxyAndRecordSettings = new ProxyAndRecordSettings
//{
// Url = "https://www.google.com",
// //ClientX509Certificate2ThumbprintOrSubjectName = "www.yourclientcertname.com OR yourcertificatethumbprint (only if the service you're proxying to requires it)",
// SaveMapping = true,
// SaveMappingToFile = false,
// ExcludedHeaders = new [] { "dnt", "Content-Length" }
//}
});
server
.Given(Request.Create().UsingGet())
.RespondWith(Response.Create()
.WithProxy(new ProxyAndRecordSettings
{
Url = "http://postman-echo.com/post",
SaveMapping = true,
SaveMappingToFile = true
}));
System.Console.WriteLine("Press any key to stop the server");
System.Console.ReadKey();
server.Stop();

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>

View File

@@ -6,6 +6,8 @@ using System.Threading;
using log4net;
using log4net.Config;
using log4net.Repository;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using WireMock.Settings;
@@ -23,11 +25,21 @@ namespace WireMock.Net.StandAlone.NETCoreApp
{
XmlConfigurator.Configure(LogRepository, new FileInfo("log4net.config"));
var settings = WireMockServerSettingsParser.ParseArguments(args, new WireMockLog4NetLogger());
if (!WireMockServerSettingsParser.TryParseArguments(args, out var settings, new WireMockLog4NetLogger()))
{
return;
}
settings.Logger.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
_server = WireMockServer.Start(settings);
//_server
// .Given(Request.Create()
// .UsingAnyMethod())
// .RespondWith(Response.Create()
// .WithProxy("https://www.google.com"));
Console.WriteLine($"{DateTime.UtcNow} Press Ctrl+C to shut down");
Console.CancelKeyPress += (s, e) =>

View File

@@ -2,7 +2,7 @@
"profiles": {
"WireMock.Net.StandAlone.NETCoreApp": {
"commandName": "Project",
"commandLineArgs": "--Port 9091 --WireMockLogger WireMockConsoleLogger"
"commandLineArgs": "--Urls https://localhost:10080 --WireMockLogger WireMockConsoleLogger"
}
}
}

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.1</TargetFrameworks>
<TargetFrameworks>netcoreapp3.1</TargetFrameworks>
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
<StartupObject>WireMock.Net.StandAlone.NETCoreApp.Program</StartupObject>
</PropertyGroup>

View File

@@ -1 +0,0 @@
dotnet run --framework netcoreapp1.1

View File

@@ -1 +0,0 @@
dotnet run --framework netcoreapp2.0

View File

@@ -1 +0,0 @@
dotnet run --framework netcoreapp2.1

View File

@@ -13,13 +13,15 @@ namespace WireMock.Net.StandAlone.Net452
{
XmlConfigurator.Configure(new FileInfo("log4net.config"));
var settings = WireMockServerSettingsParser.ParseArguments(args);
settings.Logger.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
WireMockServer.Start(settings);
Console.WriteLine("Press any key to stop the server");
Console.ReadKey();
if (WireMockServerSettingsParser.TryParseArguments(args, out var settings))
{
settings.Logger.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
WireMockServer.Start(settings);
Console.WriteLine("Press any key to stop the server");
Console.ReadKey();
}
}
}
}

View File

@@ -9,13 +9,15 @@ namespace WireMock.Net.StandAlone.Net461
{
static void Main(string[] args)
{
var settings = WireMockServerSettingsParser.ParseArguments(args);
settings.Logger.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
WireMockServer.Start(settings);
Console.WriteLine("Press any key to stop the server");
Console.ReadKey();
if (WireMockServerSettingsParser.TryParseArguments(args, out var settings))
{
settings.Logger.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
WireMockServer.Start(settings);
Console.WriteLine("Press any key to stop the server");
Console.ReadKey();
}
}
}
}

7
nuget.config Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://www.nuget.org/api/v2/" />
<add key="coverlet" value="https://f.feedz.io/marcorossignoli/coverletunofficial/nuget/index.json" />
</packageSources>
</configuration>

View File

@@ -51,7 +51,11 @@ namespace WireMock.Server
event NotifyCollectionChangedEventHandler LogEntriesChanged;
/// <summary>
/// Adds the catch all mapping.
/// Adds a 'catch all mapping'
///
/// - matches all Paths and any Methods
/// - priority is set to 1000
/// - responds with a 404 "No matching mapping found"
/// </summary>
void AddCatchAllMapping();
@@ -83,13 +87,18 @@ namespace WireMock.Server
//IRespondWithAProvider Given(IRequestMatcher requestMatcher, bool saveToFile = false);
/// <summary>
/// Reads a static mapping file and adds or updates the mapping.
/// Reads a static mapping file and adds or updates a single mapping.
///
/// Calling this method manually forces WireMock.Net to read and apply the specified static mapping file.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="path">The path to the static mapping file.</param>
bool ReadStaticMappingAndAddOrUpdate([NotNull] string path);
/// <summary>
/// Reads the static mappings from a folder.
/// (This method is also used when WireMockServerSettings.ReadStaticMappings is set to true.
///
/// Calling this method manually forces WireMock.Net to read and apply all static mapping files in the specified folder.
/// </summary>
/// <param name="folder">The optional folder. If not defined, use {CurrentFolder}/__admin/mappings</param>
void ReadStaticMappings([CanBeNull] string folder = null);
@@ -157,12 +166,16 @@ namespace WireMock.Server
/// <summary>
/// Register the mappings (via <see cref="MappingModel"/>).
///
/// This can be used if you have 1 or more <see cref="MappingModel"/> defined and want to register these in WireMock.Net directly instead of using the fluent syntax.
/// </summary>
/// <param name="mappings">The MappingModels</param>
IWireMockServer WithMapping(params MappingModel[] mappings);
/// <summary>
/// Register the mappings (via json string).
///
/// This can be used if you the mappings as json string defined and want to register these in WireMock.Net directly instead of using the fluent syntax.
/// </summary>
/// <param name="mappings">The mapping(s) as json string.</param>
IWireMockServer WithMapping(string mappings);

View File

@@ -21,6 +21,7 @@
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<!--<DelaySign>true</DelaySign>-->
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">

View File

@@ -21,6 +21,7 @@
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<!--<DelaySign>true</DelaySign>-->
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">

View File

@@ -1,5 +1,7 @@
using System;
using System.Linq;
using System.Reflection;
using System.Text;
using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
using WireMock.Exceptions;
@@ -10,13 +12,12 @@ namespace WireMock.Matchers
/// <summary>
/// CSharpCode / CS-Script Matcher
/// </summary>
/// <inheritdoc cref="IObjectMatcher"/>
/// <inheritdoc cref="IStringMatcher"/>
internal class CSharpCodeMatcher : IObjectMatcher, IStringMatcher
/// <inheritdoc cref="ICSharpCodeMatcher"/>
internal class CSharpCodeMatcher : ICSharpCodeMatcher
{
private const string TemplateForIsMatchWithString = "{0} public class CodeHelper {{ public bool IsMatch(string it) {{ {1} }} }}";
private const string TemplateForIsMatchWithString = "public class CodeHelper {{ public bool IsMatch(string it) {{ {0} }} }}";
private const string TemplateForIsMatchWithDynamic = "{0} public class CodeHelper {{ public bool IsMatch(dynamic it) {{ {1} }} }}";
private const string TemplateForIsMatchWithDynamic = "public class CodeHelper {{ public bool IsMatch(dynamic it) {{ {0} }} }}";
private readonly string[] _usings =
{
@@ -151,21 +152,29 @@ namespace WireMock.Matchers
throw new WireMockException("CSharpCodeMatcher: Problem calling method 'IsMatch' in WireMock.CodeHelper", ex);
}
#elif (NETSTANDARD2_0 || NETSTANDARD2_1 || NETCOREAPP3_1)
dynamic script;
#elif (NETSTANDARD2_0 || NETSTANDARD2_1 || NETCOREAPP3_1 || NET5_0)
Assembly assembly;
try
{
assembly = CSScriptLib.CSScript.Evaluator.CompileCode(source);
}
catch (Exception ex)
{
var assembly = CSScriptLib.CSScript.Evaluator.CompileCode(source);
throw new WireMockException($"CSharpCodeMatcher: Unable to compile code `{source}` for WireMock.CodeHelper", ex);
}
dynamic script;
try
{
#if NETSTANDARD2_0
script = csscript.GenericExtensions.CreateObject(assembly, "*");
#else
script = CSScriptLib.ReflectionExtensions.CreateObject(assembly, "*");
#endif
#endif
}
catch (Exception ex)
{
throw new WireMockException("CSharpCodeMatcher: Unable to compile code for WireMock.CodeHelper", ex);
{
throw new WireMockException("CSharpCodeMatcher: Unable to create object from assembly", ex);
}
try
@@ -175,9 +184,9 @@ namespace WireMock.Matchers
catch (Exception ex)
{
throw new WireMockException("CSharpCodeMatcher: Problem calling method 'IsMatch' in WireMock.CodeHelper", ex);
}
}
#else
throw new NotSupportedException("The 'CSharpCodeMatcher' cannot be used in netstandard 1.3");
throw new NotSupportedException("The 'CSharpCodeMatcher' cannot be used in netstandard 1.3");
#endif
try
{
@@ -192,7 +201,16 @@ namespace WireMock.Matchers
private string GetSourceForIsMatchWithString(string pattern, bool isMatchWithString)
{
string template = isMatchWithString ? TemplateForIsMatchWithString : TemplateForIsMatchWithDynamic;
return string.Format(template, string.Join(Environment.NewLine, _usings.Select(u => $"using {u};")), pattern);
var stringBuilder = new StringBuilder();
foreach (string @using in _usings)
{
stringBuilder.AppendLine($"using {@using};");
}
stringBuilder.AppendLine();
stringBuilder.AppendFormat(template, pattern);
return stringBuilder.ToString();
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>

View File

@@ -0,0 +1,6 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
// Needed for Moq in the UnitTest project
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

View File

@@ -0,0 +1,60 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>A CSharpCodeMatcher which can be used to match WireMock.Net Requests using C# code.</Description>
<AssemblyTitle>WireMock.Net.Matchers.CSharpCode</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net451;net452;net46;net461;netstandard1.3;netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>wiremock;matchers;matcher;csharp;csharpcode</PackageTags>
<RootNamespace>WireMock</RootNamespace>
<ProjectGuid>{B6269AAC-170A-4346-8B9A-444DED3D9A44}</ProjectGuid>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<!--<DelaySign>true</DelaySign>-->
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<!-- https://github.com/aspnet/RoslynCodeDomProvider/issues/51 -->
<!-- This is needed else we cannot build net452 in Azure DevOps Pipeline -->
<Target Name="CheckIfShouldKillVBCSCompiler" />
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
<ProjectReference Include="..\WireMock.Net\WireMock.Net.csproj" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' or '$(TargetFramework)' == 'net452' ">
<PackageReference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" Version="3.6.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net46' or '$(TargetFramework)' == 'net461' ">
<PackageReference Include="CS-Script" Version="3.30.3" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="CS-Script.Core" Version="1.1.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.1'">
<PackageReference Include="CS-Script.Core" Version="1.4.2-preview" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' or '$(TargetFramework)' == 'net5.0'">
<PackageReference Include="CS-Script.Core" Version="1.4.2-preview" />
</ItemGroup>
</Project>

View File

@@ -11,6 +11,7 @@
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">

View File

@@ -21,6 +21,7 @@
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<!--<DelaySign>true</DelaySign>-->
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">

View File

@@ -1,48 +1,74 @@
using JetBrains.Annotations;
using System.Linq;
using WireMock.Logging;
using WireMock.Server;
using WireMock.Settings;
using WireMock.Validation;
namespace WireMock.Net.StandAlone
{
/// <summary>
/// The StandAloneApp
/// </summary>
public static class StandAloneApp
{
/// <summary>
/// Start WireMock.Net standalone Server based on the IWireMockServerSettings.
/// </summary>
/// <param name="settings">The IWireMockServerSettings</param>
[PublicAPI]
public static WireMockServer Start([NotNull] IWireMockServerSettings settings)
{
Check.NotNull(settings, nameof(settings));
var server = WireMockServer.Start(settings);
settings.Logger?.Info("WireMock.Net server listening at {0}", string.Join(",", server.Urls));
return server;
}
/// <summary>
/// Start WireMock.Net standalone Server based on the commandline arguments.
/// </summary>
/// <param name="args">The commandline arguments</param>
/// <param name="logger">The logger</param>
[PublicAPI]
public static WireMockServer Start([NotNull] string[] args, [CanBeNull] IWireMockLogger logger = null)
{
Check.NotNull(args, nameof(args));
var settings = WireMockServerSettingsParser.ParseArguments(args, logger);
settings.Logger?.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
return Start(settings);
}
}
using System.Linq;
using JetBrains.Annotations;
using WireMock.Logging;
using WireMock.Server;
using WireMock.Settings;
using WireMock.Validation;
namespace WireMock.Net.StandAlone
{
/// <summary>
/// The StandAloneApp
/// </summary>
public static class StandAloneApp
{
/// <summary>
/// Start WireMock.Net standalone Server based on the IWireMockServerSettings.
/// </summary>
/// <param name="settings">The IWireMockServerSettings</param>
[PublicAPI]
public static WireMockServer Start([NotNull] IWireMockServerSettings settings)
{
Check.NotNull(settings, nameof(settings));
var server = WireMockServer.Start(settings);
settings.Logger?.Info("WireMock.Net server listening at {0}", string.Join(",", server.Urls));
return server;
}
/// <summary>
/// Start WireMock.Net standalone Server based on the commandline arguments.
/// </summary>
/// <param name="args">The commandline arguments</param>
/// <param name="logger">The logger</param>
[PublicAPI]
public static WireMockServer Start([NotNull] string[] args, [CanBeNull] IWireMockLogger logger = null)
{
Check.NotNull(args, nameof(args));
if (WireMockServerSettingsParser.TryParseArguments(args, out var settings, logger))
{
settings.Logger?.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
return Start(settings);
}
return null;
}
/// <summary>
/// Try to start WireMock.Net standalone Server based on the commandline arguments.
/// </summary>
/// <param name="args">The commandline arguments</param>
/// <param name="logger">The logger</param>
/// <param name="server">The WireMockServer</param>
[PublicAPI]
public static bool TryStart([NotNull] string[] args, out WireMockServer server, [CanBeNull] IWireMockLogger logger = null)
{
Check.NotNull(args, nameof(args));
if (WireMockServerSettingsParser.TryParseArguments(args, out var settings, logger))
{
settings.Logger?.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
server = Start(settings);
return true;
}
server = null;
return false;
}
}
}

View File

@@ -3,7 +3,7 @@
<Description>Lightweight StandAlone Http Mocking Server for .Net.</Description>
<AssemblyTitle>WireMock.Net.StandAlone</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net451;net452;net46;net461;netstandard1.3;netstandard2.0;netstandard2.1;netcoreapp3.1</TargetFrameworks>
<TargetFrameworks>net451;net452;net46;net461;netstandard1.3;netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.StandAlone</AssemblyName>
<PackageId>WireMock.Net.StandAlone</PackageId>

View File

@@ -1,19 +1,15 @@
using JetBrains.Annotations;
using System;
using System.Net;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using WireMock.HttpsCertificate;
using WireMock.Settings;
using WireMock.Validation;
namespace WireMock.Http
{
internal static class HttpClientHelper
internal static class HttpClientBuilder
{
public static HttpClient CreateHttpClient(IProxyAndRecordSettings settings)
public static HttpClient Build(IProxyAndRecordSettings settings)
{
#if NETSTANDARD || NETCOREAPP3_1
#if NETSTANDARD || NETCOREAPP3_1 || NET5_0
var handler = new HttpClientHandler
{
CheckCertificateRevocationList = false,
@@ -27,14 +23,12 @@ namespace WireMock.Http
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
#else
var handler = new WebRequestHandler
{
ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
#endif
if (!string.IsNullOrEmpty(settings.ClientX509Certificate2ThumbprintOrSubjectName))
@@ -61,29 +55,12 @@ namespace WireMock.Http
}
}
var client = new HttpClient(handler);
#if NET452 || NET46
#if !NETSTANDARD1_3
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback = (message, cert, chain, errors) => true;
#endif
return client;
}
public static async Task<ResponseMessage> SendAsync([NotNull] HttpClient client, [NotNull] RequestMessage requestMessage, string url, bool deserializeJson, bool decompressGzipAndDeflate)
{
Check.NotNull(client, nameof(client));
Check.NotNull(requestMessage, nameof(requestMessage));
var originalUri = new Uri(requestMessage.Url);
var requiredUri = new Uri(url);
// Create HttpRequestMessage
var httpRequestMessage = HttpRequestMessageHelper.Create(requestMessage, url);
// Call the URL
var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead);
// Create ResponseMessage
return await HttpResponseMessageHelper.CreateAsync(httpResponseMessage, requiredUri, originalUri, deserializeJson, decompressGzipAndDeflate);
return new HttpClient(handler);
}
}
}

View File

@@ -59,15 +59,29 @@ namespace WireMock.Http
foreach (var header in requestMessage.Headers.Where(h => !excludeHeaders.Contains(h.Key, StringComparer.OrdinalIgnoreCase)))
{
// Try to add to request headers. If failed - try to add to content headers
if (httpRequestMessage.Headers.Contains(header.Key))
// Skip if already added. We need to ToList() else calling httpRequestMessage.Headers.Contains() with a header starting with a ":" throws an exception.
if (httpRequestMessage.Headers.ToList().Any(h => string.Equals(h.Key, header.Key, StringComparison.OrdinalIgnoreCase)))
{
continue;
}
if (!httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value))
// Skip if already added. We need to ToList() else calling httpRequestMessage.Content.Headers.Contains(...) with a header starting with a ":" throws an exception.
if (httpRequestMessage.Content != null && httpRequestMessage.Content.Headers.ToList().Any(h => string.Equals(h.Key, header.Key, StringComparison.OrdinalIgnoreCase)))
{
httpRequestMessage.Content.Headers.TryAddWithoutValidation(header.Key, header.Value);
continue;
}
// Try to add to request headers. If failed - try to add to content headers. If still fails, just ignore this header.
try
{
if (!httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value))
{
httpRequestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
}
catch
{
// Just continue
}
}

View File

@@ -71,7 +71,7 @@ namespace WireMock
/// The WireMockServerSettings.
/// </summary>
IWireMockServerSettings Settings { get; }
/// <summary>
/// Is State started ?
/// </summary>

View File

@@ -68,9 +68,18 @@ namespace WireMock
/// <param name="executionConditionState">State in which the current mapping can occur. [Optional]</param>
/// <param name="nextState">The next state which will occur after the current mapping execution. [Optional]</param>
/// <param name="stateTimes">Only when the current state is executed this number, the next state which will occur. [Optional]</param>
public Mapping(Guid guid, [CanBeNull] string title, [CanBeNull] string path,
[NotNull] IWireMockServerSettings settings, [NotNull] IRequestMatcher requestMatcher, [NotNull] IResponseProvider provider,
int priority, [CanBeNull] string scenario, [CanBeNull] string executionConditionState, [CanBeNull] string nextState, [CanBeNull] int? stateTimes)
public Mapping(
Guid guid,
[CanBeNull] string title,
[CanBeNull] string path,
[NotNull] IWireMockServerSettings settings,
[NotNull] IRequestMatcher requestMatcher,
[NotNull] IResponseProvider provider,
int priority,
[CanBeNull] string scenario,
[CanBeNull] string executionConditionState,
[CanBeNull] string nextState,
[CanBeNull] int? stateTimes)
{
Guid = guid;
Title = title;
@@ -82,7 +91,7 @@ namespace WireMock
Scenario = scenario;
ExecutionConditionState = executionConditionState;
NextState = nextState;
StateTimes = stateTimes;
StateTimes = stateTimes;
}
/// <inheritdoc cref="IMapping.ProvideResponseAsync" />

View File

@@ -0,0 +1,11 @@
namespace WireMock.Matchers
{
/// <summary>
/// CSharpCode / CS-Script Matcher
/// </summary>
/// <inheritdoc cref="IObjectMatcher"/>
/// <inheritdoc cref="IStringMatcher"/>
public interface ICSharpCodeMatcher : IObjectMatcher, IStringMatcher
{
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections;
using System;
using System.Collections;
using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json;
@@ -17,7 +18,7 @@ namespace WireMock.Matchers
public object Value { get; }
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JsonMatcher";
public virtual string Name => "JsonMatcher";
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
@@ -29,6 +30,7 @@ namespace WireMock.Matchers
public bool ThrowException { get; }
private readonly JToken _valueAsJToken;
private readonly Func<JToken, JToken> _jTokenConverter;
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
@@ -67,6 +69,9 @@ namespace WireMock.Matchers
Value = value;
_valueAsJToken = ConvertValueToJToken(value);
_jTokenConverter = ignoreCase
? (Func<JToken, JToken>)Rename
: jToken => jToken;
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
@@ -81,7 +86,9 @@ namespace WireMock.Matchers
{
var inputAsJToken = ConvertValueToJToken(input);
match = DeepEquals(_valueAsJToken, inputAsJToken);
match = IsMatch(
_jTokenConverter(_valueAsJToken),
_jTokenConverter(inputAsJToken));
}
catch (JsonException)
{
@@ -95,6 +102,17 @@ namespace WireMock.Matchers
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
}
/// <summary>
/// Compares the input against the matcher value
/// </summary>
/// <param name="value">Matcher value</param>
/// <param name="input">Input value</param>
/// <returns></returns>
protected virtual bool IsMatch(JToken value, JToken input)
{
return JToken.DeepEquals(value, input);
}
private static JToken ConvertValueToJToken(object value)
{
// Check if JToken, string, IEnumerable or object
@@ -114,19 +132,6 @@ namespace WireMock.Matchers
}
}
private bool DeepEquals(JToken value, JToken input)
{
if (!IgnoreCase)
{
return JToken.DeepEquals(value, input);
}
JToken renamedValue = Rename(value);
JToken renamedInput = Rename(input);
return JToken.DeepEquals(renamedValue, renamedInput);
}
private static string ToUpper(string input)
{
return input?.ToUpperInvariant();

View File

@@ -0,0 +1,87 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
namespace WireMock.Matchers
{
/// <summary>
/// JsonPartialMatcher
/// </summary>
public class JsonPartialMatcher : JsonMatcher
{
/// <inheritdoc cref="IMatcher.Name"/>
public override string Name => "JsonPartialMatcher";
/// <summary>
/// Initializes a new instance of the <see cref="JsonPartialMatcher"/> class.
/// </summary>
/// <param name="value">The string value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public JsonPartialMatcher([NotNull] string value, bool ignoreCase = false, bool throwException = false)
: base(value, ignoreCase, throwException)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonPartialMatcher"/> class.
/// </summary>
/// <param name="value">The object value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public JsonPartialMatcher([NotNull] object value, bool ignoreCase = false, bool throwException = false)
: base(value, ignoreCase, throwException)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonPartialMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public JsonPartialMatcher(MatchBehaviour matchBehaviour, [NotNull] object value, bool ignoreCase = false, bool throwException = false)
: base(matchBehaviour, value, ignoreCase, throwException)
{
}
/// <inheritdoc />
protected override bool IsMatch(JToken value, JToken input)
{
if (value == null || value == input)
{
return true;
}
if (input == null || value.Type != input.Type)
{
return false;
}
switch (value.Type)
{
case JTokenType.Object:
var nestedValues = value.ToObject<Dictionary<string, JToken>>();
return nestedValues?.Any() != true ||
nestedValues.All(pair => IsMatch(pair.Value, input.SelectToken(pair.Key)));
case JTokenType.Array:
var valuesArray = value.ToObject<JToken[]>();
var tokenArray = input.ToObject<JToken[]>();
if (valuesArray?.Any() != true)
{
return true;
}
return tokenArray?.Any() == true &&
valuesArray.All(subFilter => tokenArray.Any(subToken => IsMatch(subFilter, subToken)));
default:
return value.ToString() == input.ToString();
}
}
}
}

View File

@@ -58,6 +58,7 @@ namespace WireMock.Owin
}
_host = builder
.UseSetting("suppressStatusMessages", "True") // https://andrewlock.net/suppressing-the-startup-and-shutdown-messages-in-asp-net-core/
.ConfigureAppConfigurationUsingEnvironmentVariables()
.ConfigureServices(services =>
{
@@ -122,6 +123,8 @@ namespace WireMock.Owin
_logger.Info("WireMock.Net server using netstandard2.1");
#elif NETCOREAPP3_1
_logger.Info("WireMock.Net server using .NET Core 3.1");
#elif NET5_0
_logger.Info("WireMock.Net server using .NET 5.0");
#elif NET46
_logger.Info("WireMock.Net server using .NET Framework 4.6.1 or higher");
#endif

View File

@@ -8,6 +8,7 @@ using WireMock.Owin.Mappers;
using WireMock.Serialization;
using WireMock.Types;
using WireMock.Validation;
using WireMock.ResponseBuilders;
#if !USE_ASPNETCORE
using Microsoft.Owin;
using IContext = Microsoft.Owin.IOwinContext;
@@ -129,6 +130,25 @@ namespace WireMock.Owin
response = await targetMapping.ProvideResponseAsync(request);
var responseBuilder = targetMapping.Provider as Response;
if (!targetMapping.IsAdminInterface)
{
if (responseBuilder?.ProxyAndRecordSettings?.SaveMapping == true || targetMapping?.Settings?.ProxyAndRecordSettings?.SaveMapping == true)
{
_options.Mappings.TryAdd(targetMapping.Guid, targetMapping);
}
if (responseBuilder?.ProxyAndRecordSettings?.SaveMappingToFile == true || targetMapping?.Settings?.ProxyAndRecordSettings?.SaveMappingToFile == true)
{
var matcherMapper = new MatcherMapper(targetMapping.Settings);
var mappingConverter = new MappingConverter(matcherMapper);
var mappingToFileSaver = new MappingToFileSaver(targetMapping.Settings, mappingConverter);
mappingToFileSaver.SaveMappingToFile(targetMapping);
}
}
if (targetMapping.Scenario != null)
{
UpdateScenarioState(targetMapping);

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Reflection;
namespace WireMock.Plugin
{
internal static class PluginLoader
{
private static readonly ConcurrentDictionary<Type, Type> Assemblies = new ConcurrentDictionary<Type, Type>();
public static T Load<T>(params object[] args) where T : class
{
var foundType = Assemblies.GetOrAdd(typeof(T), (type) =>
{
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.dll");
Type pluginType = null;
foreach (var file in files)
{
try
{
var assembly = Assembly.Load(new AssemblyName
{
Name = Path.GetFileNameWithoutExtension(file)
});
pluginType = GetImplementationTypeByInterface<T>(assembly);
if (pluginType != null)
{
break;
}
}
catch
{
// no-op: just try next .dll
}
}
if (pluginType != null)
{
return pluginType;
}
throw new DllNotFoundException($"No dll found which implements type '{type}'");
});
return (T)Activator.CreateInstance(foundType, args);
}
private static Type GetImplementationTypeByInterface<T>(Assembly assembly)
{
return assembly.GetTypes().FirstOrDefault(t => typeof(T).IsAssignableFrom(t) && !t.GetTypeInfo().IsInterface);
}
}
}

View File

@@ -1,7 +1,8 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("WireMock.Net.StandAlone, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
[assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
// Needed for Moq in the UnitTest project
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("WireMock.Net.Matchers.CSharpCode, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
[assembly: InternalsVisibleTo("WireMock.Net.StandAlone, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
[assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
// Needed for Moq in the UnitTest project
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

View File

@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using HandlebarsDotNet.Helpers.Validation;
using JetBrains.Annotations;
using WireMock.Http;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Settings;
using WireMock.Types;
using WireMock.Util;
namespace WireMock.Proxy
{
internal class ProxyHelper
{
private readonly IWireMockServerSettings _settings;
public ProxyHelper([NotNull] IWireMockServerSettings settings)
{
Guard.NotNull(settings, nameof(settings));
_settings = settings;
}
public async Task<(ResponseMessage ResponseMessage, IMapping Mapping)> SendAsync(
[NotNull] IProxyAndRecordSettings proxyAndRecordSettings,
[NotNull] HttpClient client,
[NotNull] RequestMessage requestMessage,
[NotNull] string url)
{
Guard.NotNull(client, nameof(client));
Guard.NotNull(requestMessage, nameof(requestMessage));
Guard.NotNull(url, nameof(url));
var originalUri = new Uri(requestMessage.Url);
var requiredUri = new Uri(url);
// Create HttpRequestMessage
var httpRequestMessage = HttpRequestMessageHelper.Create(requestMessage, url);
// Call the URL
var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead);
// Create ResponseMessage
bool deserializeJson = !_settings.DisableJsonBodyParsing.GetValueOrDefault(false);
bool decompressGzipAndDeflate = !_settings.DisableRequestBodyDecompressing.GetValueOrDefault(false);
var responseMessage = await HttpResponseMessageHelper.CreateAsync(httpResponseMessage, requiredUri, originalUri, deserializeJson, decompressGzipAndDeflate);
IMapping mapping = null;
if (HttpStatusRangeParser.IsMatch(proxyAndRecordSettings.SaveMappingForStatusCodePattern, responseMessage.StatusCode) &&
(proxyAndRecordSettings.SaveMapping || proxyAndRecordSettings.SaveMappingToFile))
{
mapping = ToMapping(proxyAndRecordSettings, requestMessage, responseMessage);
}
return (responseMessage, mapping);
}
private IMapping ToMapping(IProxyAndRecordSettings proxyAndRecordSettings, RequestMessage requestMessage, ResponseMessage responseMessage)
{
string[] excludedHeaders = proxyAndRecordSettings.ExcludedHeaders ?? new string[] { };
string[] excludedCookies = proxyAndRecordSettings.ExcludedCookies ?? new string[] { };
var request = Request.Create();
request.WithPath(requestMessage.Path);
request.UsingMethod(requestMessage.Method);
requestMessage.Query.Loop((key, value) => request.WithParam(key, false, value.ToArray()));
requestMessage.Cookies.Loop((key, value) =>
{
if (!excludedCookies.Contains(key, StringComparer.OrdinalIgnoreCase))
{
request.WithCookie(key, value);
}
});
var allExcludedHeaders = new List<string>(excludedHeaders) { "Cookie" };
requestMessage.Headers.Loop((key, value) =>
{
if (!allExcludedHeaders.Contains(key, StringComparer.OrdinalIgnoreCase))
{
request.WithHeader(key, value.ToArray());
}
});
bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
switch (requestMessage.BodyData?.DetectedBodyType)
{
case BodyType.Json:
request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson, true, throwExceptionWhenMatcherFails));
break;
case BodyType.String:
request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, throwExceptionWhenMatcherFails, requestMessage.BodyData.BodyAsString));
break;
case BodyType.Bytes:
request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes, throwExceptionWhenMatcherFails));
break;
}
var response = Response.Create(responseMessage);
return new Mapping(Guid.NewGuid(), string.Empty, null, _settings, request, response, 0, null, null, null, null);
}
}
}

View File

@@ -55,6 +55,16 @@ namespace WireMock.RequestBuilders
return _requestMatchers.OfType<T>().FirstOrDefault();
}
/// <summary>
/// Gets the request message matcher.
/// </summary>
/// <typeparam name="T">Type of IRequestMatcher</typeparam>
/// <returns>A RequestMatcher</returns>
public T GetRequestMessageMatcher<T>(Func<T, bool> func) where T : IRequestMatcher
{
return _requestMatchers.OfType<T>().FirstOrDefault(func);
}
/// <inheritdoc cref="IClientIPRequestBuilder.WithClientIP(IStringMatcher[])"/>
public IRequestBuilder WithClientIP(params IStringMatcher[] matchers)
{

View File

@@ -9,15 +9,10 @@ namespace WireMock.ResponseBuilders
{
private HttpClient _httpClientForProxy;
/// <summary>
/// The Proxy URL to use.
/// </summary>
public string ProxyUrl { get; private set; }
/// <summary>
/// The WebProxy settings.
/// </summary>
public IWebProxySettings WebProxySettings { get; private set; }
public IProxyAndRecordSettings ProxyAndRecordSettings { get; private set; }
/// <inheritdoc cref="IProxyResponseBuilder.WithProxy(string, string)"/>
public IResponseBuilder WithProxy(string proxyUrl, string clientX509Certificate2ThumbprintOrSubjectName = null)
@@ -38,10 +33,9 @@ namespace WireMock.ResponseBuilders
{
Check.NotNull(settings, nameof(settings));
ProxyUrl = settings.Url;
WebProxySettings = settings.WebProxySettings;
ProxyAndRecordSettings = settings;
_httpClientForProxy = HttpClientHelper.CreateHttpClient(settings);
_httpClientForProxy = HttpClientBuilder.Build(settings);
return this;
}
}

View File

@@ -7,7 +7,7 @@ using System.Net;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Http;
using WireMock.Proxy;
using WireMock.ResponseProviders;
using WireMock.Settings;
using WireMock.Transformers;
@@ -312,7 +312,7 @@ namespace WireMock.ResponseBuilders
await Task.Delay(Delay.Value);
}
if (ProxyUrl != null && _httpClientForProxy != null)
if (ProxyAndRecordSettings != null && _httpClientForProxy != null)
{
string RemoveFirstOccurrence(string source, string find)
{
@@ -323,16 +323,19 @@ namespace WireMock.ResponseBuilders
var requestUri = new Uri(requestMessage.Url);
// Build the proxy url and skip duplicates
string extra = RemoveFirstOccurrence(requestUri.LocalPath.TrimEnd('/'), new Uri(ProxyUrl).LocalPath.TrimEnd('/'));
requestMessage.ProxyUrl = ProxyUrl + extra + requestUri.Query;
string extra = RemoveFirstOccurrence(requestUri.LocalPath.TrimEnd('/'), new Uri(ProxyAndRecordSettings.Url).LocalPath.TrimEnd('/'));
requestMessage.ProxyUrl = ProxyAndRecordSettings.Url + extra + requestUri.Query;
return await HttpClientHelper.SendAsync(
var proxyHelper = new ProxyHelper(settings);
var (proxyResponseMessage, mapping) = await proxyHelper.SendAsync(
ProxyAndRecordSettings,
_httpClientForProxy,
requestMessage,
requestMessage.ProxyUrl,
!settings.DisableJsonBodyParsing.GetValueOrDefault(false),
!settings.DisableRequestBodyDecompressing.GetValueOrDefault(false)
requestMessage.ProxyUrl
);
return proxyResponseMessage;
}
ResponseMessage responseMessage;

View File

@@ -1,7 +1,7 @@
// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License.
// For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root.
using JetBrains.Annotations;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Settings;
namespace WireMock.ResponseProviders

View File

@@ -0,0 +1,19 @@
using Newtonsoft.Json;
namespace WireMock.Serialization
{
internal static class JsonSerializationConstants
{
public static readonly JsonSerializerSettings JsonSerializerSettingsDefault = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore
};
public static readonly JsonSerializerSettings JsonSerializerSettingsIncludeNullValues = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Include
};
}
}

View File

@@ -101,7 +101,7 @@ namespace WireMock.Serialization
}
}
if (!string.IsNullOrEmpty(response.ProxyUrl))
if (response.ProxyAndRecordSettings != null)
{
mappingModel.Response.StatusCode = null;
mappingModel.Response.Headers = null;
@@ -115,9 +115,9 @@ namespace WireMock.Serialization
mappingModel.Response.UseTransformer = null;
mappingModel.Response.UseTransformerForBodyAsFile = null;
mappingModel.Response.BodyEncoding = null;
mappingModel.Response.ProxyUrl = response.ProxyUrl;
mappingModel.Response.ProxyUrl = response.ProxyAndRecordSettings.Url;
mappingModel.Response.Fault = null;
mappingModel.Response.WebProxy = MapWebProxy(response.WebProxySettings);
mappingModel.Response.WebProxy = MapWebProxy(response.ProxyAndRecordSettings.WebProxySettings);
}
else
{

View File

@@ -0,0 +1,49 @@
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using WireMock.Settings;
using WireMock.Validation;
namespace WireMock.Serialization
{
internal class MappingToFileSaver
{
private readonly IWireMockServerSettings _settings;
private readonly MappingConverter _mappingConverter;
public MappingToFileSaver(IWireMockServerSettings settings, MappingConverter mappingConverter)
{
Check.NotNull(settings, nameof(settings));
_settings = settings;
_mappingConverter = mappingConverter;
}
public void SaveMappingToFile(IMapping mapping, string folder = null)
{
if (folder == null)
{
folder = _settings.FileSystemHandler.GetMappingFolder();
}
if (!_settings.FileSystemHandler.FolderExists(folder))
{
_settings.FileSystemHandler.CreateFolder(folder);
}
var model = _mappingConverter.ToMappingModel(mapping);
string filename = (!string.IsNullOrEmpty(mapping.Title) ? SanitizeFileName(mapping.Title) : mapping.Guid.ToString()) + ".json";
string path = Path.Combine(folder, filename);
_settings.Logger.Info("Saving Mapping file {0}", filename);
_settings.FileSystemHandler.WriteMappingFile(path, JsonConvert.SerializeObject(model, JsonSerializationConstants.JsonSerializerSettingsDefault));
}
private static string SanitizeFileName(string name, char replaceChar = '_')
{
return Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, replaceChar));
}
}
}

View File

@@ -5,6 +5,7 @@ using JetBrains.Annotations;
using SimMetrics.Net;
using WireMock.Admin.Mappings;
using WireMock.Matchers;
using WireMock.Plugin;
using WireMock.Settings;
using WireMock.Validation;
@@ -46,7 +47,7 @@ namespace WireMock.Serialization
case "CSharpCodeMatcher":
if (_settings.AllowCSharpCodeMatcher == true)
{
return new CSharpCodeMatcher(matchBehaviour, stringPatterns);
return PluginLoader.Load<ICSharpCodeMatcher>(matchBehaviour, stringPatterns);
}
throw new NotSupportedException("It's not allowed to use the 'CSharpCodeMatcher' because IWireMockServerSettings.AllowCSharpCodeMatcher is not set to 'true'.");
@@ -67,6 +68,10 @@ namespace WireMock.Serialization
object value = matcher.Pattern ?? matcher.Patterns;
return new JsonMatcher(matchBehaviour, value, ignoreCase, throwExceptionWhenMatcherFails);
case "JsonPartialMatcher":
object matcherValue = matcher.Pattern ?? matcher.Patterns;
return new JsonPartialMatcher(matchBehaviour, matcherValue, ignoreCase, throwExceptionWhenMatcherFails);
case "JsonPathMatcher":
return new JsonPathMatcher(matchBehaviour, throwExceptionWhenMatcherFails, stringPatterns);

View File

@@ -16,6 +16,7 @@ using WireMock.Http;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Matchers.Request;
using WireMock.Proxy;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.ResponseProviders;
@@ -47,18 +48,6 @@ namespace WireMock.Server
private readonly RegexMatcher _adminMappingsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/mappings\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$");
private readonly RegexMatcher _adminRequestsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/requests\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$");
private readonly JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore
};
private readonly JsonSerializerSettings _settingsIncludeNullValues = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Include
};
#region InitAdmin
private void InitAdmin()
{
@@ -119,7 +108,7 @@ namespace WireMock.Server
{
foreach (var mapping in Mappings.Where(m => !m.IsAdminInterface))
{
SaveMappingToFile(mapping, folder);
_mappingToFileSaver.SaveMappingToFile(mapping, folder);
}
}
@@ -246,7 +235,7 @@ namespace WireMock.Server
private void InitProxyAndRecord(IWireMockServerSettings settings)
{
_httpClientForProxy = HttpClientHelper.CreateHttpClient(settings.ProxyAndRecordSettings);
_httpClientForProxy = HttpClientBuilder.Build(settings.ProxyAndRecordSettings);
var respondProvider = Given(Request.Create().WithPath("/*").UsingAnyMethod());
if (settings.StartAdminInterface == true)
@@ -263,82 +252,27 @@ namespace WireMock.Server
var proxyUri = new Uri(settings.ProxyAndRecordSettings.Url);
var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery);
var responseMessage = await HttpClientHelper.SendAsync(
var proxyHelper = new ProxyHelper(settings);
var (responseMessage, mapping) = await proxyHelper.SendAsync(
_settings.ProxyAndRecordSettings,
_httpClientForProxy,
requestMessage,
proxyUriWithRequestPathAndQuery.AbsoluteUri,
!settings.DisableJsonBodyParsing.GetValueOrDefault(false),
!settings.DisableRequestBodyDecompressing.GetValueOrDefault(false)
proxyUriWithRequestPathAndQuery.AbsoluteUri
);
if (HttpStatusRangeParser.IsMatch(settings.ProxyAndRecordSettings.SaveMappingForStatusCodePattern, responseMessage.StatusCode) &&
(settings.ProxyAndRecordSettings.SaveMapping || settings.ProxyAndRecordSettings.SaveMappingToFile))
if (settings.ProxyAndRecordSettings.SaveMapping)
{
var mapping = ToMapping(
requestMessage,
responseMessage,
settings.ProxyAndRecordSettings.ExcludedHeaders ?? new string[] { },
settings.ProxyAndRecordSettings.ExcludedCookies ?? new string[] { }
);
_options.Mappings.TryAdd(mapping.Guid, mapping);
}
if (settings.ProxyAndRecordSettings.SaveMapping)
{
_options.Mappings.TryAdd(mapping.Guid, mapping);
}
if (settings.ProxyAndRecordSettings.SaveMappingToFile)
{
SaveMappingToFile(mapping);
}
if (settings.ProxyAndRecordSettings.SaveMappingToFile)
{
_mappingToFileSaver.SaveMappingToFile(mapping);
}
return responseMessage;
}
private IMapping ToMapping(RequestMessage requestMessage, ResponseMessage responseMessage, string[] excludedHeaders, string[] excludedCookies)
{
var request = Request.Create();
request.WithPath(requestMessage.Path);
request.UsingMethod(requestMessage.Method);
requestMessage.Query.Loop((key, value) => request.WithParam(key, false, value.ToArray()));
requestMessage.Cookies.Loop((key, value) =>
{
if (!excludedCookies.Contains(key, StringComparer.OrdinalIgnoreCase))
{
request.WithCookie(key, value);
}
});
var allExcludedHeaders = new List<string>(excludedHeaders) { "Cookie" };
requestMessage.Headers.Loop((key, value) =>
{
if (!allExcludedHeaders.Contains(key, StringComparer.OrdinalIgnoreCase))
{
request.WithHeader(key, value.ToArray());
}
});
bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
switch (requestMessage.BodyData?.DetectedBodyType)
{
case BodyType.Json:
request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson, true, throwExceptionWhenMatcherFails));
break;
case BodyType.String:
request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, throwExceptionWhenMatcherFails, requestMessage.BodyData.BodyAsString));
break;
case BodyType.Bytes:
request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes, throwExceptionWhenMatcherFails));
break;
}
var response = Response.Create(responseMessage);
return new Mapping(Guid.NewGuid(), string.Empty, null, _settings, request, response, 0, null, null, null, null);
}
#endregion
#region Settings
@@ -446,33 +380,6 @@ namespace WireMock.Server
return ResponseMessageBuilder.Create("Mappings saved to disk");
}
private void SaveMappingToFile(IMapping mapping, string folder = null)
{
if (folder == null)
{
folder = _settings.FileSystemHandler.GetMappingFolder();
}
if (!_settings.FileSystemHandler.FolderExists(folder))
{
_settings.FileSystemHandler.CreateFolder(folder);
}
var model = _mappingConverter.ToMappingModel(mapping);
string filename = (!string.IsNullOrEmpty(mapping.Title) ? SanitizeFileName(mapping.Title) : mapping.Guid.ToString()) + ".json";
string path = Path.Combine(folder, filename);
_settings.Logger.Info("Saving Mapping file {0}", filename);
_settings.FileSystemHandler.WriteMappingFile(path, JsonConvert.SerializeObject(model, _jsonSerializerSettings));
}
private static string SanitizeFileName(string name, char replaceChar = '_')
{
return Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, replaceChar));
}
private IEnumerable<MappingModel> ToMappingModels()
{
return Mappings.Where(m => !m.IsAdminInterface).Select(_mappingConverter.ToMappingModel);
@@ -945,7 +852,7 @@ namespace WireMock.Server
BodyData = new BodyData
{
DetectedBodyType = BodyType.String,
BodyAsString = JsonConvert.SerializeObject(result, keepNullValues ? _settingsIncludeNullValues : _jsonSerializerSettings)
BodyAsString = JsonConvert.SerializeObject(result, keepNullValues ? JsonSerializationConstants.JsonSerializerSettingsIncludeNullValues : JsonSerializationConstants.JsonSerializerSettingsDefault)
},
StatusCode = (int)HttpStatusCode.OK,
Headers = new Dictionary<string, WireMockList<string>> { { HttpKnownHeaderNames.ContentType, new WireMockList<string>(ContentTypeJson) } }

View File

@@ -35,6 +35,7 @@ namespace WireMock.Server
private readonly IWireMockMiddlewareOptions _options = new WireMockMiddlewareOptions();
private readonly MappingConverter _mappingConverter;
private readonly MatcherMapper _matcherMapper;
private readonly MappingToFileSaver _mappingToFileSaver;
/// <inheritdoc cref="IWireMockServer.IsStarted" />
[PublicAPI]
@@ -80,10 +81,7 @@ namespace WireMock.Server
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_httpServer != null)
{
_httpServer.StopAsync();
}
_httpServer?.StopAsync();
}
#endregion
@@ -241,6 +239,7 @@ namespace WireMock.Server
_matcherMapper = new MatcherMapper(_settings);
_mappingConverter = new MappingConverter(_matcherMapper);
_mappingToFileSaver = new MappingToFileSaver(_settings, _mappingConverter);
#if USE_ASPNETCORE
_httpServer = new AspNetCoreSelfHost(_options, urlOptions);
@@ -494,7 +493,7 @@ namespace WireMock.Server
if (saveToFile)
{
SaveMappingToFile(mapping);
_mappingToFileSaver.SaveMappingToFile(mapping);
}
}
}

View File

@@ -25,7 +25,7 @@ namespace WireMock.Settings
string SaveMappingForStatusCodePattern { get; set; }
/// <summary>
/// Save the mapping for each request/response also to a file. (Note that SaveMapping must also be set to true.)
/// Save the mapping for each request/response to a .json mapping file.
/// </summary>
bool SaveMappingToFile { get; set; }

View File

@@ -17,13 +17,13 @@ namespace WireMock.Settings
/// Save the mapping for each request/response to the internal Mappings.
/// </summary>
[PublicAPI]
public bool SaveMapping { get; set; } = true;
public bool SaveMapping { get; set; }
/// <summary>
/// Save the mapping for each request/response also to a file. (Note that SaveMapping must also be set to true.)
/// </summary>
[PublicAPI]
public bool SaveMappingToFile { get; set; } = true;
public bool SaveMappingToFile { get; set; }
/// <summary>
/// Only save request/response to the internal Mappings if the status code is included in this pattern. (Note that SaveMapping must also be set to true.)

View File

@@ -9,7 +9,7 @@ namespace WireMock.Settings
{
private const string Sigil = "--";
private IDictionary<string, string[]> Arguments { get; } = new Dictionary<string, string[]>();
private IDictionary<string, string[]> Arguments { get; } = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
public void Parse(string[] arguments)
{
@@ -70,6 +70,11 @@ namespace WireMock.Settings
}, defaultValue);
}
public bool GetBoolSwitchValue(string name)
{
return Contains(name);
}
public int? GetIntValue(string name, int? defaultValue = null)
{
return GetValue(name, values =>

View File

@@ -1,106 +1,114 @@
using JetBrains.Annotations;
using WireMock.Logging;
using WireMock.Validation;
namespace WireMock.Settings
{
/// <summary>
/// A static helper class to parse commandline arguments into IWireMockServerSettings.
/// </summary>
public static class WireMockServerSettingsParser
{
/// <summary>
/// Parse commandline arguments into WireMockServerSettings.
/// </summary>
/// <param name="args">The commandline arguments</param>
/// <param name="logger">The logger (optional, can be null)</param>
[PublicAPI]
public static IWireMockServerSettings ParseArguments([NotNull] string[] args, [CanBeNull] IWireMockLogger logger = null)
{
Check.HasNoNulls(args, nameof(args));
var parser = new SimpleCommandLineParser();
parser.Parse(args);
var settings = new WireMockServerSettings
{
StartAdminInterface = parser.GetBoolValue("StartAdminInterface", true),
ReadStaticMappings = parser.GetBoolValue("ReadStaticMappings"),
WatchStaticMappings = parser.GetBoolValue("WatchStaticMappings"),
AllowPartialMapping = parser.GetBoolValue("AllowPartialMapping"),
WatchStaticMappingsInSubdirectories = parser.GetBoolValue("WatchStaticMappingsInSubdirectories"),
AdminUsername = parser.GetStringValue("AdminUsername"),
AdminPassword = parser.GetStringValue("AdminPassword"),
MaxRequestLogCount = parser.GetIntValue("MaxRequestLogCount"),
RequestLogExpirationDuration = parser.GetIntValue("RequestLogExpirationDuration"),
AllowCSharpCodeMatcher = parser.GetBoolValue("AllowCSharpCodeMatcher"),
AllowBodyForAllHttpMethods = parser.GetBoolValue("AllowBodyForAllHttpMethods"),
AllowOnlyDefinedHttpStatusCodeInResponse = parser.GetBoolValue("AllowOnlyDefinedHttpStatusCodeInResponse"),
DisableJsonBodyParsing = parser.GetBoolValue("DisableJsonBodyParsing"),
HandleRequestsSynchronously = parser.GetBoolValue("HandleRequestsSynchronously"),
ThrowExceptionWhenMatcherFails = parser.GetBoolValue("ThrowExceptionWhenMatcherFails")
};
if (logger != null)
{
settings.Logger = logger;
}
if (parser.GetStringValue("WireMockLogger") == "WireMockConsoleLogger")
{
settings.Logger = new WireMockConsoleLogger();
}
if (parser.Contains("Port"))
{
settings.Port = parser.GetIntValue("Port");
}
else
{
settings.Urls = parser.GetValues("Urls", new[] { "http://*:9091/" });
}
string proxyUrl = parser.GetStringValue("ProxyURL") ?? parser.GetStringValue("ProxyUrl");
if (!string.IsNullOrEmpty(proxyUrl))
{
settings.ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = proxyUrl,
SaveMapping = parser.GetBoolValue("SaveMapping"),
SaveMappingToFile = parser.GetBoolValue("SaveMappingToFile"),
SaveMappingForStatusCodePattern = parser.GetStringValue("SaveMappingForStatusCodePattern"),
ClientX509Certificate2ThumbprintOrSubjectName = parser.GetStringValue("ClientX509Certificate2ThumbprintOrSubjectName"),
ExcludedHeaders = parser.GetValues("ExcludedHeaders"),
ExcludedCookies = parser.GetValues("ExcludedCookies"),
AllowAutoRedirect = parser.GetBoolValue("AllowAutoRedirect")
};
string proxyAddress = parser.GetStringValue("WebProxyAddress");
if (!string.IsNullOrEmpty(proxyAddress))
{
settings.ProxyAndRecordSettings.WebProxySettings = new WebProxySettings
{
Address = proxyAddress,
UserName = parser.GetStringValue("WebProxyUserName"),
Password = parser.GetStringValue("WebProxyPassword")
};
}
}
var certificateSettings = new WireMockCertificateSettings
{
X509StoreName = parser.GetStringValue("X509StoreName"),
X509StoreLocation = parser.GetStringValue("X509StoreLocation"),
X509StoreThumbprintOrSubjectName = parser.GetStringValue("X509StoreThumbprintOrSubjectName"),
X509CertificateFilePath = parser.GetStringValue("X509CertificateFilePath"),
X509CertificatePassword = parser.GetStringValue("X509CertificatePassword")
};
if (certificateSettings.IsDefined)
{
settings.CertificateSettings = certificateSettings;
}
return settings;
}
}
using JetBrains.Annotations;
using WireMock.Logging;
using WireMock.Validation;
namespace WireMock.Settings
{
/// <summary>
/// A static helper class to parse commandline arguments into IWireMockServerSettings.
/// </summary>
public static class WireMockServerSettingsParser
{
/// <summary>
/// Parse commandline arguments into WireMockServerSettings.
/// </summary>
/// <param name="args">The commandline arguments</param>
/// <param name="logger">The logger (optional, can be null)</param>
/// <param name="settings">The parsed settings</param>
[PublicAPI]
public static bool TryParseArguments([NotNull] string[] args, out IWireMockServerSettings settings, [CanBeNull] IWireMockLogger logger = null)
{
Check.HasNoNulls(args, nameof(args));
var parser = new SimpleCommandLineParser();
parser.Parse(args);
if (parser.GetBoolSwitchValue("help"))
{
(logger ?? new WireMockConsoleLogger()).Info("See https://github.com/WireMock-Net/WireMock.Net/wiki/WireMock-commandline-parameters for details on all commandline options.");
settings = null;
return false;
}
settings = new WireMockServerSettings
{
StartAdminInterface = parser.GetBoolValue("StartAdminInterface", true),
ReadStaticMappings = parser.GetBoolValue("ReadStaticMappings"),
WatchStaticMappings = parser.GetBoolValue("WatchStaticMappings"),
AllowPartialMapping = parser.GetBoolValue("AllowPartialMapping"),
WatchStaticMappingsInSubdirectories = parser.GetBoolValue("WatchStaticMappingsInSubdirectories"),
AdminUsername = parser.GetStringValue("AdminUsername"),
AdminPassword = parser.GetStringValue("AdminPassword"),
MaxRequestLogCount = parser.GetIntValue("MaxRequestLogCount"),
RequestLogExpirationDuration = parser.GetIntValue("RequestLogExpirationDuration"),
AllowCSharpCodeMatcher = parser.GetBoolValue("AllowCSharpCodeMatcher"),
AllowBodyForAllHttpMethods = parser.GetBoolValue("AllowBodyForAllHttpMethods"),
AllowOnlyDefinedHttpStatusCodeInResponse = parser.GetBoolValue("AllowOnlyDefinedHttpStatusCodeInResponse"),
DisableJsonBodyParsing = parser.GetBoolValue("DisableJsonBodyParsing"),
HandleRequestsSynchronously = parser.GetBoolValue("HandleRequestsSynchronously"),
ThrowExceptionWhenMatcherFails = parser.GetBoolValue("ThrowExceptionWhenMatcherFails")
};
if (logger != null)
{
settings.Logger = logger;
}
if (parser.GetStringValue("WireMockLogger") == "WireMockConsoleLogger")
{
settings.Logger = new WireMockConsoleLogger();
}
if (parser.Contains("Port"))
{
settings.Port = parser.GetIntValue("Port");
}
else
{
settings.Urls = parser.GetValues("Urls", new[] { "http://*:9091/" });
}
string proxyUrl = parser.GetStringValue("ProxyURL") ?? parser.GetStringValue("ProxyUrl");
if (!string.IsNullOrEmpty(proxyUrl))
{
settings.ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = proxyUrl,
SaveMapping = parser.GetBoolValue("SaveMapping"),
SaveMappingToFile = parser.GetBoolValue("SaveMappingToFile"),
SaveMappingForStatusCodePattern = parser.GetStringValue("SaveMappingForStatusCodePattern"),
ClientX509Certificate2ThumbprintOrSubjectName = parser.GetStringValue("ClientX509Certificate2ThumbprintOrSubjectName"),
ExcludedHeaders = parser.GetValues("ExcludedHeaders"),
ExcludedCookies = parser.GetValues("ExcludedCookies"),
AllowAutoRedirect = parser.GetBoolValue("AllowAutoRedirect")
};
string proxyAddress = parser.GetStringValue("WebProxyAddress");
if (!string.IsNullOrEmpty(proxyAddress))
{
settings.ProxyAndRecordSettings.WebProxySettings = new WebProxySettings
{
Address = proxyAddress,
UserName = parser.GetStringValue("WebProxyUserName"),
Password = parser.GetStringValue("WebProxyPassword")
};
}
}
var certificateSettings = new WireMockCertificateSettings
{
X509StoreName = parser.GetStringValue("X509StoreName"),
X509StoreLocation = parser.GetStringValue("X509StoreLocation"),
X509StoreThumbprintOrSubjectName = parser.GetStringValue("X509StoreThumbprintOrSubjectName"),
X509CertificateFilePath = parser.GetStringValue("X509CertificateFilePath"),
X509CertificatePassword = parser.GetStringValue("X509CertificatePassword")
};
if (certificateSettings.IsDefined)
{
settings.CertificateSettings = certificateSettings;
}
return true;
}
}
}

View File

@@ -3,7 +3,7 @@
<Description>Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.</Description>
<AssemblyTitle>WireMock.Net</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net451;net452;net46;net461;netstandard1.3;netstandard2.0;netstandard2.1;netcoreapp3.1</TargetFrameworks>
<TargetFrameworks>net451;net452;net46;net461;netstandard1.3;netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net</AssemblyName>
<PackageId>WireMock.Net</PackageId>
@@ -27,7 +27,7 @@
<!-- https://github.com/aspnet/RoslynCodeDomProvider/issues/51 -->
<!-- This is needed else we cannot build net452 in Azure DevOps Pipeline -->
<Target Name="CheckIfShouldKillVBCSCompiler" />
<!--<Target Name="CheckIfShouldKillVBCSCompiler" />-->
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<!--<PathMap>$(MSBuildProjectDirectory)=/</PathMap>-->
@@ -42,7 +42,7 @@
<DefineConstants>NETSTANDARD;USE_ASPNETCORE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp2.1' or '$(TargetFramework)' == 'netcoreapp2.2' or '$(TargetFramework)' == 'netcoreapp3.1'">
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp2.1' or '$(TargetFramework)' == 'netcoreapp2.2' or '$(TargetFramework)' == 'netcoreapp3.1' or '$(TargetFramework)' == 'net5.0'">
<DefineConstants>USE_ASPNETCORE</DefineConstants>
</PropertyGroup>
@@ -72,22 +72,12 @@
<PackageReference Include="XPath2.Extensions" Version="1.1.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' or '$(TargetFramework)' == 'net452' ">
<!-- Required for WebRequestHandler -->
<Reference Include="System.Net.Http.WebRequest" />
<PackageReference Include="Microsoft.AspNet.WebApi.OwinSelfHost" Version="5.2.6" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" Version="2.0.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
<!-- Required for WebRequestHandler -->
<Reference Include="System.Net.Http.WebRequest" />
<PackageReference Include="Microsoft.AspNet.WebApi.OwinSelfHost" Version="5.2.6" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" Version="2.0.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net46' ">
@@ -97,7 +87,6 @@
<PackageReference Include="Microsoft.Owin.Hosting" Version="4.0.0" />
<PackageReference Include="System.Net.Http" Version="4.3.3" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="CS-Script" Version="3.29.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
@@ -105,8 +94,6 @@
<!-- https://github.com/WireMock-Net/WireMock.Net/issues/507 -->
<PackageReference Include="Microsoft.AspNetCore.Server.IIS" Version="2.2.6" />
<PackageReference Include="CS-Script" Version="3.29.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
@@ -117,28 +104,15 @@
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0'">
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' ">
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<!-- https://github.com/WireMock-Net/WireMock.Net/issues/507 -->
<PackageReference Include="Microsoft.AspNetCore.Server.IIS" Version="2.2.6" />
<PackageReference Include="CS-Script.Core" Version="1.1.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.1'">
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<!-- https://github.com/WireMock-Net/WireMock.Net/issues/507 -->
<PackageReference Include="Microsoft.AspNetCore.Server.IIS" Version="2.2.6" />
<!-- https://github.com/WireMock-Net/WireMock.Net/issues/448 -->
<PackageReference Include="CS-Script.Core" Version="1.3.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1'">
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' or '$(TargetFramework)' == 'net5.0'">
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<!-- https://github.com/WireMock-Net/WireMock.Net/issues/448 -->
<PackageReference Include="CS-Script.Core" Version="1.4.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,58 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using WireMock.Net.StandAlone;
using WireMock.Server;
namespace WireMock
{
public class Program
{
private static int SleepTime = 30000;
private static readonly ILogger Logger = LoggerFactory.Create(o =>
{
o.SetMinimumLevel(LogLevel.Debug);
o.AddSimpleConsole(options =>
{
options.IncludeScopes = true;
options.SingleLine = false;
options.TimestampFormat = "yyyy-MM-ddTHH:mm:ss ";
});
}).CreateLogger(string.Empty);
private static WireMockServer Server;
static async Task Main(string[] args)
{
if (!StandAloneApp.TryStart(args, out Server, new WireMockLogger(Logger)))
{
return;
}
Logger.LogInformation("Press Ctrl+C to shut down");
Console.CancelKeyPress += (s, e) =>
{
Stop("CancelKeyPress");
};
System.Runtime.Loader.AssemblyLoadContext.Default.Unloading += ctx =>
{
Stop("AssemblyLoadContext.Default.Unloading");
};
while (true)
{
Logger.LogInformation("WireMock.Net server running : {IsStarted}", Server.IsStarted);
await Task.Delay(SleepTime);
}
}
private static void Stop(string why)
{
Logger.LogInformation("WireMock.Net server stopping because '{why}'", why);
Server.Stop();
Logger.LogInformation("WireMock.Net server stopped");
}
}
}

View File

@@ -0,0 +1,8 @@
{
"profiles": {
"dotnet-WireMock.Net": {
"commandName": "Project",
"commandLineArgs": ""
}
}
}

View File

@@ -0,0 +1,61 @@
using System;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using WireMock.Admin.Requests;
using WireMock.Logging;
namespace WireMock
{
public class WireMockLogger : IWireMockLogger
{
private readonly JsonSerializerOptions options = new JsonSerializerOptions
{
WriteIndented = true
};
private readonly ILogger _logger;
public WireMockLogger(ILogger logger)
{
_logger = logger;
}
/// <see cref="IWireMockLogger.Debug"/>
public void Debug(string formatString, params object[] args)
{
_logger.LogDebug(formatString, args);
}
/// <see cref="IWireMockLogger.Info"/>
public void Info(string formatString, params object[] args)
{
_logger.LogInformation(formatString, args);
}
/// <see cref="IWireMockLogger.Warn"/>
public void Warn(string formatString, params object[] args)
{
_logger.LogWarning(formatString, args);
}
/// <see cref="IWireMockLogger.Error(string, object[])"/>
public void Error(string formatString, params object[] args)
{
_logger.LogError(formatString, args);
}
/// <see cref="IWireMockLogger.Error(string, Exception)"/>
public void Error(string formatString, Exception exception)
{
_logger.LogError(formatString, exception);
}
/// <see cref="IWireMockLogger.DebugRequestResponse"/>
public void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminRequest)
{
string message = JsonSerializer.Serialize(logEntryModel, options);
_logger.LogDebug("Admin[{IsAdmin}] {Message}", isAdminRequest, message);
}
}
}

View File

@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<PackAsTool>true</PackAsTool>
<ToolCommandName>dotnet-wiremock</ToolCommandName>
<Description>A dotnet commandline tool for WireMock.Net (A Lightweight Http Mocking Server for .NET)</Description>
<PackageTags>tdd;mock;http;wiremock;test;server;unittest;dotnet;tool;dotnet-tool</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Authors>Stef Heyenrath</Authors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" />
<PackageReference Include="System.Text.Json" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj" />
</ItemGroup>
</Project>

View File

@@ -16,9 +16,9 @@ namespace WireMock.Net.Tests.FluentAssertions
{
public class WireMockAssertionsTests : IDisposable
{
private WireMockServer _server;
private HttpClient _httpClient;
private int _portUsed;
private readonly WireMockServer _server;
private readonly HttpClient _httpClient;
private readonly int _portUsed;
public WireMockAssertionsTests()
{
@@ -289,6 +289,7 @@ namespace WireMock.Net.Tests.FluentAssertions
{
_server?.Stop();
_server?.Dispose();
_httpClient?.Dispose();
}
}
}

View File

@@ -0,0 +1,385 @@
using System;
using System.Collections.Generic;
using System.IO;
using FluentAssertions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NFluent;
using WireMock.Matchers;
using Xunit;
namespace WireMock.Net.Tests.Matchers
{
public class JsonPartialMatcherTests
{
[Fact]
public void JsonPartialMatcher_GetName()
{
// Assign
var matcher = new JsonPartialMatcher("{}");
// Act
string name = matcher.Name;
// Assert
Check.That(name).Equals("JsonPartialMatcher");
}
[Fact]
public void JsonPartialMatcher_GetValue()
{
// Assign
var matcher = new JsonPartialMatcher("{}");
// Act
object value = matcher.Value;
// Assert
Check.That(value).Equals("{}");
}
[Fact]
public void JsonPartialMatcher_WithInvalidStringValue_Should_ThrowException()
{
// Act
Action action = () => new JsonPartialMatcher(MatchBehaviour.AcceptOnMatch, "{ \"Id\"");
// Assert
action.Should().Throw<JsonException>();
}
[Fact]
public void JsonPartialMatcher_WithInvalidObjectValue_Should_ThrowException()
{
// Act
Action action = () => new JsonPartialMatcher(MatchBehaviour.AcceptOnMatch, new MemoryStream());
// Assert
action.Should().Throw<JsonException>();
}
[Fact]
public void JsonPartialMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsFalse_Should_ReturnMismatch()
{
// Assign
var matcher = new JsonPartialMatcher("");
// Act
double match = matcher.IsMatch(new MemoryStream());
// Assert
Check.That(match).IsEqualTo(0);
}
[Fact]
public void JsonPartialMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsTrue_Should_ReturnMismatch()
{
// Assign
var matcher = new JsonPartialMatcher("", false, true);
// Act
Action action = () => matcher.IsMatch(new MemoryStream());
// Assert
action.Should().Throw<JsonException>();
}
[Fact]
public void JsonPartialMatcher_IsMatch_ByteArray()
{
// Assign
var bytes = new byte[0];
var matcher = new JsonPartialMatcher("");
// Act
double match = matcher.IsMatch(bytes);
// Assert
Check.That(match).IsEqualTo(0);
}
[Fact]
public void JsonPartialMatcher_IsMatch_NullString()
{
// Assign
string s = null;
var matcher = new JsonPartialMatcher("");
// Act
double match = matcher.IsMatch(s);
// Assert
Check.That(match).IsEqualTo(0);
}
[Fact]
public void JsonPartialMatcher_IsMatch_NullObject()
{
// Assign
object o = null;
var matcher = new JsonPartialMatcher("");
// Act
double match = matcher.IsMatch(o);
// Assert
Check.That(match).IsEqualTo(0);
}
[Fact]
public void JsonPartialMatcher_IsMatch_JArray()
{
// Assign
var matcher = new JsonPartialMatcher(new[] { "x", "y" });
// Act
var jArray = new JArray
{
"x",
"y"
};
double match = matcher.IsMatch(jArray);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonPartialMatcher_IsMatch_JObject()
{
// Assign
var matcher = new JsonPartialMatcher(new { Id = 1, Name = "Test" });
// Act
var jobject = new JObject
{
{ "Id", new JValue(1) },
{ "Name", new JValue("Test") }
};
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonPartialMatcher_IsMatch_WithIgnoreCaseTrue_JObject()
{
// Assign
var matcher = new JsonPartialMatcher(new { id = 1, Name = "test" }, true);
// Act
var jobject = new JObject
{
{ "Id", new JValue(1) },
{ "NaMe", new JValue("Test") }
};
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonPartialMatcher_IsMatch_JObjectParsed()
{
// Assign
var matcher = new JsonPartialMatcher(new { Id = 1, Name = "Test" });
// Act
var jobject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }");
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonPartialMatcher_IsMatch_WithIgnoreCaseTrue_JObjectParsed()
{
// Assign
var matcher = new JsonPartialMatcher(new { Id = 1, Name = "TESt" }, true);
// Act
var jobject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }");
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonPartialMatcher_IsMatch_JArrayAsString()
{
// Assign
var matcher = new JsonPartialMatcher("[ \"x\", \"y\" ]");
// Act
var jArray = new JArray
{
"x",
"y"
};
double match = matcher.IsMatch(jArray);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonPartialMatcher_IsMatch_JObjectAsString()
{
// Assign
var matcher = new JsonPartialMatcher("{ \"Id\" : 1, \"Name\" : \"Test\" }");
// Act
var jobject = new JObject
{
{ "Id", new JValue(1) },
{ "Name", new JValue("Test") }
};
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonPartialMatcher_IsMatch_WithIgnoreCaseTrue_JObjectAsString()
{
// Assign
var matcher = new JsonPartialMatcher("{ \"Id\" : 1, \"Name\" : \"test\" }", true);
// Act
var jobject = new JObject
{
{ "Id", new JValue(1) },
{ "Name", new JValue("Test") }
};
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonPartialMatcher_IsMatch_JObjectAsString_RejectOnMatch()
{
// Assign
var matcher = new JsonPartialMatcher(MatchBehaviour.RejectOnMatch, "{ \"Id\" : 1, \"Name\" : \"Test\" }");
// Act
var jobject = new JObject
{
{ "Id", new JValue(1) },
{ "Name", new JValue("Test") }
};
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(0.0, match);
}
[Fact]
public void JsonPartialMatcher_IsMatch_JObjectWithDateTimeOffsetAsString()
{
// Assign
var matcher = new JsonPartialMatcher("{ \"preferredAt\" : \"2019-11-21T10:32:53.2210009+00:00\" }");
// Act
var jobject = new JObject
{
{ "preferredAt", new JValue("2019-11-21T10:32:53.2210009+00:00") }
};
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(1.0, match);
}
[Theory]
[InlineData("{\"test\":\"abc\"}", "{\"test\":\"abc\",\"other\":\"xyz\"}")]
[InlineData("\"test\"", "\"test\"")]
[InlineData("123", "123")]
[InlineData("[\"test\"]", "[\"test\"]")]
[InlineData("[\"test\"]", "[\"test\", \"other\"]")]
[InlineData("[123]", "[123]")]
[InlineData("[123]", "[123, 456]")]
[InlineData("{ \"test\":\"value\" }", "{\"test\":\"value\",\"other\":123}")]
[InlineData("{ \"test\":\"value\" }", "{\"test\":\"value\"}")]
[InlineData("{\"test\":{\"nested\":\"value\"}}", "{\"test\":{\"nested\":\"value\"}}")]
public void JsonPartialMatcher_IsMatch_StringInputValidMatch(string value, string input)
{
// Assign
var matcher = new JsonPartialMatcher(value);
// Act
double match = matcher.IsMatch(input);
// Assert
Assert.Equal(1.0, match);
}
[Theory]
[InlineData("\"test\"", null)]
[InlineData("\"test1\"", "\"test2\"")]
[InlineData("123", "1234")]
[InlineData("[\"test\"]", "[\"test1\"]")]
[InlineData("[\"test\"]", "[\"test1\", \"test2\"]")]
[InlineData("[123]", "[1234]")]
[InlineData("{}", "\"test\"")]
[InlineData("{ \"test\":\"value\" }", "{\"test\":\"value2\"}")]
[InlineData("{ \"test.nested\":\"value\" }", "{\"test\":{\"nested\":\"value1\"}}")]
[InlineData("{\"test\":{\"test1\":\"value\"}}", "{\"test\":{\"test1\":\"value1\"}}")]
[InlineData("[{ \"test.nested\":\"value\" }]", "[{\"test\":{\"nested\":\"value1\"}}]")]
public void JsonPartialMatcher_IsMatch_StringInputWithInvalidMatch(string value, string input)
{
// Assign
var matcher = new JsonPartialMatcher(value);
// Act
double match = matcher.IsMatch(input);
// Assert
Assert.Equal(0.0, match);
}
[Theory]
[InlineData("{ \"test.nested\":123 }", "{\"test\":{\"nested\":123}}")]
[InlineData("{ \"test.nested\":[123, 456] }", "{\"test\":{\"nested\":[123, 456]}}")]
[InlineData("{ \"test.nested\":\"value\" }", "{\"test\":{\"nested\":\"value\"}}")]
[InlineData("{ \"['name.with.dot']\":\"value\" }", "{\"name.with.dot\":\"value\"}")]
[InlineData("[{ \"test.nested\":\"value\" }]", "[{\"test\":{\"nested\":\"value\"}}]")]
[InlineData("[{ \"['name.with.dot']\":\"value\" }]", "[{\"name.with.dot\":\"value\"}]")]
public void JsonPartialMatcher_IsMatch_ValueAsJPathValidMatch(string value, string input)
{
// Assign
var matcher = new JsonPartialMatcher(value);
// Act
double match = matcher.IsMatch(input);
// Assert
Assert.Equal(1.0, match);
}
[Theory]
[InlineData("{ \"test.nested\":123 }", "{\"test\":{\"nested\":456}}")]
[InlineData("{ \"test.nested\":[123, 456] }", "{\"test\":{\"nested\":[1, 2]}}")]
[InlineData("{ \"test.nested\":\"value\" }", "{\"test\":{\"nested\":\"value1\"}}")]
[InlineData("{ \"['name.with.dot']\":\"value\" }", "{\"name.with.dot\":\"value1\"}")]
[InlineData("[{ \"test.nested\":\"value\" }]", "[{\"test\":{\"nested\":\"value1\"}}]")]
[InlineData("[{ \"['name.with.dot']\":\"value\" }]", "[{\"name.with.dot\":\"value1\"}]")]
public void JsonPartialMatcher_IsMatch_ValueAsJPathInvalidMatch(string value, string input)
{
// Assign
var matcher = new JsonPartialMatcher(value);
// Act
double match = matcher.IsMatch(input);
// Assert
Assert.Equal(0.0, match);
}
}
}

View File

@@ -69,6 +69,8 @@ namespace WireMock.Net.Tests
// Assert
Check.That(count).Equals(1);
server.Dispose();
}
[Fact]
@@ -105,6 +107,8 @@ namespace WireMock.Net.Tests
// Assert
Check.That(countResponsesWithStatusNotOk).Equals(0);
Check.That(count).Equals(expectedCount);
server.Dispose();
}
}
}

View File

@@ -1,141 +1,250 @@
using System;
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Moq;
using Xunit;
using WireMock.Models;
using WireMock.Owin;
using WireMock.Owin.Mappers;
using WireMock.Util;
using WireMock.Logging;
using WireMock.Matchers;
using System.Collections.Generic;
using WireMock.Admin.Mappings;
using WireMock.Admin.Requests;
#if NET452
using Microsoft.Owin;
using IContext = Microsoft.Owin.IOwinContext;
using IRequest = Microsoft.Owin.IOwinRequest;
using IResponse = Microsoft.Owin.IOwinResponse;
#else
using Microsoft.AspNetCore.Http;
using IContext = Microsoft.AspNetCore.Http.HttpContext;
using IRequest = Microsoft.AspNetCore.Http.HttpRequest;
using IResponse = Microsoft.AspNetCore.Http.HttpResponse;
#endif
namespace WireMock.Net.Tests.Owin
{
public class WireMockMiddlewareTests
{
private readonly WireMockMiddleware _sut;
private readonly Mock<IWireMockMiddlewareOptions> _optionsMock;
private readonly Mock<IOwinRequestMapper> _requestMapperMock;
private readonly Mock<IOwinResponseMapper> _responseMapperMock;
private readonly Mock<IMappingMatcher> _matcherMock;
private readonly Mock<IMapping> _mappingMock;
private readonly Mock<IContext> _contextMock;
public WireMockMiddlewareTests()
{
_optionsMock = new Mock<IWireMockMiddlewareOptions>();
_optionsMock.SetupAllProperties();
_optionsMock.Setup(o => o.Mappings).Returns(new ConcurrentDictionary<Guid, IMapping>());
_optionsMock.Setup(o => o.LogEntries).Returns(new ConcurrentObservableCollection<LogEntry>());
_optionsMock.Setup(o => o.Scenarios).Returns(new ConcurrentDictionary<string, ScenarioState>());
_optionsMock.Setup(o => o.Logger.Warn(It.IsAny<string>(), It.IsAny<object[]>()));
_optionsMock.Setup(o => o.Logger.Error(It.IsAny<string>(), It.IsAny<object[]>()));
_optionsMock.Setup(o => o.Logger.DebugRequestResponse(It.IsAny<LogEntryModel>(), It.IsAny<bool>()));
_requestMapperMock = new Mock<IOwinRequestMapper>();
_requestMapperMock.SetupAllProperties();
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1");
_requestMapperMock.Setup(m => m.MapAsync(It.IsAny<IRequest>(), It.IsAny<IWireMockMiddlewareOptions>())).ReturnsAsync(request);
_responseMapperMock = new Mock<IOwinResponseMapper>();
_responseMapperMock.SetupAllProperties();
_responseMapperMock.Setup(m => m.MapAsync(It.IsAny<ResponseMessage>(), It.IsAny<IResponse>())).Returns(Task.FromResult(true));
_matcherMock = new Mock<IMappingMatcher>();
_matcherMock.SetupAllProperties();
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((new MappingMatcherResult(), new MappingMatcherResult()));
_contextMock = new Mock<IContext>();
_mappingMock = new Mock<IMapping>();
_sut = new WireMockMiddleware(null, _optionsMock.Object, _requestMapperMock.Object, _responseMapperMock.Object, _matcherMock.Object);
}
[Fact]
public async void WireMockMiddleware_Invoke_NoMatch()
{
// Act
await _sut.Invoke(_contextMock.Object);
// Assert and Verify
_optionsMock.Verify(o => o.Logger.Warn(It.IsAny<string>(), It.IsAny<object[]>()), Times.Once);
Expression<Func<ResponseMessage, bool>> match = r => (int)r.StatusCode == 404 && ((StatusModel)r.BodyData.BodyAsJson).Status == "No matching mapping found";
_responseMapperMock.Verify(m => m.MapAsync(It.Is(match), It.IsAny<IResponse>()), Times.Once);
}
[Fact]
public async void WireMockMiddleware_Invoke_IsAdminInterface_EmptyHeaders_401()
{
// Assign
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1", null, new Dictionary<string, string[]>());
_requestMapperMock.Setup(m => m.MapAsync(It.IsAny<IRequest>(), It.IsAny<IWireMockMiddlewareOptions>())).ReturnsAsync(request);
_optionsMock.SetupGet(o => o.AuthorizationMatcher).Returns(new ExactMatcher());
_mappingMock.SetupGet(m => m.IsAdminInterface).Returns(true);
var result = new MappingMatcherResult { Mapping = _mappingMock.Object };
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((result, result));
// Act
await _sut.Invoke(_contextMock.Object);
// Assert and Verify
_optionsMock.Verify(o => o.Logger.Error(It.IsAny<string>(), It.IsAny<object[]>()), Times.Once);
Expression<Func<ResponseMessage, bool>> match = r => (int)r.StatusCode == 401;
_responseMapperMock.Verify(m => m.MapAsync(It.Is(match), It.IsAny<IResponse>()), Times.Once);
}
[Fact]
public async void WireMockMiddleware_Invoke_IsAdminInterface_MissingHeader_401()
{
// Assign
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1", null, new Dictionary<string, string[]> { { "h", new[] { "x" } } });
_requestMapperMock.Setup(m => m.MapAsync(It.IsAny<IRequest>(), It.IsAny<IWireMockMiddlewareOptions>())).ReturnsAsync(request);
_optionsMock.SetupGet(o => o.AuthorizationMatcher).Returns(new ExactMatcher());
_mappingMock.SetupGet(m => m.IsAdminInterface).Returns(true);
var result = new MappingMatcherResult { Mapping = _mappingMock.Object };
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((result, result));
// Act
await _sut.Invoke(_contextMock.Object);
// Assert and Verify
_optionsMock.Verify(o => o.Logger.Error(It.IsAny<string>(), It.IsAny<object[]>()), Times.Once);
Expression<Func<ResponseMessage, bool>> match = r => (int)r.StatusCode == 401;
_responseMapperMock.Verify(m => m.MapAsync(It.Is(match), It.IsAny<IResponse>()), Times.Once);
}
[Fact]
public async void WireMockMiddleware_Invoke_RequestLogExpirationDurationIsDefined()
{
// Assign
_optionsMock.SetupGet(o => o.RequestLogExpirationDuration).Returns(1);
// Act
await _sut.Invoke(_contextMock.Object);
}
}
using System;
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Moq;
using Xunit;
using WireMock.Models;
using WireMock.Owin;
using WireMock.Owin.Mappers;
using WireMock.Util;
using WireMock.Logging;
using WireMock.Matchers;
using System.Collections.Generic;
using WireMock.Admin.Mappings;
using WireMock.Admin.Requests;
using WireMock.ResponseProviders;
using WireMock.Settings;
using FluentAssertions;
using WireMock.Handlers;
using WireMock.ResponseBuilders;
using WireMock.RequestBuilders;
#if NET452
using Microsoft.Owin;
using IContext = Microsoft.Owin.IOwinContext;
using IRequest = Microsoft.Owin.IOwinRequest;
using IResponse = Microsoft.Owin.IOwinResponse;
#else
using Microsoft.AspNetCore.Http;
using IContext = Microsoft.AspNetCore.Http.HttpContext;
using IRequest = Microsoft.AspNetCore.Http.HttpRequest;
using IResponse = Microsoft.AspNetCore.Http.HttpResponse;
#endif
namespace WireMock.Net.Tests.Owin
{
public class WireMockMiddlewareTests
{
private readonly WireMockMiddleware _sut;
private readonly Mock<IWireMockMiddlewareOptions> _optionsMock;
private readonly Mock<IOwinRequestMapper> _requestMapperMock;
private readonly Mock<IOwinResponseMapper> _responseMapperMock;
private readonly Mock<IMappingMatcher> _matcherMock;
private readonly Mock<IMapping> _mappingMock;
private readonly Mock<IContext> _contextMock;
private readonly ConcurrentDictionary<Guid, IMapping> _mappings = new ConcurrentDictionary<Guid, IMapping>();
public WireMockMiddlewareTests()
{
_optionsMock = new Mock<IWireMockMiddlewareOptions>();
_optionsMock.SetupAllProperties();
_optionsMock.Setup(o => o.Mappings).Returns(_mappings);
_optionsMock.Setup(o => o.LogEntries).Returns(new ConcurrentObservableCollection<LogEntry>());
_optionsMock.Setup(o => o.Scenarios).Returns(new ConcurrentDictionary<string, ScenarioState>());
_optionsMock.Setup(o => o.Logger.Warn(It.IsAny<string>(), It.IsAny<object[]>()));
_optionsMock.Setup(o => o.Logger.Error(It.IsAny<string>(), It.IsAny<object[]>()));
_optionsMock.Setup(o => o.Logger.DebugRequestResponse(It.IsAny<LogEntryModel>(), It.IsAny<bool>()));
_requestMapperMock = new Mock<IOwinRequestMapper>();
_requestMapperMock.SetupAllProperties();
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1");
_requestMapperMock.Setup(m => m.MapAsync(It.IsAny<IRequest>(), It.IsAny<IWireMockMiddlewareOptions>())).ReturnsAsync(request);
_responseMapperMock = new Mock<IOwinResponseMapper>();
_responseMapperMock.SetupAllProperties();
_responseMapperMock.Setup(m => m.MapAsync(It.IsAny<ResponseMessage>(), It.IsAny<IResponse>())).Returns(Task.FromResult(true));
_matcherMock = new Mock<IMappingMatcher>();
_matcherMock.SetupAllProperties();
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((new MappingMatcherResult(), new MappingMatcherResult()));
_contextMock = new Mock<IContext>();
_mappingMock = new Mock<IMapping>();
_sut = new WireMockMiddleware(null, _optionsMock.Object, _requestMapperMock.Object, _responseMapperMock.Object, _matcherMock.Object);
}
[Fact]
public async void WireMockMiddleware_Invoke_NoMatch()
{
// Act
await _sut.Invoke(_contextMock.Object);
// Assert and Verify
_optionsMock.Verify(o => o.Logger.Warn(It.IsAny<string>(), It.IsAny<object[]>()), Times.Once);
Expression<Func<ResponseMessage, bool>> match = r => (int)r.StatusCode == 404 && ((StatusModel)r.BodyData.BodyAsJson).Status == "No matching mapping found";
_responseMapperMock.Verify(m => m.MapAsync(It.Is(match), It.IsAny<IResponse>()), Times.Once);
}
[Fact]
public async void WireMockMiddleware_Invoke_IsAdminInterface_EmptyHeaders_401()
{
// Assign
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1", null, new Dictionary<string, string[]>());
_requestMapperMock.Setup(m => m.MapAsync(It.IsAny<IRequest>(), It.IsAny<IWireMockMiddlewareOptions>())).ReturnsAsync(request);
_optionsMock.SetupGet(o => o.AuthorizationMatcher).Returns(new ExactMatcher());
_mappingMock.SetupGet(m => m.IsAdminInterface).Returns(true);
var result = new MappingMatcherResult { Mapping = _mappingMock.Object };
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((result, result));
// Act
await _sut.Invoke(_contextMock.Object);
// Assert and Verify
_optionsMock.Verify(o => o.Logger.Error(It.IsAny<string>(), It.IsAny<object[]>()), Times.Once);
Expression<Func<ResponseMessage, bool>> match = r => (int)r.StatusCode == 401;
_responseMapperMock.Verify(m => m.MapAsync(It.Is(match), It.IsAny<IResponse>()), Times.Once);
}
[Fact]
public async void WireMockMiddleware_Invoke_IsAdminInterface_MissingHeader_401()
{
// Assign
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1", null, new Dictionary<string, string[]> { { "h", new[] { "x" } } });
_requestMapperMock.Setup(m => m.MapAsync(It.IsAny<IRequest>(), It.IsAny<IWireMockMiddlewareOptions>())).ReturnsAsync(request);
_optionsMock.SetupGet(o => o.AuthorizationMatcher).Returns(new ExactMatcher());
_mappingMock.SetupGet(m => m.IsAdminInterface).Returns(true);
var result = new MappingMatcherResult { Mapping = _mappingMock.Object };
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((result, result));
// Act
await _sut.Invoke(_contextMock.Object);
// Assert and Verify
_optionsMock.Verify(o => o.Logger.Error(It.IsAny<string>(), It.IsAny<object[]>()), Times.Once);
Expression<Func<ResponseMessage, bool>> match = r => (int)r.StatusCode == 401;
_responseMapperMock.Verify(m => m.MapAsync(It.Is(match), It.IsAny<IResponse>()), Times.Once);
}
[Fact]
public async void WireMockMiddleware_Invoke_RequestLogExpirationDurationIsDefined()
{
// Assign
_optionsMock.SetupGet(o => o.RequestLogExpirationDuration).Returns(1);
// Act
await _sut.Invoke(_contextMock.Object);
}
[Fact]
public async void WireMockMiddleware_Invoke_Mapping_Has_ProxyAndRecordSettings_And_SaveMapping_Is_True()
{
// Assign
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1", null, new Dictionary<string, string[]>());
_requestMapperMock.Setup(m => m.MapAsync(It.IsAny<IRequest>(), It.IsAny<IWireMockMiddlewareOptions>())).ReturnsAsync(request);
_optionsMock.SetupGet(o => o.AuthorizationMatcher).Returns(new ExactMatcher());
var fileSystemHandlerMock = new Mock<IFileSystemHandler>();
fileSystemHandlerMock.Setup(f => f.GetMappingFolder()).Returns("m");
var logger = new Mock<IWireMockLogger>();
var proxyAndRecordSettings = new ProxyAndRecordSettings
{
SaveMapping = true,
SaveMappingToFile = true
};
var settings = new WireMockServerSettings
{
FileSystemHandler = fileSystemHandlerMock.Object,
Logger = logger.Object
};
var responseBuilder = Response.Create().WithProxy(proxyAndRecordSettings);
_mappingMock.SetupGet(m => m.Provider).Returns(responseBuilder);
_mappingMock.SetupGet(m => m.Settings).Returns(settings);
_mappingMock.Setup(m => m.ProvideResponseAsync(It.IsAny<RequestMessage>())).ReturnsAsync(new ResponseMessage());
var requestBuilder = Request.Create().UsingAnyMethod();
_mappingMock.SetupGet(m => m.RequestMatcher).Returns(requestBuilder);
var result = new MappingMatcherResult { Mapping = _mappingMock.Object };
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((result, result));
// Act
await _sut.Invoke(_contextMock.Object);
// Assert and Verify
fileSystemHandlerMock.Verify(f => f.WriteMappingFile(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
_mappings.Count.Should().Be(1);
}
[Fact]
public async void WireMockMiddleware_Invoke_Mapping_Has_ProxyAndRecordSettings_And_SaveMapping_Is_False_But_WireMockServerSettings_SaveMapping_Is_True()
{
// Assign
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1", null, new Dictionary<string, string[]>());
_requestMapperMock.Setup(m => m.MapAsync(It.IsAny<IRequest>(), It.IsAny<IWireMockMiddlewareOptions>())).ReturnsAsync(request);
_optionsMock.SetupGet(o => o.AuthorizationMatcher).Returns(new ExactMatcher());
var fileSystemHandlerMock = new Mock<IFileSystemHandler>();
fileSystemHandlerMock.Setup(f => f.GetMappingFolder()).Returns("m");
var logger = new Mock<IWireMockLogger>();
var proxyAndRecordSettings = new ProxyAndRecordSettings
{
SaveMapping = false,
SaveMappingToFile = false
};
var settings = new WireMockServerSettings
{
FileSystemHandler = fileSystemHandlerMock.Object,
Logger = logger.Object,
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
SaveMapping = true,
SaveMappingToFile = true
}
};
var responseBuilder = Response.Create().WithProxy(proxyAndRecordSettings);
_mappingMock.SetupGet(m => m.Provider).Returns(responseBuilder);
_mappingMock.SetupGet(m => m.Settings).Returns(settings);
_mappingMock.Setup(m => m.ProvideResponseAsync(It.IsAny<RequestMessage>())).ReturnsAsync(new ResponseMessage());
var requestBuilder = Request.Create().UsingAnyMethod();
_mappingMock.SetupGet(m => m.RequestMatcher).Returns(requestBuilder);
var result = new MappingMatcherResult { Mapping = _mappingMock.Object };
_matcherMock.Setup(m => m.FindBestMatch(It.IsAny<RequestMessage>())).Returns((result, result));
// Act
await _sut.Invoke(_contextMock.Object);
// Assert and Verify
fileSystemHandlerMock.Verify(f => f.WriteMappingFile(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
_mappings.Count.Should().Be(1);
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
using FluentAssertions;
using WireMock.Matchers;
using WireMock.Plugin;
using Xunit;
namespace WireMock.Net.Tests.Plugin
{
public class PluginLoaderTests
{
public interface IDummy
{
}
[Fact]
public void Load_Valid()
{
// Act
var result = PluginLoader.Load<ICSharpCodeMatcher>(MatchBehaviour.AcceptOnMatch, "x");
// Assert
result.Should().NotBeNull();
}
[Fact]
public void Load_Invalid_ThrowsException()
{
// Act
Action a = () => PluginLoader.Load<IDummy>();
// Assert
a.Should().Throw<DllNotFoundException>();
}
}
}

View File

@@ -41,6 +41,8 @@ namespace WireMock.Net.Tests.ResponseBuilders
// Assert
response.Should().Contain("<hello>world</hello>");
server.Stop();
}
[Fact]
@@ -70,6 +72,8 @@ namespace WireMock.Net.Tests.ResponseBuilders
// Assert
response.Should().Contain("<hello>world</hello>");
server.Stop();
}
[Fact]
@@ -99,6 +103,8 @@ namespace WireMock.Net.Tests.ResponseBuilders
// Assert
response.Should().Contain("<hello>world</hello>");
server.Stop();
}
}
}

View File

@@ -1,6 +1,5 @@
using FluentAssertions;
using Moq;
using System.Threading.Tasks;
using System.Threading.Tasks;
using FluentAssertions;
using WireMock.Models;
using WireMock.ResponseBuilders;
using WireMock.Settings;

View File

@@ -82,6 +82,7 @@ namespace WireMock.Net.Tests.ResponseBuilders
public void Dispose()
{
_server?.Stop();
_server?.Dispose();
}
}

View File

@@ -221,5 +221,85 @@ namespace WireMock.Net.Tests.Serialization
matcher.MatchBehaviour.Should().Be(MatchBehaviour.AcceptOnMatch);
matcher.Value.Should().BeEquivalentTo(patterns);
}
[Fact]
public void MatcherMapper_Map_MatcherModel_JsonPartialMatcher_Pattern_As_String()
{
// Assign
var pattern = "{ \"AccountIds\": [ 1, 2, 3 ] }";
var model = new MatcherModel
{
Name = "JsonPartialMatcher",
Pattern = pattern
};
// Act
var matcher = (JsonPartialMatcher)_sut.Map(model);
// Assert
matcher.MatchBehaviour.Should().Be(MatchBehaviour.AcceptOnMatch);
matcher.Value.Should().BeEquivalentTo(pattern);
}
[Fact]
public void MatcherMapper_Map_MatcherModel_JsonPartialMatcher_Patterns_As_String()
{
// Assign
var pattern1 = "{ \"AccountIds\": [ 1, 2, 3 ] }";
var pattern2 = "{ \"X\": \"x\" }";
var patterns = new[] { pattern1, pattern2 };
var model = new MatcherModel
{
Name = "JsonPartialMatcher",
Pattern = patterns
};
// Act
var matcher = (JsonPartialMatcher)_sut.Map(model);
// Assert
matcher.MatchBehaviour.Should().Be(MatchBehaviour.AcceptOnMatch);
matcher.Value.Should().BeEquivalentTo(patterns);
}
[Fact]
public void MatcherMapper_Map_MatcherModel_JsonPartialMatcher_Pattern_As_Object()
{
// Assign
var pattern = new { AccountIds = new[] { 1, 2, 3 } };
var model = new MatcherModel
{
Name = "JsonPartialMatcher",
Pattern = pattern
};
// Act
var matcher = (JsonPartialMatcher)_sut.Map(model);
// Assert
matcher.MatchBehaviour.Should().Be(MatchBehaviour.AcceptOnMatch);
matcher.Value.Should().BeEquivalentTo(pattern);
}
[Fact]
public void MatcherMapper_Map_MatcherModel_JsonPartialMatcher_Patterns_As_Object()
{
// Assign
object pattern1 = new { AccountIds = new[] { 1, 2, 3 } };
object pattern2 = new { X = "x" };
var patterns = new[] { pattern1, pattern2 };
var model = new MatcherModel
{
Name = "JsonPartialMatcher",
Patterns = patterns
};
// Act
var matcher = (JsonMatcher)_sut.Map(model);
// Assert
matcher.MatchBehaviour.Should().Be(MatchBehaviour.AcceptOnMatch);
matcher.Value.Should().BeEquivalentTo(patterns);
}
}
}
}

View File

@@ -20,6 +20,50 @@ namespace WireMock.Net.Tests.Serialization
_sut = new MatcherMapper(_settings);
}
[Fact]
public void MatcherModelMapper_Map_CSharpCodeMatcher()
{
// Assign
var model = new MatcherModel
{
Name = "CSharpCodeMatcher",
Patterns = new[] { "return it == \"x\";" }
};
var sut = new MatcherMapper(new WireMockServerSettings { AllowCSharpCodeMatcher = true });
// Act 1
var matcher1 = (ICSharpCodeMatcher)sut.Map(model);
// Assert 1
matcher1.Should().NotBeNull();
matcher1.IsMatch("x").Should().Be(1.0d);
// Act 2
var matcher2 = (ICSharpCodeMatcher)sut.Map(model);
// Assert 2
matcher2.Should().NotBeNull();
matcher2.IsMatch("x").Should().Be(1.0d);
}
[Fact]
public void MatcherModelMapper_Map_CSharpCodeMatcher_NotAllowed_ThrowsException()
{
// Assign
var model = new MatcherModel
{
Name = "CSharpCodeMatcher",
Patterns = new[] { "x" }
};
var sut = new MatcherMapper(new WireMockServerSettings { AllowCSharpCodeMatcher = false });
// Act
Action action = () => sut.Map(model);
// Assert
action.Should().Throw<NotSupportedException>();
}
[Fact]
public void MatcherModelMapper_Map_Null()
{

View File

@@ -32,6 +32,8 @@ namespace WireMock.Net.Tests
// then
Check.That(response.StatusCode).IsEqualTo(HttpStatusCode.NotFound);
server.Stop();
}
[Fact]
@@ -60,6 +62,8 @@ namespace WireMock.Net.Tests
// then
Check.That(responseNoState).Equals("No state msg");
Check.That(responseWithState).Equals("Test state msg");
server.Stop();
}
[Fact]
@@ -94,6 +98,8 @@ namespace WireMock.Net.Tests
responseScenario1.Should().Be(body1);
responseScenario2.Should().Be(body1);
responseWithState.Should().Be(body2);
server.Stop();
}
[Fact]
@@ -143,6 +149,8 @@ namespace WireMock.Net.Tests
t2a.Should().Be(body2);
t2b.Should().Be(body2);
t3.Should().Be(body3);
server.Stop();
}
[Fact]
@@ -171,6 +179,8 @@ namespace WireMock.Net.Tests
// then
Check.That(responseIntScenario).Equals("Scenario 1, Setting State 2");
Check.That(responseWithIntState).Equals("Scenario 1, State 2");
server.Stop();
}
[Fact]
@@ -199,6 +209,8 @@ namespace WireMock.Net.Tests
// then
Check.That(responseIntScenario).Equals("string state, Setting State 2");
Check.That(responseWithIntState).Equals("string state, State 2");
server.Stop();
}
[Fact]
@@ -227,6 +239,8 @@ namespace WireMock.Net.Tests
// then
Check.That(responseIntScenario).Equals("int state, Setting State 2");
Check.That(responseWithIntState).Equals("string state, State 2");
server.Stop();
}
[Fact]
@@ -281,6 +295,8 @@ namespace WireMock.Net.Tests
Check.That(server.Scenarios["To do list"].NextState).IsNull();
Check.That(server.Scenarios["To do list"].Started).IsTrue();
Check.That(server.Scenarios["To do list"].Finished).IsTrue();
server.Stop();
}
[Fact]
@@ -326,6 +342,8 @@ namespace WireMock.Net.Tests
var responseWithState2 = await new HttpClient().GetStringAsync(url + "/foo2X");
Check.That(responseWithState2).Equals("Test state msg 2");
server.Stop();
}
}
}

View File

@@ -0,0 +1,30 @@
using System.Text;
using FluentAssertions;
using WireMock.Util;
using Xunit;
namespace WireMock.Net.Tests.Util
{
public class BytesEncodingUtilsTests
{
[Fact]
public void TryGetEncoding_UTF32()
{
var result = BytesEncodingUtils.TryGetEncoding(new byte[] { 0xff, 0xfe, 0x00, 0x00 }, out Encoding encoding);
// Assert
result.Should().BeTrue();
encoding.CodePage.Should().Be(Encoding.UTF32.CodePage);
}
[Fact]
public void TryGetEncoding_Invalid()
{
var result = BytesEncodingUtils.TryGetEncoding(new byte[] { 0xff }, out Encoding encoding);
// Assert
result.Should().BeFalse();
encoding.Should().BeNull();
}
}
}

View File

@@ -2,18 +2,16 @@
<PropertyGroup>
<Authors>Stef Heyenrath</Authors>
<!--<TargetFrameworks>net452;netcoreapp2.1</TargetFrameworks>-->
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFrameworks>net452;net461;netcoreapp3.1;net5.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<DebugType>full</DebugType>
<AssemblyName>WireMock.Net.Tests</AssemblyName>
<PackageId>WireMock.Net.Tests</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<ProjectGuid>{31DC2EF8-C3FE-467D-84BE-FB5D956E612E}</ProjectGuid>
<!-- https://github.com/tonerdo/coverlet/issues/6 -->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<SonarQubeTestProject>True</SonarQubeTestProject>
<SonarQubeExclude>True</SonarQubeExclude>
<!--<SonarQubeTestProject>True</SonarQubeTestProject>
<SonarQubeExclude>True</SonarQubeExclude>-->
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../../src/WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
@@ -25,39 +23,43 @@
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net.FluentAssertions\WireMock.Net.FluentAssertions.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net.Matchers.CSharpCode\WireMock.Net.Matchers.CSharpCode.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net.RestClient\WireMock.Net.RestClient.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Codecov" Version="1.10.0" />
<PackageReference Include="coverlet.msbuild" Version="2.8.1">
<PackageReference Include="coverlet.msbuild" Version="3.0.0-preview.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.0.0-preview.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Moq" Version="4.13.1" />
<PackageReference Include="System.Threading" Version="4.3.0" />
<PackageReference Include="RestEase" Version="1.4.10" />
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.12" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="Moq" Version="4.14.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NFluent" Version="2.7.0" />
<PackageReference Include="OpenCover" Version="4.7.922" />
<PackageReference Include="ReportGenerator" Version="4.6.7" />
<!--<PackageReference Include="OpenCover" Version="4.7.922" />-->
<!--<PackageReference Include="ReportGenerator" Version="4.8.1" />-->
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.12" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<!--<PackageReference Include="StrongNamer" Version="0.0.8" />-->
</ItemGroup>
@@ -66,10 +68,6 @@
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="Microsoft.AspNetCore" Version="2.1.4" />
</ItemGroup>
<ItemGroup>
<None Update="responsebody.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

View File

@@ -1,4 +1,5 @@
using System;
#if !NET452 && !NET461
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
@@ -552,4 +553,5 @@ namespace WireMock.Net.Tests
server.Stop();
}
}
}
}
#endif

View File

@@ -31,16 +31,6 @@ namespace WireMock.Net.Tests
return current;
}
[Fact]
public void WireMockServer_Admin_StartStop()
{
var server1 = WireMockServer.Start("http://localhost:19091");
Check.That(server1.Urls[0]).Equals("http://localhost:19091");
server1.Stop();
}
[Fact]
public void WireMockServer_Admin_ResetMappings()
{
@@ -57,6 +47,8 @@ namespace WireMock.Net.Tests
// Assert
Check.That(server.Mappings).HasSize(0);
Check.That(server.MappingModels).HasSize(0);
server.Stop();
}
[Fact]
@@ -106,6 +98,8 @@ namespace WireMock.Net.Tests
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(guid);
Check.That(mappings.First().Title).Equals(title);
server.Stop();
}
[Fact]
@@ -124,6 +118,8 @@ namespace WireMock.Net.Tests
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(Guid.Parse(guid));
Check.That(mappings.First().Title).IsNullOrEmpty();
server.Stop();
}
[Fact]
@@ -136,6 +132,8 @@ namespace WireMock.Net.Tests
var mappings = server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
server.Stop();
}
[Fact]
@@ -164,6 +162,8 @@ namespace WireMock.Net.Tests
Check.That(mappings.First().Provider).IsNotNull();
Check.That(mappings.First().Guid).Equals(Guid.Parse(guid));
Check.That(mappings.First().Title).IsNullOrEmpty();
server.Stop();
}
[Fact]
@@ -219,6 +219,8 @@ namespace WireMock.Net.Tests
var mappings = server.Mappings.ToArray();
Check.That(mappings).HasSize(6);
server.Stop();
}
[Fact]
@@ -257,6 +259,8 @@ namespace WireMock.Net.Tests
var mappings = server.Mappings.ToArray();
Check.That(mappings).HasSize(2);
server.Stop();
}
[Fact]
@@ -270,6 +274,8 @@ namespace WireMock.Net.Tests
var mappings = server.Mappings.ToArray();
Check.That(mappings).HasSize(1);
server.Stop();
}
[Fact]
@@ -296,6 +302,8 @@ namespace WireMock.Net.Tests
Check.That(mappings2).HasSize(1);
Check.That(mappings2.First().Guid).Equals(guid);
Check.That(mappings2.First().Provider).Equals(response2);
server.Stop();
}
[Fact]
@@ -320,6 +328,8 @@ namespace WireMock.Net.Tests
// then
Check.That((int)response.StatusCode).IsEqualTo(400);
server.Stop();
}
[Fact]
@@ -336,6 +346,8 @@ namespace WireMock.Net.Tests
var requestLogged = server.LogEntries.First();
Check.That(requestLogged.RequestMessage.Method).IsEqualTo("GET");
Check.That(requestLogged.RequestMessage.BodyData).IsNull();
server.Stop();
}
[Fact]
@@ -359,6 +371,8 @@ namespace WireMock.Net.Tests
var requestLoggedB = server.LogEntries.Last();
Check.That(requestLoggedB.RequestMessage.Path).EndsWith("/foo3");
server.Stop();
}
[Fact]

View File

@@ -22,6 +22,8 @@ namespace WireMock.Net.Tests
Check.That(options.AuthorizationMatcher.Name).IsEqualTo("RegexMatcher");
Check.That(options.AuthorizationMatcher.MatchBehaviour).IsEqualTo(MatchBehaviour.AcceptOnMatch);
Check.That(options.AuthorizationMatcher.GetPatterns()).ContainsExactly("^(?i)BASIC eDp5$");
server.Stop();
}
[Fact]
@@ -37,6 +39,8 @@ namespace WireMock.Net.Tests
// Assert
var options = server.GetPrivateFieldValue<IWireMockMiddlewareOptions>("_options");
Check.That(options.AuthorizationMatcher).IsNull();
server.Stop();
}
}
}

View File

@@ -6,20 +6,116 @@ using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using FluentAssertions;
using Moq;
using NFluent;
using WireMock.Admin.Mappings;
using WireMock.Logging;
using WireMock.Handlers;
using WireMock.Matchers.Request;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using WireMock.Settings;
using WireMock.Util;
using Xunit;
namespace WireMock.Net.Tests
{
public class WireMockServerProxyTests
{
[Fact(Skip = "Fails in Linux CI")]
public async Task WireMockServer_ProxySSL_Should_log_proxied_requests()
{
// Assign
var settings = new WireMockServerSettings
{
UseSSL = true,
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = "https://www.google.com",
SaveMapping = true,
SaveMappingToFile = false
}
};
var server = WireMockServer.Start(settings);
// Act
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(server.Urls[0])
};
var httpClientHandler = new HttpClientHandler { AllowAutoRedirect = false };
await new HttpClient(httpClientHandler).SendAsync(requestMessage);
// Assert
Check.That(server.Mappings).HasSize(2);
Check.That(server.LogEntries).HasSize(1);
}
[Fact]
public async Task WireMockServer_Proxy_With_SaveMapping_Is_True_And_SaveMappingToFile_Is_False_Should_AddInternalMappingOnly()
{
// Assign
var settings = new WireMockServerSettings
{
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = "http://www.google.com",
SaveMapping = true,
SaveMappingToFile = false
}
};
var server = WireMockServer.Start(settings);
// Act
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(server.Urls[0])
};
var httpClientHandler = new HttpClientHandler { AllowAutoRedirect = false };
await new HttpClient(httpClientHandler).SendAsync(requestMessage);
// Assert
server.Mappings.Should().HaveCount(2);
}
[Fact]
public async Task WireMockServer_Proxy_With_SaveMapping_Is_False_And_SaveMappingToFile_Is_True_ShouldSaveMappingToFile()
{
// Assign
var fileSystemHandlerMock = new Mock<IFileSystemHandler>();
fileSystemHandlerMock.Setup(f => f.GetMappingFolder()).Returns("m");
var settings = new WireMockServerSettings
{
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = "http://www.google.com",
SaveMapping = false,
SaveMappingToFile = true
},
FileSystemHandler = fileSystemHandlerMock.Object
};
var server = WireMockServer.Start(settings);
// Act
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(server.Urls[0])
};
var httpClientHandler = new HttpClientHandler { AllowAutoRedirect = false };
await new HttpClient(httpClientHandler).SendAsync(requestMessage);
// Assert
server.Mappings.Should().HaveCount(1);
// Verify
fileSystemHandlerMock.Verify(f => f.WriteMappingFile(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
}
[Fact]
public async Task WireMockServer_Proxy_Should_log_proxied_requests()
{
@@ -45,8 +141,8 @@ namespace WireMock.Net.Tests
await new HttpClient(httpClientHandler).SendAsync(requestMessage);
// Assert
Check.That(server.Mappings).HasSize(2);
Check.That(server.LogEntries).HasSize(1);
server.Mappings.Should().HaveCount(2);
server.LogEntries.Should().HaveCount(1);
}
[Fact]
@@ -73,6 +169,8 @@ namespace WireMock.Net.Tests
Check.That(server.Mappings).HasSize(1);
Check.That(server.LogEntries).HasSize(1);
Check.That(content).Contains("google");
server.Stop();
}
[Fact]
@@ -116,10 +214,56 @@ namespace WireMock.Net.Tests
// check that new proxied mapping is added
Check.That(server.Mappings).HasSize(2);
}
//var newMapping = _server.Mappings.First(m => m.Guid != guid);
//var matcher = ((Request)newMapping.RequestMatcher).GetRequestMessageMatchers<RequestMessageHeaderMatcher>().FirstOrDefault(m => m.Name == "bbb");
//Check.That(matcher).IsNotNull();
[Fact]
public async Task WireMockServer_Proxy_Should_preserve_Authorization_header_in_proxied_request()
{
// Assign
string path = $"/prx_{Guid.NewGuid()}";
var serverForProxyForwarding = WireMockServer.Start();
serverForProxyForwarding
.Given(Request.Create().WithPath(path))
.RespondWith(Response.Create().WithCallback(x => new ResponseMessage
{
BodyData = new BodyData
{
BodyAsString = x.Headers["Authorization"].ToString(),
DetectedBodyType = Types.BodyType.String
}
}));
var settings = new WireMockServerSettings
{
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = serverForProxyForwarding.Urls[0],
SaveMapping = true,
SaveMappingToFile = false
}
};
var server = WireMockServer.Start(settings);
// Act
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri($"{server.Urls[0]}{path}"),
Content = new StringContent("stringContent", Encoding.ASCII)
};
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("BASIC", "test-A");
var result = await new HttpClient().SendAsync(requestMessage);
// Assert
(await result.Content.ReadAsStringAsync()).Should().Be("BASIC test-A");
var receivedRequest = serverForProxyForwarding.LogEntries.First().RequestMessage;
var authorizationHeader = receivedRequest.Headers["Authorization"].ToString().Should().Be("BASIC test-A");
server.Mappings.Should().HaveCount(2);
var authorizationRequestMessageHeaderMatcher = ((Request)server.Mappings.Single(m => !m.IsAdminInterface).RequestMatcher)
.GetRequestMessageMatcher<RequestMessageHeaderMatcher>(x => x.Matchers.Any(m => m.GetPatterns().Contains("BASIC test-A")));
authorizationRequestMessageHeaderMatcher.Should().NotBeNull();
}
[Fact]
@@ -486,6 +630,8 @@ namespace WireMock.Net.Tests
Check.That(content2).IsEqualTo("[]");
}
// On Ubuntu latest it's : "Resource temporarily unavailable"
// On Windows-2019 it's : "No such host is known."
[Fact]
public async Task WireMockServer_Proxy_WhenTargetIsNotAvailable_Should_Return_CorrectResponse()
{
@@ -512,10 +658,12 @@ namespace WireMock.Net.Tests
result.StatusCode.Should().Be(500);
var content = await result.Content.ReadAsStringAsync();
content.Should().Contain("known"); // On Linux it's "Name or service not known". On Windows it's "No such host is known.".
content.Should().NotBeEmpty();
server.LogEntries.Should().HaveCount(1);
((StatusModel)server.LogEntries.First().ResponseMessage.BodyData.BodyAsJson).Status.Should().Contain("known");
var status = ((StatusModel)server.LogEntries.First().ResponseMessage.BodyData.BodyAsJson).Status;
server.Stop();
}
}
}

View File

@@ -27,11 +27,13 @@ namespace WireMock.Net.Tests
}));
// Act
using var httpClient = new HttpClient();
var httpClient = new HttpClient();
var response = await httpClient.PostAsync("http://localhost:" + server.Ports[0] + "/foo", new StringContent("dummy"));
// Assert
response.StatusCode.Should().Be(409);
server.Stop();
}
}
}

View File

@@ -29,6 +29,8 @@ namespace WireMock.Net.Tests
// then
Check.That(server.LogEntries).IsEmpty();
server.Stop();
}
[Fact]
@@ -51,6 +53,8 @@ namespace WireMock.Net.Tests
// then
Check.That(server.Mappings).IsEmpty();
Check.ThatAsyncCode(() => new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path)).ThrowsAny();
server.Stop();
}
[Fact]
@@ -82,6 +86,8 @@ namespace WireMock.Net.Tests
// Assert
Check.That(response).IsEqualTo("REDIRECT SUCCESSFUL");
server.Stop();
}
[Fact]
@@ -105,6 +111,8 @@ namespace WireMock.Net.Tests
// then
Check.That(watch.ElapsedMilliseconds).IsStrictlyGreaterThan(200);
server.Stop();
}
[Fact]
@@ -125,6 +133,8 @@ namespace WireMock.Net.Tests
// then
Check.That(watch.ElapsedMilliseconds).IsStrictlyGreaterThan(200);
server.Stop();
}
//Leaving commented as this requires an actual certificate with password, along with a service that expects a client certificate
@@ -161,9 +171,11 @@ namespace WireMock.Net.Tests
// Assert
Check.That(response.Headers.Contains("test")).IsTrue();
Check.That(response.Headers.Contains("Transfer-Encoding")).IsFalse();
server.Stop();
}
#if !NET452
#if !NET452 && !NET461
[Theory]
[InlineData("TRACE")]
[InlineData("GET")]
@@ -189,6 +201,8 @@ namespace WireMock.Net.Tests
// Assert
Check.That(response.StatusCode).Equals(HttpStatusCode.OK);
server.Stop();
}
#endif
@@ -221,6 +235,8 @@ namespace WireMock.Net.Tests
// Assert
Check.That(response.StatusCode).Equals(HttpStatusCode.OK);
server.Stop();
}
[Theory]
@@ -254,6 +270,8 @@ namespace WireMock.Net.Tests
// Assert
Check.That(response.StatusCode).Equals(HttpStatusCode.Created);
Check.That(await response.Content.ReadAsStringAsync()).Contains("Mapping added");
server.Stop();
}
[Theory]
@@ -284,6 +302,8 @@ namespace WireMock.Net.Tests
// Assert
Check.That(await response.Content.ReadAsStringAsync()).Contains("OK");
server.Stop();
}
}
}

View File

@@ -51,6 +51,8 @@ namespace WireMock.Net.Tests.WithMapping
m.Response.Body == response &&
(int)m.Response.StatusCode == 201
);
server.Stop();
}
[Fact]
@@ -86,6 +88,8 @@ namespace WireMock.Net.Tests.WithMapping
m.Guid == Guid.Parse("532889c2-f84d-4dc8-b847-9ea2c6aca7d5") &&
(int)m.Response.StatusCode == 201
);
server.Stop();
}
[Fact]
@@ -120,6 +124,8 @@ namespace WireMock.Net.Tests.WithMapping
// Assert
server.MappingModels.Should().HaveCount(2);
server.Stop();
}
}
}