Compare commits

..

16 Commits

Author SHA1 Message Date
Stef Heyenrath
c92e733ef9 1.0.4.9 2018-08-08 11:42:24 +02:00
Stef Heyenrath
d9fde9329a Merge branch 'stef_fix_174_jsonpathmatcher' 2018-08-08 11:37:08 +02:00
Stef Heyenrath
9e7d3b6d2d #177 2018-08-08 11:05:27 +02:00
Stef Heyenrath
5ee25fb1e7 #175 2018-08-08 08:20:52 +02:00
Stef Heyenrath
36866d9fc3 #176 2018-08-07 20:34:35 +02:00
Stef Heyenrath
4f7259d27a Fix JsonMatcher and JsonPathMatcher 2018-08-07 19:27:10 +02:00
Stef Heyenrath
f13b829c00 Add unit-test 2018-08-02 16:11:14 +02:00
Stef Heyenrath
60d9487313 Update README.md 2018-07-27 12:54:45 +02:00
Stef Heyenrath
8cb15b2311 Add more details on Using and move HTTP SSL 2018-07-26 13:39:40 +02:00
Stef Heyenrath
3907e83138 1.0.4.8 2018-07-23 17:34:25 +02:00
Stef Heyenrath
1f226f7361 Support json path in the response (#170)
* jsonpath in response

* Fix tests

* Support also BodyAsJson

* Fix Sonar Issue

* Add example (zubinix2)

* Fix batch file

* Solve CodeFactor issues

* netcoreapp2.0;netcoreapp2.1

* 1.0.4.8
2018-07-23 17:28:32 +02:00
Stef Heyenrath
215f051218 1.0.4.7 changelog 2018-07-19 22:25:40 +02:00
Stef Heyenrath
b2bf63b013 Fix for Restricted Response headers (#169)
* WebHeaderCollection.IsRestricted (#148)

* Update dependencies

* 1.0.4.7
2018-07-19 22:23:00 +02:00
Stef Heyenrath
7191c082de 1.0.4.6 2018-07-18 21:37:26 +02:00
Stef Heyenrath
8f34291ea9 Expose scenario states (#168)
* Scenarios (WIP)

* Update ToJson and StatefulBehaviorTests

* fix tests

* Update comment
2018-07-18 21:29:49 +02:00
Stef Heyenrath
6b0924029f docker 2018-07-17 21:11:05 +02:00
45 changed files with 1102 additions and 192 deletions

View File

@@ -1,3 +1,38 @@
# 1.0.4.9 (08 August 2018)
- [#177](https://github.com/WireMock-Net/WireMock.Net/issues/177) - Feature: Skip invalid static mapping files +feature
- [#176](https://github.com/WireMock-Net/WireMock.Net/issues/176) - Question: Saving mapping with relative (not found) file fails
- [#175](https://github.com/WireMock-Net/WireMock.Net/issues/175) - Bug: Don't allow adding a mapping with no URL or PATH +fix
- [#174](https://github.com/WireMock-Net/WireMock.Net/issues/174) - Bug: JsonMatcher and JsonPathMatcher throws when posting byte[] +fix
- [#172](https://github.com/WireMock-Net/WireMock.Net/issues/172) - Question: Same/similar fluent interface for in process and admin client API
Commits: 8cb15b2311...d9fde9329a
# 1.0.4.8 (23 July 2018)
- [#170](https://github.com/WireMock-Net/WireMock.Net/pull/170) - Support json path in the response contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#167](https://github.com/WireMock-Net/WireMock.Net/issues/167) - Feature: Support for JsonPath in the response (with HandleBars) +feature
Commits: 1f226f7361...1f226f7361
# 1.0.4.7 (19 July 2018)
- [#169](https://github.com/WireMock-Net/WireMock.Net/pull/169) - Fix for Restricted Response headers contributed by Stef Heyenrath ([StefH](https://github.com/StefH)) +fix
- [#148](https://github.com/WireMock-Net/WireMock.Net/issues/148) - Question: proxy passthrough when no match?
Commits: b2bf63b013...b2bf63b013
# 1.0.4.6 (18 July 2018)
- [#168](https://github.com/WireMock-Net/WireMock.Net/pull/168) - Expose scenario states contributed by Stef Heyenrath ([StefH](https://github.com/StefH)) +feature
- [#163](https://github.com/WireMock-Net/WireMock.Net/issues/163) - Feature: Expose scenario states
Commits: 6b0924029f...8f34291ea9
# 1.0.4.5 (17 July 2018)
- [#166](https://github.com/WireMock-Net/WireMock.Net/pull/166) - Fix Sonar issues contributed by Stef Heyenrath ([StefH](https://github.com/StefH))

View File

@@ -1,5 +1,5 @@
https://github.com/GitTools/GitReleaseNotes
GitReleaseNotes.exe . /OutputFile CHANGELOG.md /Version 1.0.4.5
GitReleaseNotes.exe . /OutputFile CHANGELOG.md /Version 1.0.4.9
GitReleaseNotes.exe . /OutputFile CHANGELOG.md /allTags

View File

@@ -1,65 +1,72 @@
# 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).
### Info
## Key Features
* HTTP response stubbing, matchable on URL/Path, headers, cookies and body content patterns
* Runs in unit tests, as a standalone process, as windows service, as Azure or IIS or as docker
* Configurable via a fluent DotNet API, JSON files and JSON over HTTP
* Record/playback of stubs
* Per-request conditional proxying
* Stateful behaviour simulation
* Configurable response delays
## Info
| | |
| --- | --- |
| **Chat** | [![Gitter](https://img.shields.io/gitter/room/wiremock_dotnet/Lobby.svg)](https://gitter.im/wiremock_dotnet/Lobby) |
| **Issues** | [![GitHub issues](https://img.shields.io/github/issues/WireMock-Net/WireMock.Net.svg)](https://github.com/WireMock-Net/WireMock.Net/issues) |
| **Build** | [![Build status](https://ci.appveyor.com/api/projects/status/b3n6q3ygbww4lyls?svg=true)](https://ci.appveyor.com/project/StefH/wiremock-net) |
| | |
| ***Sonar*** |   |
|  **Sonar Quality Gate** | [![Sonar Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=wiremock&metric=alert_status)](https://sonarcloud.io/project/issues?id=wiremock) |
|  **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** | [![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) |
|  **Sonar Coverage** | [![Sonar Coverage](https://sonarcloud.io/api/project_badges/measure?project=wiremock&metric=coverage)](https://sonarcloud.io/component_measures?id=wiremock&metric=coverage) |
|  **Coveralls.io** | [![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) |
| ***Project*** |   |
|   **Chat** | [![Gitter](https://img.shields.io/gitter/room/wiremock_dotnet/Lobby.svg)](https://gitter.im/wiremock_dotnet/Lobby) |
|   **Issues** | [![GitHub issues](https://img.shields.io/github/issues/WireMock-Net/WireMock.Net.svg)](https://github.com/WireMock-Net/WireMock.Net/issues) |
| | |
| ***Quality*** |   |
|   **Build** | [![Build status](https://ci.appveyor.com/api/projects/status/b3n6q3ygbww4lyls?svg=true)](https://ci.appveyor.com/project/StefH/wiremock-net) |
|   **CodeFactor** | [![CodeFactor](https://www.codefactor.io/repository/github/wiremock-net/wiremock.net/badge)](https://www.codefactor.io/repository/github/wiremock-net/wiremock.net)
|   **Sonar Quality Gate** | [![Sonar Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=wiremock&metric=alert_status)](https://sonarcloud.io/project/issues?id=wiremock) |
|   **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** | [![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) |
|   **Sonar Coverage** | [![Sonar Coverage](https://sonarcloud.io/api/project_badges/measure?project=wiremock&metric=coverage)](https://sonarcloud.io/component_measures?id=wiremock&metric=coverage) |
|   **Coveralls** | [![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) |
| |
| ***Nuget*** |   |
|  **WireMock.Net** | [![NuGet Badge WireMock.Net](https://buildstats.info/nuget/WireMock.Net)](https://www.nuget.org/packages/WireMock.Net) |
|  **WireMock.Net.StandAlone** | [![NuGet Badge WireMock.Net.StandAlone](https://buildstats.info/nuget/WireMock.Net.StandAlone)](https://www.nuget.org/packages/WireMock.Net.StandAlone) |
|   **WireMock.Net** | [![NuGet Badge WireMock.Net](https://buildstats.info/nuget/WireMock.Net)](https://www.nuget.org/packages/WireMock.Net) |
|   **WireMock.Net.StandAlone** | [![NuGet Badge WireMock.Net.StandAlone](https://buildstats.info/nuget/WireMock.Net.StandAlone)](https://www.nuget.org/packages/WireMock.Net.StandAlone) |
### Frameworks
The following frameworks are supported:
- net 4.5.2 and up
- net 4.6 and up
- netstandard 1.3
- netstandard 2.0
- net 4.5.2 and up & net 4.6 and up
- netstandard 1.3 & netstandard 2.0
## Build info
### Build info
To build you need:
- Microsoft .NET Framework 4.5.2 Developer Pack (https://www.microsoft.com/en-us/download/details.aspx?id=42637)
- Microsoft .NET Framework 4.6 Targeting Pack (https://www.microsoft.com/en-us/download/confirmation.aspx?id=48136)
- Microsoft .NET Framework 4.6.2 Developer Pack (https://www.microsoft.com/en-us/download/confirmation.aspx?id=53321)
- .NET Core 2.0 (https://www.microsoft.com/net/core)
## Stubbing
A core feature of WireMock.Net is the ability to return canned/predefined HTTP responses for requests matching criteria, see [Wiki : Stubbing & Request Matching](https://github.com/WireMock-Net/WireMock.Net/wiki/Stubbing-and-Request-Matching).
## Using WireMock in UnitTest framework
You can use your favorite test framework and use WireMock within your tests, see
[Wiki : UnitTesting](https://github.com/StefH/WireMock.Net/wiki/Using-WireMock-in-UnitTests).
## Admin API Reference
The WireMock admin API provides functionality to define the mappings via a http interface, see [Wiki : Admin API Reference](https://github.com/StefH/WireMock.Net/wiki/Admin-API-Reference).
## WireMock as a standalone process
This is quite straight forward to launch a mock server within a console application, see [Wiki : standalone](https://github.com/StefH/WireMock.Net/wiki/WireMock-as-a-standalone-process).
## Using
WireMock.Net can be used in several ways:
### SSL
You can start a standalone mock server listening for HTTPS requests. To do so, there is just a flag to set when creating the server:
```csharp
var server1 = FluentMockServer.Start(port: 8443, ssl: true);
### UnitTesting
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).
// or like this
### 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).
var server2 = FluentMockServer.Start(new FluentMockServerSettings
{
Urls = new[] { "http://localhost:9091", "https://localhost:9443" }
});
```
### 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).
- In case when using **net 4.5.2** or **net 4.6**, you need a certificate registered on your box, properly associated with your application and the port number that will be used. This is not really specific to WireMock.Net, not very straightforward and hence the following stackoverflow thread might come handy: [Httplistener with https support](http://stackoverflow.com/questions/11403333/httplistener-with-https-support).
### As a Web Job in Azure or application in IIS
See this link [WireMock-as-a-(Azure)-Web-App](https://github.com/WireMock-Net/WireMock.Net/wiki/WireMock-as-a-(Azure)-Web-App)
- When using **netstandard**, WireMock.Net uses a self signed certificate (which can be overriden if you like) to host https urls.
### In a docker container
There is also a Linux and Windows-Nano container available at [hub.docker.com](https://hub.docker.com/r/sheyenrath).
For more details see also [Docker](https://github.com/WireMock-Net/WireMock.Net-docker).
#### HTTPS / SSL
More details on using HTTPS (SSL) can be found here [Wiki : HTTPS](https://github.com/WireMock-Net/WireMock.Net/wiki/Using-HTTPS-(SSL))

View File

@@ -52,6 +52,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.StandAlone.Net
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Service", "examples\Wiremock.Net.Service\WireMock.Net.Service.csproj", "{7F0B2446-0363-4720-AF46-F47F83B557DC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.HeadersTest", "examples\WireMock.Net.Console.HeadersTest\WireMock.Net.Console.HeadersTest.csproj", "{B70278E7-A2C6-4A3B-BBA9-1C873CA6F03C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -114,6 +116,10 @@ Global
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|Any CPU.Build.0 = Release|Any CPU
{B70278E7-A2C6-4A3B-BBA9-1C873CA6F03C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B70278E7-A2C6-4A3B-BBA9-1C873CA6F03C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B70278E7-A2C6-4A3B-BBA9-1C873CA6F03C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B70278E7-A2C6-4A3B-BBA9-1C873CA6F03C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -133,6 +139,7 @@ Global
{23A9AA3C-40FC-42AA-8A5E-05899795A1C6} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{3C279524-DB73-4DE3-BEF1-F2B2958C9F65} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{7F0B2446-0363-4720-AF46-F47F83B557DC} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{B70278E7-A2C6-4A3B-BBA9-1C873CA6F03C} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BF428BCC-C837-433B-87D2-15C7014B73E9}

View File

@@ -43,11 +43,14 @@ namespace WireMock.Net.Client
var request = api.GetRequestsAsync().Result;
Console.WriteLine($"request = {JsonConvert.SerializeObject(request)}");
var deleteRequestsAsync = api.DeleteRequestsAsync().Result;
Console.WriteLine($"deleteRequestsAsync = {deleteRequestsAsync.Status}");
//var deleteRequestsAsync = api.DeleteRequestsAsync().Result;
//Console.WriteLine($"DeleteRequestsAsync = {deleteRequestsAsync.Status}");
var resetRequestsAsync = api.ResetRequestsAsync().Result;
Console.WriteLine($"resetRequestsAsync = {resetRequestsAsync.Status}");
//var resetRequestsAsync = api.ResetRequestsAsync().Result;
//Console.WriteLine($"ResetRequestsAsync = {resetRequestsAsync.Status}");
var scenarioStates = api.GetScenariosAsync().Result;
Console.WriteLine($"GetScenariosAsync = {JsonConvert.SerializeObject(scenarioStates)}");
Console.WriteLine("Press any key to quit");
Console.ReadKey();

View File

@@ -0,0 +1,60 @@
using System.IO;
using System.Reflection;
using log4net;
using log4net.Config;
using log4net.Repository;
using Newtonsoft.Json;
using WireMock.Logging;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using WireMock.Settings;
namespace WireMock.Net.Console.NETCoreApp
{
static class Program
{
private static readonly ILoggerRepository LogRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
static void Main(params string[] args)
{
XmlConfigurator.Configure(LogRepository, new FileInfo("log4net.config"));
string url = "http://localhost:9999/";
var server = FluentMockServer.Start(new FluentMockServerSettings
{
Urls = new[] { url },
StartAdminInterface = true,
Logger = new WireMockConsoleLogger()
});
System.Console.WriteLine("FluentMockServer listening at {0}", string.Join(",", server.Urls));
server.SetBasicAuthentication("a", "b");
server.AllowPartialMapping();
server
.Given(Request.Create()
.UsingGet()
.WithHeader("Keep-Alive-Test", "stef")
)
.RespondWith(Response.Create()
.WithHeader("Keep-Alive", "timeout=1, max=1")
.WithBody("Keep-Alive OK")
);
System.Console.WriteLine("Press any key to stop the server");
System.Console.ReadKey();
server.Stop();
System.Console.WriteLine("Displaying all requests");
var allRequests = server.LogEntries;
System.Console.WriteLine(JsonConvert.SerializeObject(allRequests, Formatting.Indented));
System.Console.WriteLine("Press any key to quit");
System.Console.ReadKey();
}
}
}

View File

@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
<PackageReference Include="log4net" Version="2.0.8" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<None Update="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="nlog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
</configSections>
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger{1} - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
</configuration>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="info"
internalLogFile="c:\temp\wiremock-internal-nlog.log">
<targets>
<!-- write logs to file -->
<target xsi:type="File" name="all" fileName="c:\temp\wiremock-${shortdate}.log"
layout="${longdate}|${event-properties:item=EventId.Id}|${uppercase:${level}}|${logger}|${message} ${exception}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="*" minlevel="Debug" writeTo="all" />
</rules>
</nlog>

View File

@@ -6,16 +6,12 @@
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="__admin\mappings\826aff7c-6208-4a3c-923d-575248907db4.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\WireMock.Net.ConsoleApplication\MainApp.cs" Link="MainApp.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="__admin\mappings\11111110-a633-40e8-a244-5cb80bc0ab66.json">
<Content Include="__admin\mappings\*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

View File

@@ -3,14 +3,7 @@
"Title": "",
"Priority": 0,
"Request": {
"Path": {
"Matchers": [
{
"Name": "WildcardMatcher",
"Pattern": "/proxy-google-test-post"
}
]
},
"Path": "/proxy-google-test-post",
"Methods": [
"post"
],

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

@@ -38,6 +38,33 @@ namespace WireMock.Net.ConsoleApplication
server.AllowPartialMapping();
server
.Given(Request.Create().WithPath(p => p.Contains("x")).UsingGet())
.AtPriority(4)
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithHeader("Content-Type", "application/json")
.WithBody(@"{ ""result"": ""Contains x with FUNC 200""}"));
server
.Given(Request.Create()
.UsingGet()
.WithPath("/proxy-test-keep-alive")
)
.RespondWith(Response.Create()
.WithHeader("Keep-Alive", "timeout=1, max=1")
);
server
.Given(Request.Create()
.UsingGet()
.WithPath("/proxy-execute-keep-alive")
)
.RespondWith(Response.Create()
.WithProxy(new ProxyAndRecordSettings { Url = "http://localhost:9999", BlackListedHeaders = new[] { "Keep-Alive" } })
.WithHeader("Keep-Alive-Test", "stef")
);
server
.Given(Request.Create()
.WithPath("/xpath").UsingPost()
@@ -125,8 +152,10 @@ namespace WireMock.Net.ConsoleApplication
server
.Given(Request.Create().WithPath("/file_rel").UsingGet())
.WithGuid("0000aaaa-fcf4-4256-a0d3-1c76e4862947")
.RespondWith(Response.Create()
.WithBodyFromFile("Program.cs", false)
.WithHeader("Content-Type", "application/xml")
.WithBodyFromFile("WireMock.Net.xml", false)
);
server
@@ -157,14 +186,6 @@ namespace WireMock.Net.ConsoleApplication
.WithStatusCode(200)
.WithBody("hi"));
server
.Given(Request.Create().WithPath(p => p.Contains("x")).UsingGet())
.AtPriority(4)
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithHeader("Content-Type", "application/json")
.WithBody(@"{ ""result"": ""Contains x with FUNC 200""}"));
server
.Given(Request.Create().WithPath("/data").UsingPost().WithBody(b => b.Contains("e")))
.AtPriority(999)
@@ -237,6 +258,46 @@ namespace WireMock.Net.ConsoleApplication
.WithDelay(TimeSpan.FromMilliseconds(100))
);
server
.Given(Request.Create().WithPath("/jsonpathtestToken").UsingPost())
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBody("{{JsonPath.SelectToken request.body \"$.Manufacturers[?(@.Name == 'Acme Co')]\"}}")
.WithTransformer()
);
server
.Given(Request.Create().WithPath("/zubinix").UsingPost())
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBody("{ \"result\": \"{{JsonPath.SelectToken request.bodyAsJson \"username\"}}\" }")
.WithTransformer()
);
server
.Given(Request.Create().WithPath("/zubinix2").UsingPost())
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson(new { path = "{{request.path}}", result = "{{JsonPath.SelectToken request.bodyAsJson \"username\"}}" })
.WithTransformer()
);
server
.Given(Request.Create().WithPath("/jsonpathtestTokenJson").UsingPost())
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson(new { status = "OK", url = "{{request.url}}", transformed = "{{JsonPath.SelectToken request.body \"$.Manufacturers[?(@.Name == 'Acme Co')]\"}}" })
.WithTransformer()
);
server
.Given(Request.Create().WithPath("/jsonpathtestTokens").UsingPost())
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBody("[{{#JsonPath.SelectTokens request.body \"$..Products[?(@.Price >= 50)].Name\"}} { \"idx\":{{id}}, \"value\":\"{{value}}\" }, {{/JsonPath.SelectTokens}} {} ]")
.WithTransformer()
);
server
.Given(Request.Create()
.WithPath("/state1")

View File

@@ -71,6 +71,9 @@
<Content Include="__admin\mappings\11111110-a633-40e8-a244-5cb80bc0ab66.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="__admin\mappings\873d495f-940e-4b86-a1f4-4f0fc7be8b8b.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj">

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

@@ -1,5 +1,5 @@
@echo off
call uninstall.bat
call Service-Uninstall.bat
SET mypath=%~dp0
SET targetpath=C:\Services\WireMock.Net.Service\

View File

@@ -1,19 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFrameworks>netcoreapp2.0;netcoreapp2.1</TargetFrameworks>
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
<StartupObject>WireMock.Net.WebApplication.Program</StartupObject>
<AssemblyName>WireMock.Net.WebApplication</AssemblyName>
<RootNamespace>WireMock.Net.WebApplication</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0'">
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.8" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1'">
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.4" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.2" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />

View File

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

View File

@@ -30,13 +30,13 @@ namespace WireMock.Admin.Mappings
/// <summary>
/// Execution state condition for the current mapping.
/// </summary>
public object WhenStateIs { get; set; }
public string WhenStateIs { get; set; }
/// <summary>
/// The next state which will be signaled after the current mapping execution.
/// In case the value is null state will not be changed.
/// </summary>
public object SetStateTo { get; set; }
public string SetStateTo { get; set; }
/// <summary>
/// The request.

View File

@@ -0,0 +1,28 @@
namespace WireMock.Admin.Scenarios
{
/// <summary>
/// ScenarioStateModel
/// </summary>
public class ScenarioStateModel
{
/// <summary>
/// Gets or sets the name.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the NextState.
/// </summary>
public string NextState { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="ScenarioStateModel"/> is started.
/// </summary>
public bool Started { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="ScenarioStateModel"/> is finished.
/// </summary>
public bool Finished { get; set; }
}
}

View File

@@ -145,7 +145,7 @@ namespace WireMock.Client
/// Get all scenarios
/// </summary>
[Get("__admin/scenarios")]
Task<string> GetScenariosAsync();
Task<IList<ScenarioState>> GetScenariosAsync();
/// <summary>
/// Delete (reset) all scenarios

View File

@@ -41,14 +41,14 @@ namespace WireMock
/// Execution state condition for the current mapping.
/// </summary>
[CanBeNull]
public object ExecutionConditionState { get; }
public string ExecutionConditionState { get; }
/// <summary>
/// The next state which will be signaled after the current mapping execution.
/// In case the value is null state will not be changed.
/// In case the value is null, state will not be changed.
/// </summary>
[CanBeNull]
public object NextState { get; }
public string NextState { get; }
/// <summary>
/// The Request matcher.
@@ -77,7 +77,7 @@ namespace WireMock
/// <param name="scenario">The scenario. [Optional]</param>
/// <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>
public Mapping(Guid guid, [CanBeNull] string title, [CanBeNull] string path, IRequestMatcher requestMatcher, IResponseProvider provider, int priority, [CanBeNull] string scenario, [CanBeNull] object executionConditionState, [CanBeNull] object nextState)
public Mapping(Guid guid, [CanBeNull] string title, [CanBeNull] string path, IRequestMatcher requestMatcher, IResponseProvider provider, int priority, [CanBeNull] string scenario, [CanBeNull] string executionConditionState, [CanBeNull] string nextState)
{
Guid = guid;
Title = title;
@@ -106,7 +106,7 @@ namespace WireMock
/// <param name="requestMessage">The request message.</param>
/// <param name="nextState">The Next State.</param>
/// <returns>The <see cref="RequestMatchResult"/>.</returns>
public RequestMatchResult GetRequestMatchResult(RequestMessage requestMessage, [CanBeNull] object nextState)
public RequestMatchResult GetRequestMatchResult(RequestMessage requestMessage, [CanBeNull] string nextState)
{
var result = new RequestMatchResult();

View File

@@ -63,7 +63,9 @@ namespace WireMock.Matchers
public double IsMatch(object input)
{
double match = MatchScores.Mismatch;
if (input != null)
// When input is null or byte[], return Mismatch.
if (input != null && !(input is byte[]))
{
try
{

View File

@@ -65,7 +65,9 @@ namespace WireMock.Matchers
public double IsMatch(object input)
{
bool match = false;
if (input != null)
// When input is null or byte[], return Mismatch.
if (input != null && !(input is byte[]))
{
try
{
@@ -73,10 +75,21 @@ namespace WireMock.Matchers
JToken jtokenInput = input is JToken tokenInput ? tokenInput : JObject.FromObject(input);
// Check if JToken or string or object
JToken jtokenValue =
Value is JToken tokenValue ? tokenValue :
Value is string stringValue ? JToken.Parse(stringValue) :
JObject.FromObject(input);
JToken jtokenValue;
switch (Value)
{
case JToken tokenValue:
jtokenValue = tokenValue;
break;
case string stringValue:
jtokenValue = JToken.Parse(stringValue);
break;
default:
jtokenValue = JObject.FromObject(Value);
break;
}
match = JToken.DeepEquals(jtokenValue, jtokenInput);
}

View File

@@ -1,5 +1,4 @@
namespace WireMock.Matchers
namespace WireMock.Matchers
{
internal static class MatchBehaviourHelper
{

View File

@@ -11,21 +11,21 @@ namespace WireMock.Matchers.Request
/// Execution state condition for the current mapping.
/// </summary>
[CanBeNull]
private readonly object _executionConditionState;
private readonly string _executionConditionState;
/// <summary>
/// The next state which will be signaled after the current mapping execution.
/// In case the value is null state will not be changed.
/// </summary>
[CanBeNull]
private readonly object _nextState;
private readonly string _nextState;
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageScenarioAndStateMatcher"/> class.
/// </summary>
/// <param name="nextState">The next state.</param>
/// <param name="executionConditionState">Execution state condition for the current mapping.</param>
public RequestMessageScenarioAndStateMatcher([CanBeNull] object nextState, [CanBeNull] object executionConditionState)
public RequestMessageScenarioAndStateMatcher([CanBeNull] string nextState, [CanBeNull] string executionConditionState)
{
_nextState = nextState;
_executionConditionState = executionConditionState;

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
@@ -49,8 +50,13 @@ namespace WireMock.Owin
else
{
#if !NETSTANDARD
response.Headers.AppendValues(pair.Key, pair.Value.ToArray());
// For non-NETSTANDARD, check if this response header can be added (#148)
if (!WebHeaderCollection.IsRestricted(pair.Key, true))
{
response.Headers.AppendValues(pair.Key, pair.Value.ToArray());
}
#else
// NETSTANDARD can add any header (or so it seems)
response.Headers.Append(pair.Key, pair.Value.ToArray());
#endif
}
@@ -70,6 +76,11 @@ namespace WireMock.Owin
#endif
)
{
if (responseMessage == null)
{
return;
}
response.StatusCode = responseMessage.StatusCode;
byte[] bytes = null;

View File

@@ -60,7 +60,10 @@ namespace WireMock.Owin
// Set start
if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState)
{
_options.Scenarios.TryAdd(mapping.Scenario, null);
_options.Scenarios.TryAdd(mapping.Scenario, new ScenarioState
{
Name = mapping.Scenario
});
}
}
@@ -68,7 +71,7 @@ namespace WireMock.Owin
.Select(m => new
{
Mapping = m,
MatchResult = m.GetRequestMatchResult(request, m.Scenario != null && _options.Scenarios.ContainsKey(m.Scenario) ? _options.Scenarios[m.Scenario] : null)
MatchResult = m.GetRequestMatchResult(request, m.Scenario != null && _options.Scenarios.ContainsKey(m.Scenario) ? _options.Scenarios[m.Scenario].NextState : null)
})
.ToList();
@@ -125,7 +128,9 @@ namespace WireMock.Owin
if (targetMapping.Scenario != null)
{
_options.Scenarios[targetMapping.Scenario] = targetMapping.NextState;
_options.Scenarios[targetMapping.Scenario].NextState = targetMapping.NextState;
_options.Scenarios[targetMapping.Scenario].Started = true;
_options.Scenarios[targetMapping.Scenario].Finished = targetMapping.NextState == null;
}
}
catch (Exception ex)

View File

@@ -22,9 +22,9 @@ namespace WireMock.Owin
public bool AllowPartialMapping { get; set; }
public ConcurrentDictionary<Guid, Mapping> Mappings { get; } = new ConcurrentDictionary<Guid, Mapping>(); // Checked
public ConcurrentDictionary<Guid, Mapping> Mappings { get; } = new ConcurrentDictionary<Guid, Mapping>();
public ConcurrentDictionary<string, object> Scenarios { get; } = new ConcurrentDictionary<string, object>(); // Checked
public ConcurrentDictionary<string, ScenarioState> Scenarios { get; } = new ConcurrentDictionary<string, ScenarioState>();
public ObservableCollection<LogEntry> LogEntries { get; } = new ConcurentObservableCollection<LogEntry>();

View File

@@ -0,0 +1,28 @@
namespace WireMock
{
/// <summary>
/// The ScenarioState
/// </summary>
public class ScenarioState
{
/// <summary>
/// Gets or sets the Name (from the Scenario).
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the NextState.
/// </summary>
public string NextState { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="ScenarioState"/> is started.
/// </summary>
public bool Started { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="ScenarioState"/> is finished.
/// </summary>
public bool Finished { get; set; }
}
}

View File

@@ -37,19 +37,16 @@ namespace WireMock.Serialization
ClientIP = clientIPMatchers != null && clientIPMatchers.Any() ? new ClientIPModel
{
Matchers = MatcherMapper.Map(clientIPMatchers.Where(m => m.Matchers != null).SelectMany(m => m.Matchers))
//Funcs = Map(clientIPMatchers.Where(m => m.Funcs != null).SelectMany(m => m.Funcs))
} : null,
Path = pathMatchers != null && pathMatchers.Any() ? new PathModel
{
Matchers = MatcherMapper.Map(pathMatchers.Where(m => m.Matchers != null).SelectMany(m => m.Matchers))
//Funcs = Map(pathMatchers.Where(m => m.Funcs != null).SelectMany(m => m.Funcs))
} : null,
Url = urlMatchers != null && urlMatchers.Any() ? new UrlModel
{
Matchers = MatcherMapper.Map(urlMatchers.Where(m => m.Matchers != null).SelectMany(m => m.Matchers))
//Funcs = Map(urlMatchers.Where(m => m.Funcs != null).SelectMany(m => m.Funcs))
} : null,
Methods = methodMatcher?.Methods,
@@ -58,28 +55,23 @@ namespace WireMock.Serialization
{
Name = hm.Name,
Matchers = MatcherMapper.Map(hm.Matchers)
//Funcs = Map(hm.Funcs)
}).ToList() : null,
Cookies = cookieMatchers != null && cookieMatchers.Any() ? cookieMatchers.Select(cm => new CookieModel
{
Name = cm.Name,
Matchers = MatcherMapper.Map(cm.Matchers)
//Funcs = Map(cm.Funcs)
}).ToList() : null,
Params = paramsMatchers != null && paramsMatchers.Any() ? paramsMatchers.Select(pm => new ParamModel
{
Name = pm.Key,
Matchers = MatcherMapper.Map(pm.Matchers)
//Funcs = Map(pm.Funcs)
}).ToList() : null,
Body = methodMatcher?.Methods != null && methodMatcher.Methods.Any(m => m == "get") ? null : new BodyModel
{
Matcher = bodyMatcher != null ? MatcherMapper.Map(bodyMatcher.Matcher) : null
//Func = bodyMatcher != null ? Map(bodyMatcher.Func) : null,
//DataFunc = bodyMatcher != null ? Map(bodyMatcher.DataFunc) : null
}
},
Response = new ResponseModel

View File

@@ -21,7 +21,7 @@ namespace WireMock.Serialization
string matcherName = parts[0];
string matcherType = parts.Length > 1 ? parts[1] : null;
string[] stringPatterns = matcher.Patterns != null ? matcher.Patterns.Cast<string>().ToArray() : new [] { matcher.Pattern as string };
string[] stringPatterns = matcher.Patterns != null ? matcher.Patterns.Cast<string>().ToArray() : new[] { matcher.Pattern as string };
MatchBehaviour matchBehaviour = matcher.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch;
switch (matcherName)
@@ -39,7 +39,7 @@ namespace WireMock.Serialization
return new JsonPathMatcher(matchBehaviour, stringPatterns);
case "XPathMatcher":
return new XPathMatcher(matchBehaviour, (string) matcher.Pattern);
return new XPathMatcher(matchBehaviour, (string)matcher.Pattern);
case "WildcardMatcher":
return new WildcardMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true);
@@ -51,7 +51,7 @@ namespace WireMock.Serialization
throw new NotSupportedException($"Matcher '{matcherName}' with Type '{matcherType}' is not supported.");
}
return new SimMetricsMatcher(matchBehaviour, (string) matcher.Pattern, type);
return new SimMetricsMatcher(matchBehaviour, (string)matcher.Pattern, type);
default:
throw new NotSupportedException($"Matcher '{matcherName}' is not supported.");

View File

@@ -9,6 +9,7 @@ using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Admin.Mappings;
using WireMock.Admin.Scenarios;
using WireMock.Admin.Settings;
using WireMock.Http;
using WireMock.Logging;
@@ -41,7 +42,13 @@ namespace WireMock.Server
private readonly JsonSerializerSettings _settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
};
private readonly JsonSerializerSettings _settingsIncludeNullValues = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Include
};
#region InitAdmin
@@ -114,7 +121,15 @@ namespace WireMock.Server
foreach (string filename in Directory.EnumerateFiles(folder).OrderBy(f => f))
{
_logger.Info("Reading Static MappingFile : '{0}'", filename);
ReadStaticMappingAndAddOrUpdate(filename);
try
{
ReadStaticMappingAndAddOrUpdate(filename);
}
catch
{
_logger.Error("Static MappingFile : '{0}' could not be read. This file will be skipped.", filename);
}
}
}
@@ -309,9 +324,9 @@ namespace WireMock.Server
Guid guid = Guid.Parse(requestMessage.Path.TrimStart(AdminMappings.ToCharArray()));
var mappingModel = DeserializeObject<MappingModel>(requestMessage);
DeserializeAndAddOrUpdateMapping(mappingModel, guid);
Guid? guidFromPut = DeserializeAndAddOrUpdateMapping(mappingModel, guid);
return ResponseMessageBuilder.Create("Mapping added or updated", 200, guid);
return ResponseMessageBuilder.Create("Mapping added or updated", 200, guidFromPut);
}
private ResponseMessage MappingDelete(RequestMessage requestMessage)
@@ -394,13 +409,18 @@ namespace WireMock.Server
return ResponseMessageBuilder.Create("Mapping added", 201, guid);
}
private Guid DeserializeAndAddOrUpdateMapping(MappingModel mappingModel, Guid? guid = null, string path = null)
private Guid? DeserializeAndAddOrUpdateMapping(MappingModel mappingModel, Guid? guid = null, string path = null)
{
Check.NotNull(mappingModel, nameof(mappingModel));
Check.NotNull(mappingModel.Request, nameof(mappingModel.Request));
Check.NotNull(mappingModel.Response, nameof(mappingModel.Response));
var requestBuilder = InitRequestBuilder(mappingModel.Request);
var requestBuilder = InitRequestBuilder(mappingModel.Request, true);
if (requestBuilder == null)
{
return null;
}
var responseBuilder = InitResponseBuilder(mappingModel.Response);
var respondProvider = Given(requestBuilder);
@@ -504,7 +524,7 @@ namespace WireMock.Server
{
var requestModel = DeserializeObject<RequestModel>(requestMessage);
var request = (Request)InitRequestBuilder(requestModel);
var request = (Request)InitRequestBuilder(requestModel, false);
var dict = new Dictionary<LogEntry, RequestMatchResult>();
foreach (var logEntry in LogEntries.Where(le => !le.RequestMessage.Path.StartsWith("/__admin/")))
@@ -525,13 +545,15 @@ namespace WireMock.Server
#region Scenarios
private ResponseMessage ScenariosGet(RequestMessage requestMessage)
{
var scenarios = Scenarios.ToArray().Select(s => new
var scenariosStates = Scenarios.Values.Select(s => new ScenarioStateModel
{
Name = s.Key,
Started = s.Value != null,
NextState = s.Value
Name = s.Name,
NextState = s.NextState,
Started = s.Started,
Finished = s.Finished
});
return ToJson(scenarios);
return ToJson(scenariosStates, true);
}
private ResponseMessage ScenariosReset(RequestMessage requestMessage)
@@ -542,7 +564,7 @@ namespace WireMock.Server
}
#endregion
private IRequestBuilder InitRequestBuilder(RequestModel requestModel)
private IRequestBuilder InitRequestBuilder(RequestModel requestModel, bool pathOrUrlRequired)
{
IRequestBuilder requestBuilder = Request.Create();
@@ -562,11 +584,13 @@ namespace WireMock.Server
}
}
bool pathOrUrlmatchersValid = false;
if (requestModel.Path != null)
{
if (requestModel.Path is string path)
{
requestBuilder = requestBuilder.WithPath(path);
pathOrUrlmatchersValid = true;
}
else
{
@@ -574,15 +598,16 @@ namespace WireMock.Server
if (pathModel?.Matchers != null)
{
requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(MatcherMapper.Map).Cast<IStringMatcher>().ToArray());
pathOrUrlmatchersValid = true;
}
}
}
if (requestModel.Url != null)
else if (requestModel.Url != null)
{
if (requestModel.Url is string url)
{
requestBuilder = requestBuilder.WithUrl(url);
pathOrUrlmatchersValid = true;
}
else
{
@@ -590,10 +615,17 @@ namespace WireMock.Server
if (urlModel?.Matchers != null)
{
requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(MatcherMapper.Map).Cast<IStringMatcher>().ToArray());
pathOrUrlmatchersValid = true;
}
}
}
if (pathOrUrlRequired && !pathOrUrlmatchersValid)
{
_logger.Error("Path or Url matcher is missing for this mapping, this mapping will not be added.");
return null;
}
if (requestModel.Methods != null)
{
requestBuilder = requestBuilder.UsingMethod(requestModel.Methods);
@@ -692,7 +724,6 @@ namespace WireMock.Server
{
responseBuilder = responseBuilder.WithBodyFromBase64(responseModel.BodyFromBase64, ToEncoding(responseModel.BodyEncoding));
}
else if (responseModel.BodyAsFile != null)
{
responseBuilder = responseBuilder.WithBodyFromFile(responseModel.BodyAsFile);
@@ -706,11 +737,11 @@ namespace WireMock.Server
return responseBuilder;
}
private ResponseMessage ToJson<T>(T result)
private ResponseMessage ToJson<T>(T result, bool keepNullValues = false)
{
return new ResponseMessage
{
Body = JsonConvert.SerializeObject(result, _settings),
Body = JsonConvert.SerializeObject(result, keepNullValues ? _settingsIncludeNullValues : _settings),
StatusCode = 200,
Headers = new Dictionary<string, WireMockList<string>> { { HttpKnownHeaderNames.ContentType, new WireMockList<string>("application/json") } }
};

View File

@@ -14,6 +14,7 @@ using WireMock.Owin;
using WireMock.RequestBuilders;
using WireMock.ResponseProviders;
using WireMock.Settings;
using WireMock.Transformers;
using WireMock.Validation;
namespace WireMock.Server
@@ -56,7 +57,7 @@ namespace WireMock.Server
/// Gets the scenarios.
/// </summary>
[PublicAPI]
public ConcurrentDictionary<string, object> Scenarios => new ConcurrentDictionary<string, object>(_options.Scenarios);
public ConcurrentDictionary<string, ScenarioState> Scenarios => new ConcurrentDictionary<string, ScenarioState>(_options.Scenarios);
#region IDisposable Members
/// <summary>
@@ -387,7 +388,6 @@ namespace WireMock.Server
public void SetMaxRequestLogCount([CanBeNull] int? maxRequestLogCount)
{
_options.MaxRequestLogCount = maxRequestLogCount;
}
/// <summary>

View File

@@ -66,13 +66,13 @@ namespace WireMock.Server
/// </summary>
/// <param name="state">Any object which identifies the current state</param>
/// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
IRespondWithAProvider WhenStateIs(object state);
IRespondWithAProvider WhenStateIs(string state);
/// <summary>
/// Once this mapping is executed the state will be changed to specified one.
/// </summary>
/// <param name="state">Any object which identifies the new state</param>
/// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
IRespondWithAProvider WillSetStateTo(object state);
IRespondWithAProvider WillSetStateTo(string state);
}
}

View File

@@ -12,8 +12,8 @@ namespace WireMock.Server
private int _priority;
private string _title;
private string _path;
private object _executionConditionState;
private object _nextState;
private string _executionConditionState;
private string _nextState;
private string _scenario;
private readonly RegistrationCallback _registrationCallback;
private readonly IRequestMatcher _requestMatcher;
@@ -87,25 +87,20 @@ namespace WireMock.Server
}
/// <see cref="IRespondWithAProvider.WhenStateIs"/>
public IRespondWithAProvider WhenStateIs(object state)
public IRespondWithAProvider WhenStateIs(string state)
{
if (string.IsNullOrEmpty(_scenario))
{
throw new NotSupportedException("Unable to set state condition when no scenario is defined.");
}
//if (_nextState != null)
//{
// throw new NotSupportedException("Unable to set state condition when next state is defined.");
//}
_executionConditionState = state;
return this;
}
/// <see cref="IRespondWithAProvider.WillSetStateTo"/>
public IRespondWithAProvider WillSetStateTo(object state)
public IRespondWithAProvider WillSetStateTo(string state)
{
if (string.IsNullOrEmpty(_scenario))
{

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using HandlebarsDotNet;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Validation;
namespace WireMock.Transformers
{
internal static class HandlebarsHelpers
{
public static void Register()
{
Handlebars.RegisterHelper("JsonPath.SelectToken", (writer, context, arguments) =>
{
(JObject valueToProcess, string jsonpath) = Parse(arguments);
JToken result = null;
try
{
result = valueToProcess.SelectToken(jsonpath);
}
catch (JsonException)
{
// Ignore JsonException and return
return;
}
if (result != null)
{
writer.WriteSafeString(result);
}
});
Handlebars.RegisterHelper("JsonPath.SelectTokens", (writer, options, context, arguments) =>
{
(JObject valueToProcess, string jsonpath) = Parse(arguments);
IEnumerable<JToken> values = null;
try
{
values = valueToProcess.SelectTokens(jsonpath);
}
catch (JsonException)
{
// Ignore JsonException and return
return;
}
if (values == null)
{
return;
}
int id = 0;
foreach (JToken value in values)
{
options.Template(writer, new { id, value });
id++;
}
});
}
private static (JObject valueToProcess, string jsonpath) Parse(object[] arguments)
{
Check.Condition(arguments, args => args.Length == 2, nameof(arguments));
Check.NotNull(arguments[0], "arguments[0]");
Check.NotNullOrEmpty(arguments[1] as string, "arguments[1]");
JObject valueToProcess;
switch (arguments[0])
{
case string jsonAsString:
valueToProcess = JObject.Parse(jsonAsString);
break;
case JObject jsonAsJObject:
valueToProcess = jsonAsJObject;
break;
default:
throw new NotSupportedException($"The value '{arguments[0]}' with type {arguments[0].GetType()} cannot be used in Handlebars JsonPath.");
}
return (valueToProcess, arguments[1] as string);
}
}
}

View File

@@ -2,12 +2,18 @@
using System.Linq;
using HandlebarsDotNet;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Util;
namespace WireMock.Transformers
{
internal static class ResponseMessageTransformer
{
static ResponseMessageTransformer()
{
HandlebarsHelpers.Register();
}
public static ResponseMessage Transform(RequestMessage requestMessage, ResponseMessage original)
{
bool bodyIsJson = original.BodyAsJson != null;
@@ -20,21 +26,13 @@ namespace WireMock.Transformers
var template = new { request = requestMessage };
// Body
Formatting formatting = original.BodyAsJsonIndented == true ? Formatting.Indented : Formatting.None;
string body = bodyIsJson ? JsonConvert.SerializeObject(original.BodyAsJson, formatting) : original.Body;
if (body != null)
if (!bodyIsJson)
{
var templateBody = Handlebars.Compile(body);
if (!bodyIsJson)
{
responseMessage.Body = templateBody(template);
}
else
{
responseMessage.BodyAsJson = JsonConvert.DeserializeObject(templateBody(template));
}
TransformBodyAsString(template, original, responseMessage);
}
else
{
TransformBodyAsJson(template, original, responseMessage);
}
// Headers
@@ -54,5 +52,79 @@ namespace WireMock.Transformers
return responseMessage;
}
private static void TransformBodyAsJson(object template, ResponseMessage original, ResponseMessage responseMessage)
{
JObject jobject;
switch (original.BodyAsJson)
{
case JObject bodyAsJObject:
jobject = bodyAsJObject;
break;
default:
jobject = JObject.FromObject(original.BodyAsJson);
break;
}
WalkNode(jobject, template);
responseMessage.BodyAsJson = jobject;
}
private static void WalkNode(JToken node, object template)
{
if (node.Type == JTokenType.Object)
{
// In case of Object, loop all children.
foreach (JProperty child in node.Children<JProperty>())
{
WalkNode(child.Value, template);
}
}
else if (node.Type == JTokenType.Array)
{
// In case of Array, loop all items.
foreach (JToken child in node.Children())
{
WalkNode(child, template);
}
}
else if (node.Type == JTokenType.String)
{
// In case of string, try to transform the value.
string stringValue = node.Value<string>();
if (string.IsNullOrEmpty(stringValue))
{
return;
}
var templateForStringValue = Handlebars.Compile(stringValue);
string transformedString = templateForStringValue(template);
if (!string.Equals(stringValue, transformedString))
{
JToken value;
try
{
// Try to convert this string into a real JsonObject
value = JToken.Parse(transformedString);
}
catch (JsonException)
{
// Ignore JsonException and just convert to JToken
value = transformedString;
}
node.Replace(value);
}
}
}
private static void TransformBodyAsString(object template, ResponseMessage original, ResponseMessage responseMessage)
{
var templateBody = Handlebars.Compile(original.Body);
responseMessage.Body = templateBody(template);
}
}
}

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<Description>Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.</Description>
<AssemblyTitle>WireMock.Net</AssemblyTitle>
<Version>1.0.4.5</Version>
<Version>1.0.4.9</Version>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -41,7 +41,7 @@
<PackageReference Include="JetBrains.Annotations" Version="11.1.0">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="Handlebars.Net" Version="1.9.0" />
<PackageReference Include="Handlebars.Net" Version="1.9.5" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="SimMetrics.Net" Version="1.0.4" />
<PackageReference Include="System.Net.Http" Version="4.3.3" />
@@ -50,25 +50,28 @@
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
<PackageReference Include="Microsoft.AspNet.WebApi.OwinSelfHost" Version="5.2.3" />
<PackageReference Include="Microsoft.AspNet.WebApi.OwinSelfHost" Version="5.2.6" />
<PackageReference Include="XPath2" Version="1.0.5.1" />
<Reference Include="System.Net.Http.WebRequest" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net46' ">
<PackageReference Include="Microsoft.AspNet.WebApi.OwinSelfHost" Version="5.2.4" />
<PackageReference Include="Microsoft.AspNet.WebApi.OwinSelfHost" Version="5.2.6" />
<PackageReference Include="Microsoft.Owin" Version="4.0.0" />
<PackageReference Include="Microsoft.Owin.Host.HttpListener" Version="4.0.0" />
<PackageReference Include="Microsoft.Owin.Hosting" Version="4.0.0" />
<PackageReference Include="System.Net.Http" Version="4.3.3" />
<PackageReference Include="XPath2" Version="1.0.5.1" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.5" />
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.7" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="1.1.3" />
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
<PackageReference Include="System.Xml.XPath.XmlDocument" Version="4.3.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">

View File

@@ -585,6 +585,23 @@ namespace WireMock.Net.Tests
Check.That(response).IsEqualTo("/fooBar");
}
[Fact]
public async Task FluentMockServer_Should_exclude_restrictedResponseHeader_for_IOwinResponse()
{
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/foo").UsingGet())
.RespondWith(Response.Create().WithHeader("Keep-Alive", "").WithHeader("test", ""));
// Act
var response = await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo");
// Assert
Check.That(response.Headers.Contains("test")).IsTrue();
Check.That(response.Headers.Contains("Keep-Alive")).IsFalse();
}
public void Dispose()
{
_server?.Stop();

View File

@@ -33,6 +33,20 @@ namespace WireMock.Net.Tests.Matchers
Check.That(value).Equals("{}");
}
[Fact]
public void JsonMatcher_IsMatch_ByteArray()
{
// Assign
var bytes = new byte[0];
var matcher = new JsonMatcher("");
// Act
double match = matcher.IsMatch(bytes);
// Assert
Check.That(match).IsEqualTo(0);
}
[Fact]
public void JsonMatcher_IsMatch_NullString()
{
@@ -65,7 +79,7 @@ namespace WireMock.Net.Tests.Matchers
public void JsonMatcher_IsMatch_JObject1()
{
// Assign
var matcher = new JsonMatcher(new { Id = 1, Name = "test" });
var matcher = new JsonMatcher(new { Id = 1, Name = "Test" });
// Act
var jobject = new JObject
@@ -83,7 +97,7 @@ namespace WireMock.Net.Tests.Matchers
public void JsonMatcher_IsMatch_JObject2()
{
// Assign
var matcher = new JsonMatcher(new { Id = 1, Name = "test" });
var matcher = new JsonMatcher(new { Id = 1, Name = "Test" });
// Act
var jobject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }");

View File

@@ -33,6 +33,20 @@ namespace WireMock.Net.Tests.Matchers
Check.That(patterns).ContainsExactly("X");
}
[Fact]
public void JsonPathMatcher_IsMatch_ByteArray()
{
// Assign
var bytes = new byte[0];
var matcher = new JsonPathMatcher("");
// Act
double match = matcher.IsMatch(bytes);
// Assert
Check.That(match).IsEqualTo(0);
}
[Fact]
public void JsonPathMatcher_IsMatch_NullString()
{

View File

@@ -4,6 +4,7 @@ using System.Text;
using System.Threading.Tasks;
using Microsoft.Owin;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NFluent;
using WireMock.Models;
using WireMock.ResponseBuilders;
@@ -19,7 +20,7 @@ namespace WireMock.Net.Tests.ResponseBuilderTests
[Fact]
public async Task Response_ProvideResponse_Handlebars_WithBodyAsJson()
{
// given
// Assign
string jsonString = "{ \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"Wiremock\" } ] }";
var bodyData = new BodyData
{
@@ -32,17 +33,17 @@ namespace WireMock.Net.Tests.ResponseBuilderTests
.WithBodyAsJson(new { x = "test {{request.url}}" })
.WithTransformer();
// act
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// then
// Assert
Check.That(JsonConvert.SerializeObject(responseMessage.BodyAsJson)).Equals("{\"x\":\"test http://localhost/foo\"}");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_UrlPathVerb()
{
// given
// Assign
var body = new BodyData
{
BodyAsString = "whatever"
@@ -53,17 +54,17 @@ namespace WireMock.Net.Tests.ResponseBuilderTests
.WithBody("test {{request.url}} {{request.path}} {{request.method}}")
.WithTransformer();
// act
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// then
// Assert
Check.That(responseMessage.Body).Equals("test http://localhost/foo /foo post");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_UrlPath()
{
// given
// Assign
var urlDetails = UrlUtils.Parse(new Uri("http://localhost/wiremock/a/b"), new PathString("/wiremock"));
var request = new RequestMessage(urlDetails, "POST", ClientIp);
@@ -71,17 +72,17 @@ namespace WireMock.Net.Tests.ResponseBuilderTests
.WithBody("{{request.url}} {{request.absoluteurl}} {{request.path}} {{request.absolutepath}}")
.WithTransformer();
// act
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// then
// Assert
Check.That(responseMessage.Body).Equals("http://localhost/a/b http://localhost/wiremock/a/b /a/b /wiremock/a/b");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_PathSegments()
{
// given
// Assign
var urlDetails = UrlUtils.Parse(new Uri("http://localhost/wiremock/a/b"), new PathString("/wiremock"));
var request = new RequestMessage(urlDetails, "POST", ClientIp);
@@ -89,17 +90,17 @@ namespace WireMock.Net.Tests.ResponseBuilderTests
.WithBody("{{request.pathsegments.[0]}} {{request.absolutepathsegments.[0]}}")
.WithTransformer();
// act
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// then
// Assert
Check.That(responseMessage.Body).Equals("a wiremock");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_Query()
{
// given
// Assign
var body = new BodyData
{
BodyAsString = "abc"
@@ -110,17 +111,17 @@ namespace WireMock.Net.Tests.ResponseBuilderTests
.WithBody("test keya={{request.query.a}} idx={{request.query.a.[0]}} idx={{request.query.a.[1]}} keyb={{request.query.b}}")
.WithTransformer();
// act
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// then
// Assert
Check.That(responseMessage.Body).Equals("test keya=1 idx=1 idx=2 keyb=5");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_Header()
{
// given
// Assign
var body = new BodyData
{
BodyAsString = "abc"
@@ -129,10 +130,10 @@ namespace WireMock.Net.Tests.ResponseBuilderTests
var response = Response.Create().WithHeader("x", "{{request.headers.Content-Type}}").WithBody("test").WithTransformer();
// act
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// then
// Assert
Check.That(responseMessage.Body).Equals("test");
Check.That(responseMessage.Headers).ContainsKey("x");
Check.That(responseMessage.Headers["x"]).ContainsExactly("text/plain");
@@ -141,7 +142,7 @@ namespace WireMock.Net.Tests.ResponseBuilderTests
[Fact]
public async Task Response_ProvideResponse_Handlebars_Headers()
{
// given
// Assign
var body = new BodyData
{
BodyAsString = "abc"
@@ -150,10 +151,10 @@ namespace WireMock.Net.Tests.ResponseBuilderTests
var response = Response.Create().WithHeader("x", "{{request.headers.Content-Type}}", "{{request.url}}").WithBody("test").WithTransformer();
// act
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// then
// Assert
Check.That(responseMessage.Body).Equals("test");
Check.That(responseMessage.Headers).ContainsKey("x");
Check.That(responseMessage.Headers["x"]).Contains("text/plain");
@@ -163,7 +164,7 @@ namespace WireMock.Net.Tests.ResponseBuilderTests
[Fact]
public async Task Response_ProvideResponse_Handlebars_Origin_Port_Protocol_Host()
{
// given
// Assign
var body = new BodyData
{
BodyAsString = "abc"
@@ -174,11 +175,319 @@ namespace WireMock.Net.Tests.ResponseBuilderTests
.WithBody("test {{request.origin}} {{request.port}} {{request.protocol}} {{request.host}}")
.WithTransformer();
// act
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// then
// Assert
Check.That(responseMessage.Body).Equals("test http://localhost:1234 1234 http localhost");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_JsonPath_SelectToken_Object_ResponseBodyAsJson()
{
// Assign
var body = new BodyData
{
BodyAsString = @"{
""Stores"": [
""Lambton Quay"",
""Willis Street""
],
""Manufacturers"": [
{
""Name"": ""Acme Co"",
""Products"": [
{
""Name"": ""Anvil"",
""Price"": 50
}
]
},
{
""Name"": ""Contoso"",
""Products"": [
{
""Name"": ""Elbow Grease"",
""Price"": 99.95
},
{
""Name"": ""Headlight Fluid"",
""Price"": 4
}
]
}
]
}"
};
var request = new RequestMessage(new UrlDetails("http://localhost:1234"), "POST", ClientIp, body);
var response = Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson(new { x = "{{JsonPath.SelectToken request.body \"$.Manufacturers[?(@.Name == 'Acme Co')]\"}}" })
.WithTransformer();
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// Assert
JObject j = JObject.FromObject(responseMessage.BodyAsJson);
Check.That(j["x"]).IsNotNull();
Check.That(j["x"]["Name"].ToString()).Equals("Acme Co");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_JsonPath_SelectToken_Number_ResponseBodyAsJson()
{
// Assign
var body = new BodyData { BodyAsString = "{ \"Price\": 99 }" };
var request = new RequestMessage(new UrlDetails("http://localhost:1234"), "POST", ClientIp, body);
var response = Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson(new { x = "{{JsonPath.SelectToken request.body \"..Price\"}}" })
.WithTransformer();
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// Assert
JObject j = JObject.FromObject(responseMessage.BodyAsJson);
Check.That(j["x"].Value<long>()).Equals(99);
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_JsonPath_SelectToken_Request_BodyAsString()
{
// Assign
var body = new BodyData
{
BodyAsString = @"{
""Stores"": [
""Lambton Quay"",
""Willis Street""
],
""Manufacturers"": [
{
""Name"": ""Acme Co"",
""Products"": [
{
""Name"": ""Anvil"",
""Price"": 50
}
]
},
{
""Name"": ""Contoso"",
""Products"": [
{
""Name"": ""Elbow Grease"",
""Price"": 99.95
},
{
""Name"": ""Headlight Fluid"",
""Price"": 4
}
]
}
]
}"
};
var request = new RequestMessage(new UrlDetails("http://localhost:1234"), "POST", ClientIp, body);
var response = Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBody("{{JsonPath.SelectToken request.body \"$.Manufacturers[?(@.Name == 'Acme Co')]\"}}")
.WithTransformer();
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// Assert
Check.That(responseMessage.Body).Equals("{\r\n \"Name\": \"Acme Co\",\r\n \"Products\": [\r\n {\r\n \"Name\": \"Anvil\",\r\n \"Price\": 50\r\n }\r\n ]\r\n}");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_JsonPath_SelectToken_Request_BodyAsJObject()
{
// Assign
var body = new BodyData
{
BodyAsJson = JObject.Parse(@"{
'Stores': [
'Lambton Quay',
'Willis Street'
],
'Manufacturers': [
{
'Name': 'Acme Co',
'Products': [
{
'Name': 'Anvil',
'Price': 50
}
]
},
{
'Name': 'Contoso',
'Products': [
{
'Name': 'Elbow Grease',
'Price': 99.95
},
{
'Name': 'Headlight Fluid',
'Price': 4
}
]
}
]
}")
};
var request = new RequestMessage(new UrlDetails("http://localhost:1234"), "POST", ClientIp, body);
var response = Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBody("{{JsonPath.SelectToken request.bodyAsJson \"$.Manufacturers[?(@.Name == 'Acme Co')]\"}}")
.WithTransformer();
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// Assert
Check.That(responseMessage.Body).Equals("{\r\n \"Name\": \"Acme Co\",\r\n \"Products\": [\r\n {\r\n \"Name\": \"Anvil\",\r\n \"Price\": 50\r\n }\r\n ]\r\n}");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_JsonPath_SelectTokens_Request_BodyAsString()
{
// Assign
var body = new BodyData
{
BodyAsString = @"{
""Stores"": [
""Lambton Quay"",
""Willis Street""
],
""Manufacturers"": [
{
""Name"": ""Acme Co"",
""Products"": [
{
""Name"": ""Anvil"",
""Price"": 50
}
]
},
{
""Name"": ""Contoso"",
""Products"": [
{
""Name"": ""Elbow Grease"",
""Price"": 99.95
},
{
""Name"": ""Headlight Fluid"",
""Price"": 4
}
]
}
]
}"
};
var request = new RequestMessage(new UrlDetails("http://localhost:1234"), "POST", ClientIp, body);
var response = Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBody("{{#JsonPath.SelectTokens request.body \"$..Products[?(@.Price >= 50)].Name\"}}{{id}} {{value}},{{/JsonPath.SelectTokens}}")
.WithTransformer();
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// Assert
Check.That(responseMessage.Body).Equals("0 Anvil,1 Elbow Grease,");
}
[Fact]
public async Task Response_ProvideResponse_Handlebars_JsonPath_SelectTokens_Request_BodyAsJObject()
{
// Assign
var body = new BodyData
{
BodyAsJson = JObject.Parse(@"{
'Stores': [
'Lambton Quay',
'Willis Street'
],
'Manufacturers': [
{
'Name': 'Acme Co',
'Products': [
{
'Name': 'Anvil',
'Price': 50
}
]
},
{
'Name': 'Contoso',
'Products': [
{
'Name': 'Elbow Grease',
'Price': 99.95
},
{
'Name': 'Headlight Fluid',
'Price': 4
}
]
}
]
}")
};
var request = new RequestMessage(new UrlDetails("http://localhost:1234"), "POST", ClientIp, body);
var response = Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBody("{{#JsonPath.SelectTokens request.bodyAsJson \"$..Products[?(@.Price >= 50)].Name\"}}{{id}} {{value}},{{/JsonPath.SelectTokens}}")
.WithTransformer();
// Act
var responseMessage = await response.ProvideResponseAsync(request);
// Assert
Check.That(responseMessage.Body).Equals("0 Anvil,1 Elbow Grease,");
}
[Fact]
public void Response_ProvideResponse_Handlebars_JsonPath_SelectTokens_Throws()
{
// Assign
var body = new BodyData
{
BodyAsJson = JObject.Parse(@"{
'Stores': [
'Lambton Quay',
'Willis Street'
]
}")
};
var request = new RequestMessage(new UrlDetails("http://localhost:1234"), "POST", ClientIp, body);
var response = Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBody("{{#JsonPath.SelectTokens request.body \"$..Products[?(@.Price >= 50)].Name\"}}{{id}} {{value}},{{/JsonPath.SelectTokens}}")
.WithTransformer();
// Act
Check.ThatAsyncCode(() => response.ProvideResponseAsync(request)).Throws<ArgumentNullException>();
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using NFluent;
using NFluent;
using WireMock.Models;
using WireMock.ResponseBuilders;
using Xunit;

View File

@@ -1,4 +1,5 @@
using System.Net;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using NFluent;
@@ -12,7 +13,7 @@ namespace WireMock.Net.Tests
public class StatefulBehaviorTests
{
[Fact]
public async Task Should_skip_non_relevant_states()
public async Task Scenarios_Should_skip_non_relevant_states()
{
// given
var server = FluentMockServer.Start();
@@ -33,7 +34,7 @@ namespace WireMock.Net.Tests
}
[Fact]
public async Task Should_process_request_if_equals_state_and_single_state_defined()
public async Task Scenarios_Should_process_request_if_equals_state_and_single_state_defined()
{
// given
var server = FluentMockServer.Start();
@@ -62,7 +63,7 @@ namespace WireMock.Net.Tests
}
[Fact]
public async Task Scenario_and_State_TodoList_Example()
public async Task Scenarios_TodoList_Example()
{
// Assign
var server = FluentMockServer.Start();
@@ -86,22 +87,39 @@ namespace WireMock.Net.Tests
.WhenStateIs("Cancel newspaper item added")
.RespondWith(Response.Create().WithBody("Buy milk;Cancel newspaper subscription"));
Check.That(server.Scenarios.Any()).IsFalse();
// Act and Assert
string url = "http://localhost:" + server.Ports[0];
string getResponse1 = new HttpClient().GetStringAsync(url + "/todo/items").Result;
Check.That(getResponse1).Equals("Buy milk");
Check.That(server.Scenarios["To do list"].Name).IsEqualTo("To do list");
Check.That(server.Scenarios["To do list"].NextState).IsEqualTo("TodoList State Started");
Check.That(server.Scenarios["To do list"].Started).IsTrue();
Check.That(server.Scenarios["To do list"].Finished).IsFalse();
var postResponse = await new HttpClient().PostAsync(url + "/todo/items", new StringContent("Cancel newspaper subscription"));
Check.That(postResponse.StatusCode).Equals(HttpStatusCode.Created);
Check.That(server.Scenarios["To do list"].Name).IsEqualTo("To do list");
Check.That(server.Scenarios["To do list"].NextState).IsEqualTo("Cancel newspaper item added");
Check.That(server.Scenarios["To do list"].Started).IsTrue();
Check.That(server.Scenarios["To do list"].Finished).IsFalse();
string getResponse2 = await new HttpClient().GetStringAsync(url + "/todo/items");
Check.That(getResponse2).Equals("Buy milk;Cancel newspaper subscription");
Check.That(server.Scenarios["To do list"].Name).IsEqualTo("To do list");
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.Dispose();
}
// [Fact]
public async Task Should_process_request_if_equals_state_and_multiple_state_defined()
[Fact]
public async Task Scenarios_Should_process_request_if_equals_state_and_multiple_state_defined()
{
// Assign
var server = FluentMockServer.Start();
@@ -113,7 +131,7 @@ namespace WireMock.Net.Tests
.RespondWith(Response.Create().WithBody("No state msg 1"));
server
.Given(Request.Create().WithPath("/fooX").UsingGet())
.Given(Request.Create().WithPath("/foo1X").UsingGet())
.InScenario("s1")
.WhenStateIs("Test state 1")
.RespondWith(Response.Create().WithBody("Test state msg 1"));
@@ -125,7 +143,7 @@ namespace WireMock.Net.Tests
.RespondWith(Response.Create().WithBody("No state msg 2"));
server
.Given(Request.Create().WithPath("/fooX").UsingGet())
.Given(Request.Create().WithPath("/foo2X").UsingGet())
.InScenario("s2")
.WhenStateIs("Test state 2")
.RespondWith(Response.Create().WithBody("Test state msg 2"));
@@ -138,10 +156,10 @@ namespace WireMock.Net.Tests
var responseNoState2 = await new HttpClient().GetStringAsync(url + "/state2");
Check.That(responseNoState2).Equals("No state msg 2");
var responseWithState1 = await new HttpClient().GetStringAsync(url + "/fooX");
var responseWithState1 = await new HttpClient().GetStringAsync(url + "/foo1X");
Check.That(responseWithState1).Equals("Test state msg 1");
var responseWithState2 = await new HttpClient().GetStringAsync(url + "/fooX");
var responseWithState2 = await new HttpClient().GetStringAsync(url + "/foo2X");
Check.That(responseWithState2).Equals("Test state msg 2");
server.Dispose();