mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-02-14 22:37:41 +01:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7678e8fb70 | ||
|
|
8ae0abb023 | ||
|
|
b3c2af0c22 | ||
|
|
2dd30b4f14 | ||
|
|
45d8c0cc27 | ||
|
|
178f2cf02f | ||
|
|
1b326a54d6 | ||
|
|
8bafd6a1ba | ||
|
|
a47750c058 | ||
|
|
5bb10c3350 | ||
|
|
3a221f51b1 | ||
|
|
0ff23a3d15 | ||
|
|
9b323ab388 | ||
|
|
9b3c750754 | ||
|
|
a5d6061c2d | ||
|
|
395be3c583 | ||
|
|
ea6a8d3b73 | ||
|
|
4886ac6196 | ||
|
|
0ca63eef66 | ||
|
|
c72487a748 | ||
|
|
79db955611 | ||
|
|
395f48a2bf | ||
|
|
596177d4e5 | ||
|
|
fc024678fa | ||
|
|
2e78a04f3d | ||
|
|
f3d2452093 | ||
|
|
92e693818a | ||
|
|
9a1ae6a3f0 | ||
|
|
e701566a1f | ||
|
|
84ad5a927e | ||
|
|
3250604b5a | ||
|
|
9d2963632e | ||
|
|
9e0536c54c | ||
|
|
676e973011 | ||
|
|
31f3d77b38 | ||
|
|
4a2d512f83 | ||
|
|
87534c35f5 | ||
|
|
7789f94737 | ||
|
|
b2167f85ae | ||
|
|
3cc361e216 | ||
|
|
0a9214ef47 | ||
|
|
4afef3695b | ||
|
|
782b082949 | ||
|
|
36325fe2c7 | ||
|
|
01171b9592 | ||
|
|
d6f44b2202 | ||
|
|
a2b22d8b0c | ||
|
|
666992ef24 | ||
|
|
9cd16f726f | ||
|
|
feea64b328 | ||
|
|
e1798fbb8e | ||
|
|
5b8b588983 | ||
|
|
2f406029c9 | ||
|
|
8c9a51c46d | ||
|
|
ebe3275079 | ||
|
|
c0a43ed204 | ||
|
|
7941894543 |
136
CHANGELOG.md
136
CHANGELOG.md
@@ -1,41 +1,94 @@
|
||||
# 1.0.41.0 (14 December 2019)
|
||||
- [#392](https://github.com/WireMock-Net/WireMock.Net/pull/392) - Fix array in JsonMatcher [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#390](https://github.com/WireMock-Net/WireMock.Net/issues/390) - JsonMatcher does not match a body containing an array of strings [bug]
|
||||
|
||||
# 1.0.40.0 (09 December 2019)
|
||||
- [#389](https://github.com/WireMock-Net/WireMock.Net/pull/389) - Fix QueryStringParser [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#387](https://github.com/WireMock-Net/WireMock.Net/issues/387) - Query string parameter value which contains %26 does not work with ExactMatcher [bug]
|
||||
|
||||
# 1.0.39.0 (07 December 2019)
|
||||
- [#370](https://github.com/WireMock-Net/WireMock.Net/pull/370) - Add WebProxySettings (use when proxying requests) [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#388](https://github.com/WireMock-Net/WireMock.Net/pull/388) - Transform body as file [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#369](https://github.com/WireMock-Net/WireMock.Net/issues/369) - Question: Is there a way to provide a corporate proxy configuration? [feature]
|
||||
- [#375](https://github.com/WireMock-Net/WireMock.Net/issues/375) - Proxying does not follow redirects : make this configurable [feature]
|
||||
- [#386](https://github.com/WireMock-Net/WireMock.Net/issues/386) - Is transforming contents of XML file supported.? [bug]
|
||||
|
||||
# 1.0.38.0 (30 November 2019)
|
||||
- [#376](https://github.com/WireMock-Net/WireMock.Net/pull/376) - Support int values for states and scenario naming [feature] contributed by [thewholuver94](https://github.com/thewholuver94)
|
||||
- [#378](https://github.com/WireMock-Net/WireMock.Net/pull/378) - Set handlebars dependency for .net 4.5.1 to fixed value [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#381](https://github.com/WireMock-Net/WireMock.Net/pull/381) - Use dotnet default development certificate for .NET Core 2.x [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#377](https://github.com/WireMock-Net/WireMock.Net/issues/377) - Unable to build against .NET 4.5.1 because of Handlebars [bug]
|
||||
|
||||
# 1.0.37.0 (08 November 2019)
|
||||
- [#373](https://github.com/WireMock-Net/WireMock.Net/pull/373) - Make Sonar and WhiteSource optional in the Azure pipelines build [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#374](https://github.com/WireMock-Net/WireMock.Net/pull/374) - WatchStaticMappingsInSubdirectories [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#372](https://github.com/WireMock-Net/WireMock.Net/issues/372) - Reset in WireMock admin API not working fine. [feature]
|
||||
|
||||
# 1.0.36.0 (26 October 2019)
|
||||
- [#360](https://github.com/WireMock-Net/WireMock.Net/pull/360) - Add support for Faults [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#343](https://github.com/WireMock-Net/WireMock.Net/issues/343) - Feature: Please provide support for Bad responses. [feature]
|
||||
|
||||
# 1.0.35.0 (25 October 2019)
|
||||
- [#367](https://github.com/WireMock-Net/WireMock.Net/pull/367) - No symbol NuGets [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#368](https://github.com/WireMock-Net/WireMock.Net/pull/368) - Remove Obsolete annotations [feature] contributed by [StefH](https://github.com/StefH)
|
||||
|
||||
# 1.0.34.0 (22 October 2019)
|
||||
- [#354](https://github.com/WireMock-Net/WireMock.Net/pull/354) - AllowBodyForAllHttpMethods [bug, feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#365](https://github.com/WireMock-Net/WireMock.Net/pull/365) - Bump Microsoft.AspNetCore.All from 2.0.8 to 2.0.9 in /examples/WireMock.Net.WebApplication [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
|
||||
- [#366](https://github.com/WireMock-Net/WireMock.Net/pull/366) - Update ObsoleteAnnotations [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#352](https://github.com/WireMock-Net/WireMock.Net/issues/352) - DELETE request drops the body [feature]
|
||||
|
||||
# 1.0.33.0 (12 October 2019)
|
||||
- [#311](https://github.com/WireMock-Net/WireMock.Net/pull/311) - fix jsonpath matcher [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#324](https://github.com/WireMock-Net/WireMock.Net/pull/324) - Add CSharpCodeMatcher [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#353](https://github.com/WireMock-Net/WireMock.Net/pull/353) - Fixed failing admin requests when content type includes a charset (based on idea from Paul Roub) [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#355](https://github.com/WireMock-Net/WireMock.Net/pull/355) - Add Try-Catch to the event LogEntriesChanged [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#357](https://github.com/WireMock-Net/WireMock.Net/pull/357) - Add Proxy Setting for: SaveMappingForStatusCodePattern to only save the mapping when the status code matches the pattern [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#358](https://github.com/WireMock-Net/WireMock.Net/pull/358) - Fix JsonMatcher (parsing DateTimeOffset) contributed by [StefH](https://github.com/StefH)
|
||||
- [#306](https://github.com/WireMock-Net/WireMock.Net/issues/306) - Writing to the response body is invalid for responses with status code 204 [bug]
|
||||
- [#307](https://github.com/WireMock-Net/WireMock.Net/issues/307) - JsonPathMatcher always convert to JArray before matching [bug]
|
||||
- [#329](https://github.com/WireMock-Net/WireMock.Net/issues/329) - Feature: Add support for CSharpCodeMatcher [feature]
|
||||
- [#350](https://github.com/WireMock-Net/WireMock.Net/issues/350) - Admin requests fail when content type includes a charset [bug]
|
||||
- [#356](https://github.com/WireMock-Net/WireMock.Net/issues/356) - JsonMatcher not working when JSON contains a DateTimeOffset [bug]
|
||||
|
||||
# 1.0.32.0 (20 September 2019)
|
||||
- [#348](https://github.com/WireMock-Net/WireMock.Net/pull/348) - When posting new mapping, use DateParseHandling.None [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#347](https://github.com/WireMock-Net/WireMock.Net/issues/347) - Query string match on DateTimeOffset is not working [bug]
|
||||
|
||||
# 1.0.31.0 (19 September 2019)
|
||||
- [#334](https://github.com/WireMock-Net/WireMock.Net/pull/334) - Fix issues with Proxy mode and Binary Request Bodies [bug] contributed by [andi0b](https://github.com/andi0b)
|
||||
- [#338](https://github.com/WireMock-Net/WireMock.Net/pull/338) - Fix ContentType with parameters in Proxy Mode [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#339](https://github.com/WireMock-Net/WireMock.Net/pull/339) - Fix ConcurrentObservableCollection [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#345](https://github.com/WireMock-Net/WireMock.Net/pull/345) - Fix CompareTo in RequestMatchResult [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#346](https://github.com/WireMock-Net/WireMock.Net/pull/346) - Fix recorded requests skipped by request logger contributed by [vitaliydavydiak](https://github.com/vitaliydavydiak)
|
||||
- [#337](https://github.com/WireMock-Net/WireMock.Net/issues/337) - Proxy Missing header Content-Type - tried with Recording [bug]
|
||||
- [#344](https://github.com/WireMock-Net/WireMock.Net/issues/344) - Mapping adding order matters for multiple mappings? [bug]
|
||||
|
||||
# 1.0.29.0 (29 August 2019)
|
||||
- [#328](https://github.com/WireMock-Net/WireMock.Net/pull/328) - Fix LogRequest : Index Out Of Bounds [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#331](https://github.com/WireMock-Net/WireMock.Net/pull/331) - Fix: Collection was modified exception [bug] contributed by [theramis](https://github.com/theramis)
|
||||
- [#333](https://github.com/WireMock-Net/WireMock.Net/pull/333) - JsonMatcher support IgnoreCase [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#327](https://github.com/WireMock-Net/WireMock.Net/issues/327) - Index must be within the bounds of the List - Bug [bug]
|
||||
- [#332](https://github.com/WireMock-Net/WireMock.Net/issues/332) - Case sensitive true is ignored for JsonMatcher [feature]
|
||||
|
||||
# 1.0.28.0 (20 August 2019)
|
||||
- [#309](https://github.com/WireMock-Net/WireMock.Net/pull/309) - Fix LogEntries: collection was modified exception [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#314](https://github.com/WireMock-Net/WireMock.Net/pull/314) - RequestLogExpirationDuration : use DateTime.UtcNow [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#316](https://github.com/WireMock-Net/WireMock.Net/pull/316) - Handles case where parameter value contains == [feature] contributed by [lobsteropteryx](https://github.com/lobsteropteryx)
|
||||
- [#317](https://github.com/WireMock-Net/WireMock.Net/pull/317) - Make SaveMapping and SaveMappingToFile settings independent. [feature] contributed by [vitaliydavydiak](https://github.com/vitaliydavydiak)
|
||||
- [#319](https://github.com/WireMock-Net/WireMock.Net/pull/319) - Add blacklist for Request Cookies. contributed by [vitaliydavydiak](https://github.com/vitaliydavydiak)
|
||||
- [#320](https://github.com/WireMock-Net/WireMock.Net/pull/320) - Remove coverlet folder from source control [doc] contributed by [StefH](https://github.com/StefH)
|
||||
- [#322](https://github.com/WireMock-Net/WireMock.Net/pull/322) - Fix MappingMatcher in case of an exception in LinqMatcher. [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#323](https://github.com/WireMock-Net/WireMock.Net/pull/323) - Refactor MappingConverter & MatcherMapper [refactor] contributed by [StefH](https://github.com/StefH)
|
||||
- [#326](https://github.com/WireMock-Net/WireMock.Net/pull/326) - Fix Parsing Guid in PUT Mapping [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#318](https://github.com/WireMock-Net/WireMock.Net/issues/318) - Documentation: Add valid CLI parameters [doc, question]
|
||||
- [#325](https://github.com/WireMock-Net/WireMock.Net/issues/325) - Admin API: PUT Mapping, FormatException because of wrong parsing of the Query [bug]
|
||||
|
||||
# 1.0.27.0 (14 August 2019)
|
||||
- [#316](https://github.com/WireMock-Net/WireMock.Net/pull/316) - Handles case where parameter value contains == [feature] contributed by [lobsteropteryx](https://github.com/lobsteropteryx)
|
||||
- [#287](https://github.com/WireMock-Net/WireMock.Net/issues/287) - Error with parameter that contains a "=" character [bug, question]
|
||||
- [#315](https://github.com/WireMock-Net/WireMock.Net/issues/315) - Wiki - Proxying: AtPriority() example not set on right object [doc]
|
||||
|
||||
# 1.0.26.0 (11 August 2019)
|
||||
- [#309](https://github.com/WireMock-Net/WireMock.Net/pull/309) - Fix LogEntries: collection was modified exception [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#314](https://github.com/WireMock-Net/WireMock.Net/pull/314) - RequestLogExpirationDuration : use DateTime.UtcNow [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#252](https://github.com/WireMock-Net/WireMock.Net/issues/252) - Proxy with Transform [help wanted]
|
||||
- [#305](https://github.com/WireMock-Net/WireMock.Net/issues/305) - Allow Custom SSL Certification? [question]
|
||||
- [#252](https://github.com/WireMock-Net/WireMock.Net/issues/252) - Proxy with Transform
|
||||
- [#308](https://github.com/WireMock-Net/WireMock.Net/issues/308) - __admin/requests - "Collection was modified" exception [bug]
|
||||
- [#313](https://github.com/WireMock-Net/WireMock.Net/issues/313) - RequestLogExpirationDuration - bug [bug]
|
||||
- [#325](https://github.com/WireMock-Net/WireMock.Net/issues/325) - Admin API: PUT Mapping, FormatException because of wrong parsing of the Query [bug]
|
||||
|
||||
# 1.0.25.0 (23 July 2019)
|
||||
- [#304](https://github.com/WireMock-Net/WireMock.Net/pull/304) - Support WithBody with multiple matchers [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#303](https://github.com/WireMock-Net/WireMock.Net/issues/303) - Question: WithBody can't be used with multiple matching rules? [question]
|
||||
|
||||
# 1.0.24.0 (22 July 2019)
|
||||
- [#302](https://github.com/WireMock-Net/WireMock.Net/pull/302) - Fixed bug 301 by not setting BodyAsFile to null after first use [bug] contributed by [rwwilden](https://github.com/rwwilden)
|
||||
- [#299](https://github.com/WireMock-Net/WireMock.Net/issues/299) - Get Mappings models instead of just IMapping interface [feature, question]
|
||||
- [#300](https://github.com/WireMock-Net/WireMock.Net/issues/300) - Integration with Azure Function [question]
|
||||
- [#301](https://github.com/WireMock-Net/WireMock.Net/issues/301) - Error thrown when calling mocked endpoint second time when using file-based response body [bug]
|
||||
|
||||
# 1.0.23.0 (16 July 2019)
|
||||
@@ -43,28 +96,20 @@
|
||||
|
||||
# 1.0.22.0 (15 July 2019)
|
||||
- [#297](https://github.com/WireMock-Net/WireMock.Net/pull/297) - FixNullRef (#295) contributed by [StefH](https://github.com/StefH)
|
||||
- [#178](https://github.com/WireMock-Net/WireMock.Net/issues/178) - Bug: Path matching fails when the URL contains encoded parts [bug, question]
|
||||
- [#295](https://github.com/WireMock-Net/WireMock.Net/issues/295) - NullRef in 1.0.21 [bug]
|
||||
- [#296](https://github.com/WireMock-Net/WireMock.Net/issues/296) - url param - how to accept either of multiple values [question]
|
||||
|
||||
# 1.0.21.0 (03 July 2019)
|
||||
- [#286](https://github.com/WireMock-Net/WireMock.Net/pull/286) - Handlebars Extension [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#293](https://github.com/WireMock-Net/WireMock.Net/pull/293) - workaround for AppContext.BaseDirectory being null on some platforms contributed by [eli-darkly](https://github.com/eli-darkly)
|
||||
- [#294](https://github.com/WireMock-Net/WireMock.Net/pull/294) - don't strip request body if we don't recognize the request method contributed by [eli-darkly](https://github.com/eli-darkly)
|
||||
- [#275](https://github.com/WireMock-Net/WireMock.Net/issues/275) - Server not starting up with 1.0.15 code [invalid, question]
|
||||
- [#280](https://github.com/WireMock-Net/WireMock.Net/issues/280) - Static Mapping Not work [question]
|
||||
- [#285](https://github.com/WireMock-Net/WireMock.Net/issues/285) - Need ability to add custom ResponseMessageTransformers [feature, question]
|
||||
- [#288](https://github.com/WireMock-Net/WireMock.Net/issues/288) - Allow setting root folder in LocalFileSystemHandler [feature, question]
|
||||
- [#289](https://github.com/WireMock-Net/WireMock.Net/issues/289) - Bug: When WatchStaticMappings=true throws exceptions on updating the mapping files [bug]
|
||||
- [#290](https://github.com/WireMock-Net/WireMock.Net/issues/290) - Request body is dropped if verb is REPORT [bug]
|
||||
- [#291](https://github.com/WireMock-Net/WireMock.Net/issues/291) - Define multiple scenarios for the same url path and switch to it at run-time? [question]
|
||||
- [#292](https://github.com/WireMock-Net/WireMock.Net/issues/292) - Can't start server in Xamarin Android [bug]
|
||||
|
||||
# 1.0.20.0 (17 June 2019)
|
||||
- [#284](https://github.com/WireMock-Net/WireMock.Net/pull/284) - Add SaveToFile in the mapping [feature] contributed by [StefH](https://github.com/StefH)
|
||||
|
||||
# 1.0.19.0 (15 June 2019)
|
||||
- [#279](https://github.com/WireMock-Net/WireMock.Net/issues/279) - How to simulate disconnect? [question]
|
||||
- [#283](https://github.com/WireMock-Net/WireMock.Net/issues/283) - Support equal-sign in query [bug]
|
||||
|
||||
# 1.0.18.0 (10 June 2019)
|
||||
@@ -72,7 +117,6 @@
|
||||
|
||||
# 1.0.17.0 (05 June 2019)
|
||||
- [#278](https://github.com/WireMock-Net/WireMock.Net/pull/278) - Add support for HandleBars File (to read a file) [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#276](https://github.com/WireMock-Net/WireMock.Net/issues/276) - No server response in Postman and Receive Failure in Fiddler [invalid]
|
||||
|
||||
# 1.0.16.0 (16 May 2019)
|
||||
- [#274](https://github.com/WireMock-Net/WireMock.Net/pull/274) - Sign Assembly [feature] contributed by [StefH](https://github.com/StefH)
|
||||
@@ -83,11 +127,9 @@
|
||||
- [#271](https://github.com/WireMock-Net/WireMock.Net/pull/271) - Support Dynamic response files using Handlebars templating [bug, feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#272](https://github.com/WireMock-Net/WireMock.Net/pull/272) - Add unit test for JsonPath and BodyAsFile mapping contributed by [denstorti](https://github.com/denstorti)
|
||||
- [#273](https://github.com/WireMock-Net/WireMock.Net/pull/273) - Dynamic response handlebars templating (2) [bug, feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#270](https://github.com/WireMock-Net/WireMock.Net/issues/270) - Dynamic response files using Handlebars templating [bug, question]
|
||||
|
||||
# 1.0.14.0 (20 April 2019)
|
||||
- [#269](https://github.com/WireMock-Net/WireMock.Net/pull/269) - Add JmesPath matcher [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#268](https://github.com/WireMock-Net/WireMock.Net/issues/268) - Swagger UI for admin api [question]
|
||||
|
||||
# 1.0.13.0 (11 April 2019)
|
||||
- [#266](https://github.com/WireMock-Net/WireMock.Net/pull/266) - [265] Add file upload to allow mocking of file operations contributed by [JackCreativeCrew](https://github.com/JackCreativeCrew)
|
||||
@@ -103,8 +145,6 @@
|
||||
|
||||
# 1.0.10.0 (27 March 2019)
|
||||
- [#260](https://github.com/WireMock-Net/WireMock.Net/pull/260) - Fix Response.Delay property serialization [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#257](https://github.com/WireMock-Net/WireMock.Net/issues/257) - Doc: Update outdated [question]
|
||||
- [#258](https://github.com/WireMock-Net/WireMock.Net/issues/258) - InvalidProgramException when following running as standalone process example with dotnetcore [invalid]
|
||||
|
||||
# 1.0.9.0 (25 March 2019)
|
||||
- [#256](https://github.com/WireMock-Net/WireMock.Net/pull/256) - Fixed Multi Param Match logic contributed by [StefH](https://github.com/StefH)
|
||||
@@ -112,26 +152,21 @@
|
||||
|
||||
# 1.0.8.0 (12 March 2019)
|
||||
- [#254](https://github.com/WireMock-Net/WireMock.Net/pull/254) - RequestMessageParamMatcher supports Ignore Case for the key [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#251](https://github.com/WireMock-Net/WireMock.Net/issues/251) - Problem with Request Match WithBody [question]
|
||||
- [#253](https://github.com/WireMock-Net/WireMock.Net/issues/253) - Request Path and query parameter keys are case-sensitive
|
||||
|
||||
# 1.0.7.0 (19 January 2019)
|
||||
- [#244](https://github.com/WireMock-Net/WireMock.Net/pull/244) - Fix BodyAsFile to also allow relative paths [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#240](https://github.com/WireMock-Net/WireMock.Net/issues/240) - How to submit mappings for multiple request, responses [feature]
|
||||
- [#243](https://github.com/WireMock-Net/WireMock.Net/issues/243) - Not able to read response from file [question]
|
||||
- [#243](https://github.com/WireMock-Net/WireMock.Net/issues/243) - Not able to read response from file [bug]
|
||||
|
||||
# 1.0.6.1 (10 January 2019)
|
||||
- [#247](https://github.com/WireMock-Net/WireMock.Net/pull/247) - Issue 225 improve logging in example for wire mock as windows service contributed by [paulssn](https://github.com/paulssn)
|
||||
- [#249](https://github.com/WireMock-Net/WireMock.Net/pull/249) - Fixed "Content-Type multipart/form-data" [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#225](https://github.com/WireMock-Net/WireMock.Net/issues/225) - Feature: Improve logging in example for WireMock as Windows Service [feature]
|
||||
- [#238](https://github.com/WireMock-Net/WireMock.Net/issues/238) - Localhost and free port problem [question]
|
||||
- [#245](https://github.com/WireMock-Net/WireMock.Net/issues/245) - Not able to match XML request body using XPathMatcher pattern [question]
|
||||
- [#248](https://github.com/WireMock-Net/WireMock.Net/issues/248) - Content-Type multipart/form-data is not seen as byte[] anymore
|
||||
|
||||
# 1.0.6 (15 December 2018)
|
||||
- [#242](https://github.com/WireMock-Net/WireMock.Net/pull/242) - Post multiple Mappings [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#237](https://github.com/WireMock-Net/WireMock.Net/issues/237) - Port not released [question]
|
||||
- [#239](https://github.com/WireMock-Net/WireMock.Net/issues/239) - Not able to hit the mock server if AllowPartialMapping is not set to true [question]
|
||||
|
||||
# 1.0.5 (07 December 2018)
|
||||
- [#236](https://github.com/WireMock-Net/WireMock.Net/pull/236) - Add Random Regex (using Fare) [feature] contributed by [StefH](https://github.com/StefH)
|
||||
@@ -152,7 +187,6 @@
|
||||
- [#224](https://github.com/WireMock-Net/WireMock.Net/pull/224) - Fixed issue 223: Example for WireMock as Windows Service throws Exception because of WireMockConsoleLogger contributed by [paulssn](https://github.com/paulssn)
|
||||
- [#228](https://github.com/WireMock-Net/WireMock.Net/pull/228) - Fixed logic for IsRestrictedResponseHeader [bug] contributed by [StefH](https://github.com/StefH)
|
||||
- [#223](https://github.com/WireMock-Net/WireMock.Net/issues/223) - Bug: Example for WireMock as Windows Service throws Exception because of WireMockConsoleLogger [bug]
|
||||
- [#227](https://github.com/WireMock-Net/WireMock.Net/issues/227) - Question: proxy passthrough when no match? [question]
|
||||
|
||||
# 1.0.4.19 (31 October 2018)
|
||||
- [#220](https://github.com/WireMock-Net/WireMock.Net/pull/220) - Update SimpleCommandLineParser to handle arguments with key and value contributed by [StefH](https://github.com/StefH)
|
||||
@@ -178,7 +212,6 @@
|
||||
# 1.0.4.17 (22 September 2018)
|
||||
- [#203](https://github.com/WireMock-Net/WireMock.Net/pull/203) - Set up CI with Azure Pipelines contributed by [azure-pipelines[bot]](https://github.com/apps/azure-pipelines)
|
||||
- [#204](https://github.com/WireMock-Net/WireMock.Net/pull/204) - Lower priority from Proxy mappings in favor of Admin Mappings [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#115](https://github.com/WireMock-Net/WireMock.Net/issues/115) - Question : Do we have provision to read the Response data from a file? [question]
|
||||
- [#200](https://github.com/WireMock-Net/WireMock.Net/issues/200) - Issue: Incorrect port matching
|
||||
- [#205](https://github.com/WireMock-Net/WireMock.Net/issues/205) - Issue: DELETE method is proxied as lowercase [bug]
|
||||
|
||||
@@ -197,7 +230,6 @@
|
||||
# 1.0.4.13 (31 August 2018)
|
||||
- [#195](https://github.com/WireMock-Net/WireMock.Net/pull/195) - Add LinqMatcher contributed by [StefH](https://github.com/StefH)
|
||||
- [#192](https://github.com/WireMock-Net/WireMock.Net/issues/192) - Cannot upgrade from 1.0.4.10 to 1.0.4.12 without upgrading to .net core 2.1 [bug]
|
||||
- [#193](https://github.com/WireMock-Net/WireMock.Net/issues/193) - Question: WireMock in Azure [question]
|
||||
|
||||
# 1.0.4.12 (23 August 2018)
|
||||
- [#190](https://github.com/WireMock-Net/WireMock.Net/pull/190) - Fix ResponseMessageTransformer (#188) contributed by [StefH](https://github.com/StefH)
|
||||
@@ -240,10 +272,8 @@
|
||||
- [#164](https://github.com/WireMock-Net/WireMock.Net/pull/164) - Support running WireMock.Net as a sub-app in IIS [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#165](https://github.com/WireMock-Net/WireMock.Net/pull/165) - Add SonarCloud contributed by [StefH](https://github.com/StefH)
|
||||
- [#166](https://github.com/WireMock-Net/WireMock.Net/pull/166) - Fix Sonar issues contributed by [StefH](https://github.com/StefH)
|
||||
- [#105](https://github.com/WireMock-Net/WireMock.Net/issues/105) - Question: URL binding issues [question]
|
||||
- [#120](https://github.com/WireMock-Net/WireMock.Net/issues/120) - Question: JsonPathMatcher - not matching? Correct syntax?
|
||||
- [#123](https://github.com/WireMock-Net/WireMock.Net/issues/123) - Fix for DateTime Header causing null value in ResponseBuilder
|
||||
- [#158](https://github.com/WireMock-Net/WireMock.Net/issues/158) - Feature: Support running WireMock.Net as a sub-app in IIS [question]
|
||||
|
||||
# 1.0.4.4 (01 July 2018)
|
||||
- [#156](https://github.com/WireMock-Net/WireMock.Net/issues/156) - Feature: when adding / updating a mapping : return more details
|
||||
@@ -275,24 +305,18 @@
|
||||
|
||||
# 1.0.3.18 (25 May 2018)
|
||||
- [#142](https://github.com/WireMock-Net/WireMock.Net/pull/142) - Allow all headers to be set as Response headers contributed by [StefH](https://github.com/StefH)
|
||||
- [#97](https://github.com/WireMock-Net/WireMock.Net/issues/97) - Request matching logic is not practical [question]
|
||||
- [#122](https://github.com/WireMock-Net/WireMock.Net/issues/122) - WireMock.Net not responding in unit tests - same works in console application
|
||||
- [#126](https://github.com/WireMock-Net/WireMock.Net/issues/126) - Question: UsingHead always returns 0 for Content-Length header even when explicitly specified
|
||||
- [#127](https://github.com/WireMock-Net/WireMock.Net/issues/127) - Question: Stub priority - Most recent stub is not always used [question]
|
||||
- [#132](https://github.com/WireMock-Net/WireMock.Net/issues/132) - LogEntries not being recorded on subsequent tests
|
||||
- [#136](https://github.com/WireMock-Net/WireMock.Net/issues/136) - Question: Does the WireMock send Content-Length response header
|
||||
- [#137](https://github.com/WireMock-Net/WireMock.Net/issues/137) - Question: How to specify Transfer-Encoding response header?
|
||||
- [#139](https://github.com/WireMock-Net/WireMock.Net/issues/139) - Wiki link https://github.com/StefH/WireMock.Net/wiki/Record-(via-proxy)-and-Save is dead
|
||||
- [#140](https://github.com/WireMock-Net/WireMock.Net/issues/140) - Question: Why the Microsoft.Owin.Host.HttpListener is not referenced in the dll, which uses WireMock? [question]
|
||||
|
||||
# 1.0.3.17 (16 May 2018)
|
||||
- [#134](https://github.com/WireMock-Net/WireMock.Net/pull/134) - Stef negate matcher contributed by [alastairtree](https://github.com/alastairtree)
|
||||
- [#135](https://github.com/WireMock-Net/WireMock.Net/pull/135) - Merge into the stef_negate_matcher branch (solves issue #133) contributed by [StefH](https://github.com/StefH)
|
||||
- [#138](https://github.com/WireMock-Net/WireMock.Net/pull/138) - Added Negate matcher logic contributed by [StefH](https://github.com/StefH)
|
||||
- [#103](https://github.com/WireMock-Net/WireMock.Net/issues/103) - Support for Faults [question]
|
||||
- [#128](https://github.com/WireMock-Net/WireMock.Net/issues/128) - Feature: Negate a matcher [feature, question]
|
||||
- [#130](https://github.com/WireMock-Net/WireMock.Net/issues/130) - ...
|
||||
- [#133](https://github.com/WireMock-Net/WireMock.Net/issues/133) - Issue: Wildcard matching a json body does not work? [bug, question]
|
||||
|
||||
# 1.0.3.16 (17 April 2018)
|
||||
- [#121](https://github.com/WireMock-Net/WireMock.Net/pull/121) - Fix for issue #118 [bug] contributed by [raghavendrabankapur](https://github.com/raghavendrabankapur)
|
||||
@@ -309,9 +333,6 @@
|
||||
- [#113](https://github.com/WireMock-Net/WireMock.Net/issues/113) - Feature: Add BodyAsJsonIndented for response message [feature]
|
||||
- [#114](https://github.com/WireMock-Net/WireMock.Net/issues/114) - Feature: Add PathSegments in Transform [feature]
|
||||
|
||||
# 1.0.3.12 (24 March 2018)
|
||||
- [#100](https://github.com/WireMock-Net/WireMock.Net/issues/100) - Issue: JsonPathMatcher - not working for rootless jsons? [question]
|
||||
|
||||
# 1.0.3.11 (20 March 2018)
|
||||
- [#110](https://github.com/WireMock-Net/WireMock.Net/issues/110) - Fix: remove `Func[]` from MappingModel
|
||||
|
||||
@@ -324,9 +345,6 @@
|
||||
# 1.0.3.8 (10 March 2018)
|
||||
- [#106](https://github.com/WireMock-Net/WireMock.Net/issues/106) - Issue: Params does not work, when there are multiple values for a key
|
||||
|
||||
# 1.0.3.7 (09 March 2018)
|
||||
- [#104](https://github.com/WireMock-Net/WireMock.Net/issues/104) - Issue: PlatformNotSupportedException [question]
|
||||
|
||||
# 1.0.3.4 (04 March 2018)
|
||||
- [#95](https://github.com/WireMock-Net/WireMock.Net/pull/95) - Unittest fix contributed by [StefH](https://github.com/StefH)
|
||||
- [#96](https://github.com/WireMock-Net/WireMock.Net/pull/96) - Replace log4net by custom logger (#94) contributed by [StefH](https://github.com/StefH)
|
||||
@@ -382,7 +400,6 @@
|
||||
- [#65](https://github.com/WireMock-Net/WireMock.Net/pull/65) - bug: Fix admin api client definition returning the wrong types contributed by [alastairtree](https://github.com/alastairtree)
|
||||
- [#67](https://github.com/WireMock-Net/WireMock.Net/pull/67) - bug: fix supporting the Patch method and logging the body contributed by [alastairtree](https://github.com/alastairtree)
|
||||
- [#64](https://github.com/WireMock-Net/WireMock.Net/issues/64) - Pull Requests do not trigger test + codecoverage ?
|
||||
- [#68](https://github.com/WireMock-Net/WireMock.Net/issues/68) - Full path required in Stub [question]
|
||||
|
||||
# 1.0.2.7 (18 November 2017)
|
||||
- [#62](https://github.com/WireMock-Net/WireMock.Net/pull/62) - Add the Host, Protocol, Port and Origin to the Request message so they can be used in templating contributed by [alastairtree](https://github.com/alastairtree)
|
||||
@@ -390,7 +407,6 @@
|
||||
- [#27](https://github.com/WireMock-Net/WireMock.Net/issues/27) - New feature: Record and Save
|
||||
- [#42](https://github.com/WireMock-Net/WireMock.Net/issues/42) - Enhancement - Save/load request logs to/from disk [feature]
|
||||
- [#53](https://github.com/WireMock-Net/WireMock.Net/issues/53) - New feature request: Access to Owin pipeline
|
||||
- [#61](https://github.com/WireMock-Net/WireMock.Net/issues/61) - Partial mapping [question]
|
||||
|
||||
# 1.0.2.6 (30 October 2017)
|
||||
- [#59](https://github.com/WireMock-Net/WireMock.Net/pull/59) - Add ability to provide multiple values for headers in response contributed by [Dreamescaper](https://github.com/Dreamescaper)
|
||||
@@ -414,13 +430,8 @@
|
||||
- [#45](https://github.com/WireMock-Net/WireMock.Net/pull/45) - Add RequestLogExpirationDuration and MaxRequestLogCount (#43) contributed by [StefH](https://github.com/StefH)
|
||||
- [#51](https://github.com/WireMock-Net/WireMock.Net/pull/51) - Observable logs contributed by [deeptowncitizen](https://github.com/deeptowncitizen)
|
||||
- [#15](https://github.com/WireMock-Net/WireMock.Net/issues/15) - New feature: Proxying [feature]
|
||||
- [#19](https://github.com/WireMock-Net/WireMock.Net/issues/19) - Is this the same as Mock4Net? [question]
|
||||
- [#20](https://github.com/WireMock-Net/WireMock.Net/issues/20) - Add client certificate authentication [question]
|
||||
- [#31](https://github.com/WireMock-Net/WireMock.Net/issues/31) - Feature request: Nuget package for standalone version [feature]
|
||||
- [#33](https://github.com/WireMock-Net/WireMock.Net/issues/33) - Issue with launching sample code (StandAlone server) [bug]
|
||||
- [#34](https://github.com/WireMock-Net/WireMock.Net/issues/34) - Where is SearchLogsFor method? [question]
|
||||
- [#36](https://github.com/WireMock-Net/WireMock.Net/issues/36) - How to implement a request body-dependent response? [question]
|
||||
- [#37](https://github.com/WireMock-Net/WireMock.Net/issues/37) - Wrong Request Match result is returning [question]
|
||||
- [#38](https://github.com/WireMock-Net/WireMock.Net/issues/38) - Bug: support also listening on *:{port}
|
||||
- [#43](https://github.com/WireMock-Net/WireMock.Net/issues/43) - Feature: Add RequestLogExpirationDuration and MaxRequestLogCount
|
||||
- [#46](https://github.com/WireMock-Net/WireMock.Net/issues/46) - Log the ip-address from the client/caller also in the RequestLog [feature]
|
||||
@@ -428,8 +439,6 @@
|
||||
- [#50](https://github.com/WireMock-Net/WireMock.Net/issues/50) - New Feature: Callbacks
|
||||
|
||||
# 1.0.2.1 (14 June 2017)
|
||||
- [#28](https://github.com/WireMock-Net/WireMock.Net/issues/28) - Facing issue with WildcardMatcher and '?' [question]
|
||||
- [#29](https://github.com/WireMock-Net/WireMock.Net/issues/29) - Support of .Net 4.0 [question]
|
||||
- [#30](https://github.com/WireMock-Net/WireMock.Net/issues/30) - [Feature] Disable partial mappings by default in standalone version [bug, feature]
|
||||
|
||||
# 1.0.2.0 (05 May 2017)
|
||||
@@ -450,7 +459,6 @@
|
||||
- [#4](https://github.com/WireMock-Net/WireMock.Net/issues/4) - Handlebar support
|
||||
- [#5](https://github.com/WireMock-Net/WireMock.Net/issues/5) - Xml(2)Path matching
|
||||
- [#6](https://github.com/WireMock-Net/WireMock.Net/issues/6) - JsonPath support matching
|
||||
- [#7](https://github.com/WireMock-Net/WireMock.Net/issues/7) - Add WithStatusCodeRange matching [invalid]
|
||||
- [#9](https://github.com/WireMock-Net/WireMock.Net/issues/9) - Cookie matching
|
||||
- [#10](https://github.com/WireMock-Net/WireMock.Net/issues/10) - Add usingDelete [feature]
|
||||
- [#11](https://github.com/WireMock-Net/WireMock.Net/issues/11) - Add response body in binary format [feature]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>1.0.29</VersionPrefix>
|
||||
<VersionPrefix>1.0.41</VersionPrefix>
|
||||
</PropertyGroup>
|
||||
|
||||
<Choose>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
https://github.com/StefH/GitHubReleaseNotes
|
||||
|
||||
GitHubReleaseNotes.exe --output CHANGELOG.md --skip-empty-releases --version 1.0.29.0
|
||||
GitHubReleaseNotes.exe --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc --version 1.0.41.0
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2036
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29512.175
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EF242EDF-7133-4277-9A0C-18744DE08707}"
|
||||
EndProject
|
||||
@@ -9,6 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.runsettings = .runsettings
|
||||
azure-pipelines-linux.yml = azure-pipelines-linux.yml
|
||||
azure-pipelines-nuget.yml = azure-pipelines-nuget.yml
|
||||
azure-pipelines.yml = azure-pipelines.yml
|
||||
build-info.md = build-info.md
|
||||
CHANGELOG.md = CHANGELOG.md
|
||||
@@ -60,6 +61,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Console.Net452
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.NETCoreApp2", "examples\WireMock.Net.Console.NETCoreApp2\WireMock.Net.Console.NETCoreApp2.csproj", "{83645809-9E01-4E81-8733-BA9497554ABF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Console.RequestLogTest", "examples\WireMock.Net.Console.RequestLogTest\WireMock.Net.Console.RequestLogTest.csproj", "{A9D039B9-7509-4CF1-9EFD-87EB82998575}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -130,6 +133,10 @@ Global
|
||||
{83645809-9E01-4E81-8733-BA9497554ABF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{83645809-9E01-4E81-8733-BA9497554ABF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{83645809-9E01-4E81-8733-BA9497554ABF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -151,6 +158,7 @@ Global
|
||||
{1261BB9B-A7D4-456C-8985-3CE560361B8E} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
|
||||
{668F689E-57B4-422E-8846-C0FF643CA268} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
|
||||
{83645809-9E01-4E81-8733-BA9497554ABF} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
|
||||
{A9D039B9-7509-4CF1-9EFD-87EB82998575} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {BF428BCC-C837-433B-87D2-15C7014B73E9}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CS/@EntryIndexedValue">CS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ID/@EntryIndexedValue">ID</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MD/@EntryIndexedValue">MD5</s:String>
|
||||
|
||||
46
azure-pipelines-nuget.yml
Normal file
46
azure-pipelines-nuget.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
pool:
|
||||
vmImage: 'vs2017-win2016'
|
||||
|
||||
variables:
|
||||
Prerelease: ''
|
||||
buildId: "1$(Build.BuildId)"
|
||||
buildProjects: '**/src/**/*.csproj'
|
||||
|
||||
steps:
|
||||
# Print buildId
|
||||
- script: |
|
||||
echo "BuildId = $(buildId)"
|
||||
displayName: 'Print buildId'
|
||||
|
||||
# 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)
|
||||
|
||||
- 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 NuGet
|
||||
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://api.nuget.org/v3/index.json -k $(NuGetKey)
|
||||
@@ -1,5 +1,5 @@
|
||||
pool:
|
||||
vmImage: 'vs2017-win2016'
|
||||
vmImage: 'windows-2019'
|
||||
|
||||
variables:
|
||||
Prerelease: 'ci'
|
||||
@@ -26,6 +26,7 @@ steps:
|
||||
- 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'))
|
||||
|
||||
# Build source, tests and run tests for net452 and netcoreapp2.1 (with coverage)
|
||||
- script: |
|
||||
@@ -37,9 +38,11 @@ steps:
|
||||
- script: |
|
||||
%USERPROFILE%\.dotnet\tools\dotnet-sonarscanner end /d:sonar.login="$(SONAR_TOKEN)"
|
||||
displayName: End SonarScanner
|
||||
condition: and(succeeded(), eq(variables['RUN_SONAR'], 'yes'))
|
||||
|
||||
- task: whitesource.ws-bolt.bolt.wss.WhiteSource Bolt@19
|
||||
displayName: 'WhiteSource Bolt'
|
||||
condition: and(succeeded(), eq(variables['RUN_WHITESOURCE'], 'yes'))
|
||||
|
||||
# Upload coverage to codecov.io
|
||||
- script: |
|
||||
@@ -76,10 +79,11 @@ steps:
|
||||
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 --source https://www.myget.org/F/wiremock-net/api/v3/index.json --no-service-endpoint --api-key $(MyGetKey)
|
||||
arguments: push $(Build.ArtifactStagingDirectory)\packages\*.nupkg -n true -s https://www.myget.org/F/wiremock-net/api/v3/index.json -k $(MyGetKey)
|
||||
@@ -3,13 +3,14 @@ using RestEase;
|
||||
using System;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using WireMock.Client;
|
||||
|
||||
namespace WireMock.Net.Client
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
// Create an implementation of the IFluentMockServerAdmin and pass in the base URL for the API.
|
||||
var api = RestClient.For<IFluentMockServerAdmin>("http://localhost:9091");
|
||||
@@ -18,29 +19,29 @@ namespace WireMock.Net.Client
|
||||
var value = Convert.ToBase64String(Encoding.ASCII.GetBytes("a:b"));
|
||||
api.Authorization = new AuthenticationHeaderValue("Basic", value);
|
||||
|
||||
var settings1 = api.GetSettingsAsync().Result;
|
||||
var settings1 = await api.GetSettingsAsync();
|
||||
Console.WriteLine($"settings1 = {JsonConvert.SerializeObject(settings1)}");
|
||||
|
||||
settings1.GlobalProcessingDelay = 1077;
|
||||
api.PostSettingsAsync(settings1).Wait();
|
||||
|
||||
var settings2 = api.GetSettingsAsync().Result;
|
||||
var settings2 = await api.GetSettingsAsync();
|
||||
Console.WriteLine($"settings2 = {JsonConvert.SerializeObject(settings2)}");
|
||||
|
||||
var mappings = api.GetMappingsAsync().Result;
|
||||
var mappings = await api.GetMappingsAsync();
|
||||
Console.WriteLine($"mappings = {JsonConvert.SerializeObject(mappings)}");
|
||||
|
||||
try
|
||||
{
|
||||
var guid = Guid.Parse("11111110-a633-40e8-a244-5cb80bc0ab66");
|
||||
var mapping = api.GetMappingAsync(guid).Result;
|
||||
var mapping = await api.GetMappingAsync(guid);
|
||||
Console.WriteLine($"mapping = {JsonConvert.SerializeObject(mapping)}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
|
||||
var request = api.GetRequestsAsync().Result;
|
||||
var request = await api.GetRequestsAsync();
|
||||
Console.WriteLine($"request = {JsonConvert.SerializeObject(request)}");
|
||||
|
||||
//var deleteRequestsAsync = api.DeleteRequestsAsync().Result;
|
||||
@@ -49,15 +50,21 @@ namespace WireMock.Net.Client
|
||||
//var resetRequestsAsync = api.ResetRequestsAsync().Result;
|
||||
//Console.WriteLine($"ResetRequestsAsync = {resetRequestsAsync.Status}");
|
||||
|
||||
var scenarioStates = api.GetScenariosAsync().Result;
|
||||
var scenarioStates = await api.GetScenariosAsync();
|
||||
Console.WriteLine($"GetScenariosAsync = {JsonConvert.SerializeObject(scenarioStates)}");
|
||||
|
||||
var postFileResult = api.PostFileAsync("1.cs", "C# Hello").GetAwaiter().GetResult();
|
||||
var postFileResult = await api.PostFileAsync("1.cs", "C# Hello");
|
||||
Console.WriteLine($"postFileResult = {JsonConvert.SerializeObject(postFileResult)}");
|
||||
|
||||
var getFileResult = api.GetFileAsync("1.cs").GetAwaiter().GetResult();
|
||||
var getFileResult = await api.GetFileAsync("1.cs");
|
||||
Console.WriteLine($"getFileResult = {getFileResult}");
|
||||
|
||||
var resetMappingsAsync = await api.ResetMappingsAsync();
|
||||
Console.WriteLine($"resetMappingsAsync = {resetMappingsAsync.Status}");
|
||||
|
||||
var resetMappingsAndReloadStaticMappingsAsync = await api.ResetMappingsAsync(true);
|
||||
Console.WriteLine($"resetMappingsAndReloadStaticMappingsAsync = {resetMappingsAndReloadStaticMappingsAsync.Status}");
|
||||
|
||||
Console.WriteLine("Press any key to quit");
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<!-- <RuntimeFrameworkVersion>1.0.1</RuntimeFrameworkVersion> -->
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
// C# Hello
|
||||
@@ -21,9 +21,9 @@ namespace WireMock.Net.ConsoleApplication
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IFileSystemHandler.EnumerateFiles"/>
|
||||
public IEnumerable<string> EnumerateFiles(string path)
|
||||
public IEnumerable<string> EnumerateFiles(string path, bool includeSubdirectories)
|
||||
{
|
||||
return Directory.EnumerateFiles(path);
|
||||
return includeSubdirectories ? Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories) : Directory.EnumerateFiles(path);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IFileSystemHandler.GetMappingFolder"/>
|
||||
|
||||
@@ -41,10 +41,12 @@ namespace WireMock.Net.ConsoleApplication
|
||||
|
||||
var server = FluentMockServer.Start(new FluentMockServerSettings
|
||||
{
|
||||
AllowCSharpCodeMatcher = true,
|
||||
Urls = new[] { url1, url2, url3 },
|
||||
StartAdminInterface = true,
|
||||
ReadStaticMappings = true,
|
||||
WatchStaticMappings = true,
|
||||
WatchStaticMappingsInSubdirectories = true,
|
||||
//ProxyAndRecordSettings = new ProxyAndRecordSettings
|
||||
//{
|
||||
// SaveMapping = true
|
||||
@@ -103,6 +105,24 @@ namespace WireMock.Net.ConsoleApplication
|
||||
.WithProxy(new ProxyAndRecordSettings { Url = "http://postman-echo.com/get" })
|
||||
);
|
||||
|
||||
server
|
||||
.Given(Request.Create()
|
||||
.UsingGet()
|
||||
.WithHeader("postmanecho", "get2")
|
||||
)
|
||||
.RespondWith(Response.Create()
|
||||
.WithProxy(new ProxyAndRecordSettings
|
||||
{
|
||||
Url = "http://postman-echo.com/get",
|
||||
WebProxySettings = new WebProxySettings
|
||||
{
|
||||
Address = "http://company",
|
||||
UserName = "test",
|
||||
Password = "pwd"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
server
|
||||
.Given(Request.Create()
|
||||
.UsingGet()
|
||||
|
||||
63
examples/WireMock.Net.Console.RequestLogTest/Program.cs
Normal file
63
examples/WireMock.Net.Console.RequestLogTest/Program.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Net.StandAlone;
|
||||
using WireMock.RequestBuilders;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.Settings;
|
||||
|
||||
namespace WireMock.Net.Console.RequestLogTest
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
var server = StandAloneApp.Start(new FluentMockServerSettings
|
||||
{
|
||||
Port = 19019,
|
||||
StartAdminInterface = true,
|
||||
StartTimeout = 1000,
|
||||
MaxRequestLogCount = 100,
|
||||
RequestLogExpirationDuration = 6,
|
||||
Logger = new WireMockConsoleLogger()
|
||||
});
|
||||
|
||||
server
|
||||
.Given(Request
|
||||
.Create()
|
||||
.UsingGet())
|
||||
.RespondWith(Response.Create()
|
||||
.WithHeader("Content-Type", "application/json")
|
||||
.WithBodyAsJson(new { result = "x" }));
|
||||
|
||||
await Task.Delay(2000);
|
||||
|
||||
var client = new HttpClient();
|
||||
client.BaseAddress = new Uri(server.Urls[0]);
|
||||
|
||||
var options = new ParallelOptions()
|
||||
{
|
||||
MaxDegreeOfParallelism = 2
|
||||
};
|
||||
|
||||
var list = Enumerable.Range(1, 1000);
|
||||
Parallel.ForEach(list, options, async i =>
|
||||
{
|
||||
string result = await client.GetStringAsync("/x");
|
||||
System.Console.WriteLine(result);
|
||||
});
|
||||
|
||||
//for (int i = 0; i < 1000; i++)
|
||||
//{
|
||||
// string result = await client.GetStringAsync("/x");
|
||||
// System.Console.WriteLine(result);
|
||||
//}
|
||||
|
||||
System.Console.WriteLine("Press any key to stop the server");
|
||||
System.Console.ReadKey();
|
||||
server.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj" />
|
||||
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -11,13 +11,13 @@
|
||||
|
||||
<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="Microsoft.AspNetCore.All" Version="2.0.9" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
</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.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.All" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
BIN
resources/MyGet-Config.png
Normal file
BIN
resources/MyGet-Config.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
resources/MyGet-Use.png
Normal file
BIN
resources/MyGet-Use.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
@@ -1,9 +1,9 @@
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using System.Linq;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Server;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Validation;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Logging;
|
||||
|
||||
namespace WireMock.Net.StandAlone
|
||||
{
|
||||
@@ -46,11 +46,14 @@ namespace WireMock.Net.StandAlone
|
||||
StartAdminInterface = parser.GetBoolValue("StartAdminInterface", true),
|
||||
ReadStaticMappings = parser.GetBoolValue("ReadStaticMappings"),
|
||||
WatchStaticMappings = parser.GetBoolValue("WatchStaticMappings"),
|
||||
AllowPartialMapping = parser.GetBoolValue("AllowPartialMapping", false),
|
||||
WatchStaticMappingsInSubdirectories = parser.GetBoolValue("WatchStaticMappingsInSubdirectories"),
|
||||
AllowPartialMapping = parser.GetBoolValue("AllowPartialMapping"),
|
||||
AdminUsername = parser.GetStringValue("AdminUsername"),
|
||||
AdminPassword = parser.GetStringValue("AdminPassword"),
|
||||
MaxRequestLogCount = parser.GetIntValue("MaxRequestLogCount"),
|
||||
RequestLogExpirationDuration = parser.GetIntValue("RequestLogExpirationDuration")
|
||||
RequestLogExpirationDuration = parser.GetIntValue("RequestLogExpirationDuration"),
|
||||
AllowCSharpCodeMatcher = parser.GetBoolValue("AllowCSharpCodeMatcher"),
|
||||
AllowBodyForAllHttpMethods = parser.GetBoolValue("AllowBodyForAllHttpMethods")
|
||||
};
|
||||
|
||||
if (logger != null)
|
||||
@@ -80,10 +83,23 @@ namespace WireMock.Net.StandAlone
|
||||
Url = proxyURL,
|
||||
SaveMapping = parser.GetBoolValue("SaveMapping"),
|
||||
SaveMappingToFile = parser.GetBoolValue("SaveMappingToFile"),
|
||||
SaveMappingForStatusCodePattern = parser.GetStringValue("SaveMappingForStatusCodePattern"),
|
||||
ClientX509Certificate2ThumbprintOrSubjectName = parser.GetStringValue("ClientX509Certificate2ThumbprintOrSubjectName"),
|
||||
BlackListedHeaders = parser.GetValues("BlackListedHeaders"),
|
||||
BlackListedCookies = parser.GetValues("BlackListedCookies")
|
||||
BlackListedCookies = parser.GetValues("BlackListedCookies"),
|
||||
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")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
settings.Logger.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
<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>
|
||||
<PackageLicenseUrl>https://raw.githubusercontent.com/WireMock-Net/WireMock.Net/master/LICENSE</PackageLicenseUrl>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<RepositoryUrl>https://github.com/WireMock-Net/WireMock.Net</RepositoryUrl>
|
||||
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
|
||||
<RootNamespace>WireMock.Net.StandAlone</RootNamespace>
|
||||
<DebugType>full</DebugType>
|
||||
<!--<DebugType>full</DebugType>
|
||||
<IncludeSource>True</IncludeSource>
|
||||
<IncludeSymbols>True</IncludeSymbols>
|
||||
<IncludeSymbols>True</IncludeSymbols>-->
|
||||
<ProjectGuid>{B6269AAC-170A-43D5-8B9A-579DED3D9A95}</ProjectGuid>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
|
||||
|
||||
18
src/WireMock.Net/Admin/Mappings/FaultModel.cs
Normal file
18
src/WireMock.Net/Admin/Mappings/FaultModel.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace WireMock.Admin.Mappings
|
||||
{
|
||||
/// <summary>
|
||||
/// Fault Model
|
||||
/// </summary>
|
||||
public class FaultModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the fault. Can be null, "", NONE, EMPTY_RESPONSE, MALFORMED_RESPONSE_CHUNK or RANDOM_DATA_THEN_CLOSE.
|
||||
/// </summary>
|
||||
public string Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the fault percentage.
|
||||
/// </summary>
|
||||
public double? Percentage { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,11 @@ namespace WireMock.Admin.Mappings
|
||||
/// </summary>
|
||||
public bool? UseTransformer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Use the Handlerbars transformer for the content from the referenced BodyAsFile.
|
||||
/// </summary>
|
||||
public bool? UseTransformerForBodyAsFile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the headers.
|
||||
/// </summary>
|
||||
@@ -86,5 +91,15 @@ namespace WireMock.Admin.Mappings
|
||||
/// The client X509Certificate2 Thumbprint or SubjectName to use.
|
||||
/// </summary>
|
||||
public string X509Certificate2ThumbprintOrSubjectName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the fault.
|
||||
/// </summary>
|
||||
public FaultModel Fault { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the WebProxy settings.
|
||||
/// </summary>
|
||||
public WebProxyModel WebProxy { get; set; }
|
||||
}
|
||||
}
|
||||
23
src/WireMock.Net/Admin/Mappings/WebProxyModel.cs
Normal file
23
src/WireMock.Net/Admin/Mappings/WebProxyModel.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace WireMock.Admin.Mappings
|
||||
{
|
||||
/// <summary>
|
||||
/// WebProxy settings
|
||||
/// </summary>
|
||||
public class WebProxyModel
|
||||
{
|
||||
/// <summary>
|
||||
/// A string instance that contains the address of the proxy server.
|
||||
/// </summary>
|
||||
public string Address { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user name associated with the credentials.
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The password for the user name associated with the credentials.
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -68,5 +68,15 @@ namespace WireMock.Admin.Requests
|
||||
/// The detected body type (detection based on Content-Type).
|
||||
/// </summary>
|
||||
public BodyType DetectedBodyTypeFromContentType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The FaultType.
|
||||
/// </summary>
|
||||
public string FaultType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Fault percentage.
|
||||
/// </summary>
|
||||
public double? FaultPercentage { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -24,5 +24,10 @@
|
||||
/// Gets or sets the MaxRequestLog count.
|
||||
/// </summary>
|
||||
public int? MaxRequestLogCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets wether to allow a body for all HTTP methods.
|
||||
/// </summary>
|
||||
public bool? AllowBodyForAllHttpMethods { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -75,8 +75,9 @@ namespace WireMock.Client
|
||||
/// <summary>
|
||||
/// Delete (reset) all mappings.
|
||||
/// </summary>
|
||||
/// <param name="reloadStaticMappings">A value indicating whether to reload the static mappings after the reset.</param>
|
||||
[Post("__admin/mappings/reset")]
|
||||
Task<StatusModel> ResetMappingsAsync();
|
||||
Task<StatusModel> ResetMappingsAsync(bool? reloadStaticMappings = false);
|
||||
|
||||
/// <summary>
|
||||
/// Get a mapping based on the guid
|
||||
|
||||
28
src/WireMock.Net/Compatibility/WebProxy.cs
Normal file
28
src/WireMock.Net/Compatibility/WebProxy.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
#if NETSTANDARD1_3
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace System.Net
|
||||
{
|
||||
internal class WebProxy : IWebProxy
|
||||
{
|
||||
private readonly string _proxy;
|
||||
public ICredentials Credentials { get; set; }
|
||||
|
||||
public WebProxy(string proxy)
|
||||
{
|
||||
_proxy = proxy;
|
||||
}
|
||||
|
||||
public Uri GetProxy(Uri destination)
|
||||
{
|
||||
return new Uri(_proxy);
|
||||
}
|
||||
|
||||
public bool IsBypassed(Uri host)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -31,8 +31,9 @@ namespace WireMock.Handlers
|
||||
/// Returns an enumerable collection of file names in a specified path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>An enumerable collection of the full names (including paths) for the files in the directory specified by path.</returns>
|
||||
IEnumerable<string> EnumerateFiles([NotNull] string path);
|
||||
/// <param name="includeSubdirectories">A value indicating whether subdirectories should also included when enumerating files.</param>
|
||||
/// <returns>An enumerable collection of the full names (including paths) for the files in the directory (and optionally subdirectories) specified by path.</returns>
|
||||
IEnumerable<string> EnumerateFiles([NotNull] string path, bool includeSubdirectories);
|
||||
|
||||
/// <summary>
|
||||
/// Read a static mapping file as text.
|
||||
|
||||
@@ -46,11 +46,11 @@ namespace WireMock.Handlers
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IFileSystemHandler.EnumerateFiles"/>
|
||||
public IEnumerable<string> EnumerateFiles(string path)
|
||||
public IEnumerable<string> EnumerateFiles(string path, bool includeSubdirectories)
|
||||
{
|
||||
Check.NotNullOrEmpty(path, nameof(path));
|
||||
|
||||
return Directory.EnumerateFiles(path);
|
||||
return includeSubdirectories ? Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories) : Directory.EnumerateFiles(path);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IFileSystemHandler.GetMappingFolder"/>
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.HttpsCertificate;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Http
|
||||
{
|
||||
internal static class HttpClientHelper
|
||||
{
|
||||
public static HttpClient CreateHttpClient(string clientX509Certificate2ThumbprintOrSubjectName = null)
|
||||
public static HttpClient CreateHttpClient(IProxyAndRecordSettings settings)
|
||||
{
|
||||
#if NETSTANDARD
|
||||
var handler = new HttpClientHandler
|
||||
@@ -36,20 +37,30 @@ namespace WireMock.Http
|
||||
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
|
||||
#endif
|
||||
|
||||
if (!string.IsNullOrEmpty(clientX509Certificate2ThumbprintOrSubjectName))
|
||||
if (!string.IsNullOrEmpty(settings.ClientX509Certificate2ThumbprintOrSubjectName))
|
||||
{
|
||||
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
|
||||
|
||||
var x509Certificate2 = ClientCertificateHelper.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName);
|
||||
var x509Certificate2 = ClientCertificateHelper.GetCertificate(settings.ClientX509Certificate2ThumbprintOrSubjectName);
|
||||
handler.ClientCertificates.Add(x509Certificate2);
|
||||
}
|
||||
|
||||
// For proxy we shouldn't follow auto redirects
|
||||
handler.AllowAutoRedirect = false;
|
||||
handler.AllowAutoRedirect = settings.AllowAutoRedirect == true;
|
||||
|
||||
// If UseCookies enabled, httpClient ignores Cookie header
|
||||
handler.UseCookies = false;
|
||||
|
||||
if (settings.WebProxySettings != null)
|
||||
{
|
||||
handler.UseProxy = true;
|
||||
|
||||
handler.Proxy = new WebProxy(settings.WebProxySettings.Address);
|
||||
if (settings.WebProxySettings.UserName != null && settings.WebProxySettings.Password != null)
|
||||
{
|
||||
handler.Proxy.Credentials = new NetworkCredential(settings.WebProxySettings.UserName, settings.WebProxySettings.Password);
|
||||
}
|
||||
}
|
||||
|
||||
var client = new HttpClient(handler);
|
||||
#if NET452 || NET46
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
|
||||
@@ -72,7 +83,7 @@ namespace WireMock.Http
|
||||
var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead);
|
||||
|
||||
// Create ResponseMessage
|
||||
return await HttpResponseMessageHelper.Create(httpResponseMessage, requiredUri, originalUri);
|
||||
return await HttpResponseMessageHelper.CreateAsync(httpResponseMessage, requiredUri, originalUri);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using JetBrains.Annotations;
|
||||
using MimeKit;
|
||||
using Newtonsoft.Json;
|
||||
using WireMock.Util;
|
||||
using WireMock.Validation;
|
||||
@@ -19,11 +19,11 @@ namespace WireMock.Http
|
||||
|
||||
var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url);
|
||||
|
||||
ContentType contentType = null;
|
||||
MediaTypeHeaderValue contentType = null;
|
||||
if (requestMessage.Headers != null && requestMessage.Headers.ContainsKey(HttpKnownHeaderNames.ContentType))
|
||||
{
|
||||
var value = requestMessage.Headers[HttpKnownHeaderNames.ContentType].FirstOrDefault();
|
||||
ContentType.TryParse(value, out contentType);
|
||||
MediaTypeHeaderValue.TryParse(value, out contentType);
|
||||
}
|
||||
|
||||
switch (requestMessage.BodyData?.DetectedBodyType)
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace WireMock.Http
|
||||
{
|
||||
internal static class HttpResponseMessageHelper
|
||||
{
|
||||
public static async Task<ResponseMessage> Create(HttpResponseMessage httpResponseMessage, Uri requiredUri, Uri originalUri)
|
||||
public static async Task<ResponseMessage> CreateAsync(HttpResponseMessage httpResponseMessage, Uri requiredUri, Uri originalUri)
|
||||
{
|
||||
var responseMessage = new ResponseMessage { StatusCode = (int)httpResponseMessage.StatusCode };
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using JetBrains.Annotations;
|
||||
using MimeKit;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Http
|
||||
@@ -10,29 +8,18 @@ namespace WireMock.Http
|
||||
internal static class StringContentHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a StringContent object. Note that the Encoding is only set when it's also set on the original header.
|
||||
/// Creates a StringContent object.
|
||||
/// </summary>
|
||||
/// <param name="content">The string content (cannot be null)</param>
|
||||
/// <param name="contentType">The ContentType (can be null)</param>
|
||||
/// <returns>StringContent</returns>
|
||||
internal static StringContent Create([NotNull] string content, [CanBeNull] ContentType contentType)
|
||||
internal static StringContent Create([NotNull] string content, [CanBeNull] MediaTypeHeaderValue contentType)
|
||||
{
|
||||
Check.NotNull(content, nameof(content));
|
||||
|
||||
if (contentType == null)
|
||||
{
|
||||
return new StringContent(content);
|
||||
}
|
||||
|
||||
if (contentType.Charset == null)
|
||||
{
|
||||
var stringContent = new StringContent(content);
|
||||
stringContent.Headers.ContentType = new MediaTypeHeaderValue(contentType.MimeType);
|
||||
return stringContent;
|
||||
}
|
||||
|
||||
var encoding = Encoding.GetEncoding(contentType.Charset);
|
||||
return new StringContent(content, encoding, contentType.MimeType);
|
||||
var stringContent = new StringContent(content);
|
||||
stringContent.Headers.ContentType = contentType;
|
||||
return stringContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,9 @@ using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace WireMock.HttpsCertificate
|
||||
{
|
||||
/// <summary>
|
||||
/// Only used for NetStandard 1.3
|
||||
/// </summary>
|
||||
internal static class PublicCertificateHelper
|
||||
{
|
||||
// 1] Generate using https://www.pluralsight.com/blog/software-development/selfcert-create-a-self-signed-certificate-interactively-gui-or-programmatically-in-net
|
||||
|
||||
@@ -78,6 +78,14 @@ namespace WireMock
|
||||
/// <c>true</c> if this mapping is an Admin Interface; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
bool IsAdminInterface { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this mapping to be logged.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this mapping to be logged; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
bool LogMapping { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ProvideResponseAsync
|
||||
|
||||
@@ -48,6 +48,9 @@ namespace WireMock
|
||||
/// <inheritdoc cref="IMapping.IsAdminInterface" />
|
||||
public bool IsAdminInterface => Provider is DynamicResponseProvider || Provider is DynamicAsyncResponseProvider || Provider is ProxyAsyncResponseProvider;
|
||||
|
||||
/// <inheritdoc cref="IMapping.LogMapping" />
|
||||
public bool LogMapping => !(Provider is DynamicResponseProvider || Provider is DynamicAsyncResponseProvider);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Mapping"/> class.
|
||||
/// </summary>
|
||||
|
||||
197
src/WireMock.Net/Matchers/CSharpCodeMatcher.cs
Normal file
197
src/WireMock.Net/Matchers/CSharpCodeMatcher.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using WireMock.Exceptions;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Matchers
|
||||
{
|
||||
/// <summary>
|
||||
/// CSharpCode / CS-Script Matcher
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="IObjectMatcher"/>
|
||||
/// <inheritdoc cref="IStringMatcher"/>
|
||||
internal class CSharpCodeMatcher : IObjectMatcher, IStringMatcher
|
||||
{
|
||||
private const string TemplateForIsMatchWithString = "{0} public class CodeHelper {{ public bool IsMatch(string it) {{ {1} }} }}";
|
||||
|
||||
private const string TemplateForIsMatchWithDynamic = "{0} public class CodeHelper {{ public bool IsMatch(dynamic it) {{ {1} }} }}";
|
||||
|
||||
private readonly string[] _usings =
|
||||
{
|
||||
"System",
|
||||
"System.Linq",
|
||||
"System.Collections.Generic",
|
||||
"Microsoft.CSharp",
|
||||
"Newtonsoft.Json.Linq"
|
||||
};
|
||||
|
||||
public MatchBehaviour MatchBehaviour { get; }
|
||||
|
||||
private readonly string[] _patterns;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CSharpCodeMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="patterns">The patterns.</param>
|
||||
public CSharpCodeMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CSharpCodeMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||
/// <param name="patterns">The patterns.</param>
|
||||
public CSharpCodeMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] patterns)
|
||||
{
|
||||
Check.NotNull(patterns, nameof(patterns));
|
||||
|
||||
MatchBehaviour = matchBehaviour;
|
||||
_patterns = patterns;
|
||||
}
|
||||
|
||||
public double IsMatch(string input)
|
||||
{
|
||||
return IsMatchInternal(input);
|
||||
}
|
||||
|
||||
public double IsMatch(object input)
|
||||
{
|
||||
return IsMatchInternal(input);
|
||||
}
|
||||
|
||||
public double IsMatchInternal(object input)
|
||||
{
|
||||
double match = MatchScores.Mismatch;
|
||||
|
||||
if (input != null)
|
||||
{
|
||||
match = MatchScores.ToScore(_patterns.Select(pattern => IsMatch(input, pattern)));
|
||||
}
|
||||
|
||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||
}
|
||||
|
||||
private bool IsMatch(dynamic input, string pattern)
|
||||
{
|
||||
bool isMatchWithString = input is string;
|
||||
var inputValue = isMatchWithString ? input : JObject.FromObject(input);
|
||||
string source = GetSourceForIsMatchWithString(pattern, isMatchWithString);
|
||||
|
||||
object result = null;
|
||||
|
||||
#if NET451 || NET452
|
||||
var compilerParams = new System.CodeDom.Compiler.CompilerParameters
|
||||
{
|
||||
GenerateInMemory = true,
|
||||
GenerateExecutable = false,
|
||||
ReferencedAssemblies =
|
||||
{
|
||||
"System.dll",
|
||||
"System.Core.dll",
|
||||
"Microsoft.CSharp.dll",
|
||||
"Newtonsoft.Json.dll"
|
||||
}
|
||||
};
|
||||
|
||||
using (var codeProvider = new Microsoft.CSharp.CSharpCodeProvider())
|
||||
{
|
||||
var compilerResults = codeProvider.CompileAssemblyFromSource(compilerParams, source);
|
||||
|
||||
if (compilerResults.Errors.Count != 0)
|
||||
{
|
||||
var errors = from System.CodeDom.Compiler.CompilerError er in compilerResults.Errors select er.ToString();
|
||||
throw new WireMockException(string.Join(", ", errors));
|
||||
}
|
||||
|
||||
object helper = compilerResults.CompiledAssembly.CreateInstance("CodeHelper");
|
||||
if (helper == null)
|
||||
{
|
||||
throw new WireMockException("CSharpCodeMatcher: Unable to create instance from WireMock.CodeHelper");
|
||||
}
|
||||
|
||||
var methodInfo = helper.GetType().GetMethod("IsMatch");
|
||||
if (methodInfo == null)
|
||||
{
|
||||
throw new WireMockException("CSharpCodeMatcher: Unable to find method 'IsMatch' in WireMock.CodeHelper");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
result = methodInfo.Invoke(helper, new[] { inputValue });
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new WireMockException("CSharpCodeMatcher: Unable to call method 'IsMatch' in WireMock.CodeHelper");
|
||||
}
|
||||
}
|
||||
#elif NET46 || NET461
|
||||
dynamic script;
|
||||
try
|
||||
{
|
||||
script = CSScriptLibrary.CSScript.Evaluator.CompileCode(source).CreateObject("*");
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new WireMockException("CSharpCodeMatcher: Unable to create compiler for WireMock.CodeHelper");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
result = script.IsMatch(inputValue);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new WireMockException("CSharpCodeMatcher: Problem calling method 'IsMatch' in WireMock.CodeHelper");
|
||||
}
|
||||
#elif NETSTANDARD2_0
|
||||
dynamic script;
|
||||
try
|
||||
{
|
||||
var assembly = CSScriptLib.CSScript.Evaluator.CompileCode(source);
|
||||
script = csscript.GenericExtensions.CreateObject(assembly, "*");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new WireMockException("CSharpCodeMatcher: Unable to compile code for WireMock.CodeHelper", ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
result = script.IsMatch(inputValue);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new WireMockException("CSharpCodeMatcher: Problem calling method 'IsMatch' in WireMock.CodeHelper");
|
||||
}
|
||||
#else
|
||||
throw new NotSupportedException("The 'CSharpCodeMatcher' cannot be used in netstandard 1.3");
|
||||
#endif
|
||||
try
|
||||
{
|
||||
return (bool)result;
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new WireMockException($"Unable to cast result '{result}' to bool");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
|
||||
public string[] GetPatterns()
|
||||
{
|
||||
return _patterns;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IMatcher.Name"/>
|
||||
public string Name => "CSharpCodeMatcher";
|
||||
}
|
||||
}
|
||||
73
src/WireMock.Net/Matchers/ContentTypeMatcher.cs
Normal file
73
src/WireMock.Net/Matchers/ContentTypeMatcher.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System.Net.Http.Headers;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace WireMock.Matchers
|
||||
{
|
||||
/// <summary>
|
||||
/// ContentTypeMatcher which accepts also all charsets
|
||||
/// </summary>
|
||||
/// <seealso cref="RegexMatcher" />
|
||||
public class ContentTypeMatcher : WildcardMatcher
|
||||
{
|
||||
private readonly string[] _patterns;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="pattern">The pattern.</param>
|
||||
/// <param name="ignoreCase">IgnoreCase (default false)</param>
|
||||
public ContentTypeMatcher([NotNull] string pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||
/// <param name="pattern">The pattern.</param>
|
||||
/// <param name="ignoreCase">IgnoreCase (default false)</param>
|
||||
public ContentTypeMatcher(MatchBehaviour matchBehaviour, [NotNull] string pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="patterns">The patterns.</param>
|
||||
/// <param name="ignoreCase">IgnoreCase (default false)</param>
|
||||
public ContentTypeMatcher([NotNull] string[] patterns, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||
/// <param name="patterns">The patterns.</param>
|
||||
/// <param name="ignoreCase">IgnoreCase (default false)</param>
|
||||
public ContentTypeMatcher(MatchBehaviour matchBehaviour, [NotNull] string[] patterns, bool ignoreCase = false) : base(matchBehaviour, patterns, ignoreCase)
|
||||
{
|
||||
_patterns = patterns;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="RegexMatcher.IsMatch"/>
|
||||
public override double IsMatch(string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out MediaTypeHeaderValue contentType))
|
||||
{
|
||||
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch);
|
||||
}
|
||||
|
||||
return base.IsMatch(contentType.MediaType);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
|
||||
public override string[] GetPatterns()
|
||||
{
|
||||
return _patterns;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IMatcher.Name"/>
|
||||
public override string Name => "ContentTypeMatcher";
|
||||
}
|
||||
}
|
||||
@@ -93,10 +93,7 @@ namespace WireMock.Matchers
|
||||
|
||||
private double IsMatch(JToken jtoken)
|
||||
{
|
||||
// Wrap in array if needed
|
||||
JToken tokenOrArray = jtoken is JArray ? jtoken : new JArray(jtoken);
|
||||
|
||||
return MatchScores.ToScore(_patterns.Select(pattern => tokenOrArray.SelectToken(pattern) != null));
|
||||
return MatchScores.ToScore(_patterns.Select(pattern => jtoken.SelectToken(pattern) != null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using WireMock.Util;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Matchers
|
||||
@@ -84,7 +86,7 @@ namespace WireMock.Matchers
|
||||
// Check if JToken or object
|
||||
JToken jtokenInput = input is JToken tokenInput ? tokenInput : JObject.FromObject(input);
|
||||
|
||||
// Check if JToken or string or object
|
||||
// Check if JToken, string, IEnumerable or object
|
||||
JToken jtokenValue;
|
||||
switch (Value)
|
||||
{
|
||||
@@ -93,7 +95,11 @@ namespace WireMock.Matchers
|
||||
break;
|
||||
|
||||
case string stringValue:
|
||||
jtokenValue = JToken.Parse(stringValue);
|
||||
jtokenValue = JsonUtils.Parse(stringValue);
|
||||
break;
|
||||
|
||||
case IEnumerable enumerableValue:
|
||||
jtokenValue = JArray.FromObject(enumerableValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -9,8 +9,9 @@ namespace WireMock.Matchers
|
||||
/// <summary>
|
||||
/// System.Linq.Dynamic.Core Expression Matcher
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="IObjectMatcher"/>
|
||||
/// <inheritdoc cref="IStringMatcher"/>
|
||||
public class LinqMatcher : IStringMatcher
|
||||
public class LinqMatcher : IObjectMatcher, IStringMatcher
|
||||
{
|
||||
private readonly string[] _patterns;
|
||||
|
||||
@@ -117,7 +118,6 @@ namespace WireMock.Matchers
|
||||
}
|
||||
|
||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace WireMock.Matchers
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
|
||||
public double IsMatch(string input)
|
||||
public virtual double IsMatch(string input)
|
||||
{
|
||||
double match = MatchScores.Mismatch;
|
||||
if (input != null)
|
||||
|
||||
11
src/WireMock.Net/Matchers/Request/MatchDetail.cs
Normal file
11
src/WireMock.Net/Matchers/Request/MatchDetail.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace WireMock.Matchers.Request
|
||||
{
|
||||
public class MatchDetail
|
||||
{
|
||||
public Type MatcherType { get; set; }
|
||||
|
||||
public double Score { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace WireMock.Matchers.Request
|
||||
{
|
||||
@@ -14,7 +15,7 @@ namespace WireMock.Matchers.Request
|
||||
/// <value>
|
||||
/// The match-score.
|
||||
/// </value>
|
||||
public double TotalScore { get; private set; }
|
||||
public double TotalScore => MatchDetails.Sum(md => md.Score);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the total number of matches.
|
||||
@@ -22,7 +23,7 @@ namespace WireMock.Matchers.Request
|
||||
/// <value>
|
||||
/// The total number of matches.
|
||||
/// </value>
|
||||
public int TotalNumber { get; private set; }
|
||||
public int TotalNumber => MatchDetails.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is perfect match.
|
||||
@@ -43,12 +44,7 @@ namespace WireMock.Matchers.Request
|
||||
/// <summary>
|
||||
/// Gets the match details.
|
||||
/// </summary>
|
||||
public IList<KeyValuePair<Type, double>> MatchDetails { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMatchResult"/> class.
|
||||
/// </summary>
|
||||
public RequestMatchResult() => MatchDetails = new List<KeyValuePair<Type, double>>();
|
||||
public IList<MatchDetail> MatchDetails { get; } = new List<MatchDetail>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds the score.
|
||||
@@ -58,9 +54,7 @@ namespace WireMock.Matchers.Request
|
||||
/// <returns>The score.</returns>
|
||||
public double AddScore(Type matcherType, double score)
|
||||
{
|
||||
TotalScore += score;
|
||||
TotalNumber++;
|
||||
MatchDetails.Add(new KeyValuePair<Type, double>(matcherType, score));
|
||||
MatchDetails.Add(new MatchDetail { MatcherType = matcherType, Score = score });
|
||||
|
||||
return score;
|
||||
}
|
||||
@@ -76,7 +70,10 @@ namespace WireMock.Matchers.Request
|
||||
{
|
||||
var compareObj = (RequestMatchResult)obj;
|
||||
|
||||
return compareObj.AverageTotalScore.CompareTo(AverageTotalScore);
|
||||
int averageTotalScoreResult = compareObj.AverageTotalScore.CompareTo(AverageTotalScore);
|
||||
|
||||
// In case the score is equal, prefer the one with the most matchers.
|
||||
return averageTotalScoreResult == 0 ? compareObj.TotalNumber.CompareTo(TotalNumber) : averageTotalScoreResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,17 +145,17 @@ namespace WireMock.Matchers.Request
|
||||
|
||||
if (Func != null)
|
||||
{
|
||||
return MatchScores.ToScore(requestMessage?.BodyData?.DetectedBodyType == BodyType.String && Func(requestMessage.BodyData.BodyAsString));
|
||||
return MatchScores.ToScore(Func(requestMessage?.BodyData?.BodyAsString));
|
||||
}
|
||||
|
||||
if (JsonFunc != null)
|
||||
{
|
||||
return MatchScores.ToScore(requestMessage?.BodyData?.DetectedBodyType == BodyType.Json && JsonFunc(requestMessage.BodyData.BodyAsJson));
|
||||
return MatchScores.ToScore(JsonFunc(requestMessage?.BodyData?.BodyAsJson));
|
||||
}
|
||||
|
||||
if (DataFunc != null)
|
||||
{
|
||||
return MatchScores.ToScore(requestMessage?.BodyData?.DetectedBodyType == BodyType.Bytes && DataFunc(requestMessage.BodyData.BodyAsBytes));
|
||||
return MatchScores.ToScore(DataFunc(requestMessage?.BodyData?.BodyAsBytes));
|
||||
}
|
||||
|
||||
return MatchScores.Mismatch;
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace WireMock.Owin
|
||||
PortUtils.TryExtract(url, out string protocol, out string host, out int port);
|
||||
options.Listen(System.Net.IPAddress.Any, port, listenOptions =>
|
||||
{
|
||||
listenOptions.UseHttps(PublicCertificateHelper.GetX509Certificate2());
|
||||
listenOptions.UseHttps(); // PublicCertificateHelper.GetX509Certificate2()
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.ObjectModel;
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Util;
|
||||
#if !USE_ASPNETCORE
|
||||
using Owin;
|
||||
#else
|
||||
@@ -20,13 +20,13 @@ namespace WireMock.Owin
|
||||
|
||||
IStringMatcher AuthorizationMatcher { get; set; }
|
||||
|
||||
bool AllowPartialMapping { get; set; }
|
||||
bool? AllowPartialMapping { get; set; }
|
||||
|
||||
ConcurrentDictionary<Guid, IMapping> Mappings { get; }
|
||||
|
||||
ConcurrentDictionary<string, ScenarioState> Scenarios { get; }
|
||||
|
||||
ObservableCollection<LogEntry> LogEntries { get; }
|
||||
ConcurrentObservableCollection<LogEntry> LogEntries { get; }
|
||||
|
||||
int? RequestLogExpirationDuration { get; set; }
|
||||
|
||||
@@ -37,5 +37,7 @@ namespace WireMock.Owin
|
||||
Action<IAppBuilder> PostWireMockMiddlewareInit { get; set; }
|
||||
|
||||
IFileSystemHandler FileSystemHandler { get; set; }
|
||||
|
||||
bool? AllowBodyForAllHttpMethods { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,8 @@ namespace WireMock.Owin.Mappers
|
||||
/// MapAsync IRequest to RequestMessage
|
||||
/// </summary>
|
||||
/// <param name="request">The OwinRequest/HttpRequest</param>
|
||||
/// <param name="options">The WireMockMiddlewareOptions</param>
|
||||
/// <returns>RequestMessage</returns>
|
||||
Task<RequestMessage> MapAsync(IRequest request);
|
||||
Task<RequestMessage> MapAsync(IRequest request, IWireMockMiddlewareOptions options);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ namespace WireMock.Owin.Mappers
|
||||
internal class OwinRequestMapper : IOwinRequestMapper
|
||||
{
|
||||
/// <inheritdoc cref="IOwinRequestMapper.MapAsync"/>
|
||||
public async Task<RequestMessage> MapAsync(IRequest request)
|
||||
public async Task<RequestMessage> MapAsync(IRequest request, IWireMockMiddlewareOptions options)
|
||||
{
|
||||
(UrlDetails urldetails, string clientIP) = ParseRequest(request);
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace WireMock.Owin.Mappers
|
||||
}
|
||||
|
||||
BodyData body = null;
|
||||
if (request.Body != null && BodyParser.ShouldParseBody(method))
|
||||
if (request.Body != null && BodyParser.ShouldParseBody(method, options.AllowBodyForAllHttpMethods == true))
|
||||
{
|
||||
body = await BodyParser.Parse(request.Body, request.ContentType);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,11 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using RandomDataGenerator.FieldOptions;
|
||||
using RandomDataGenerator.Randomizers;
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Http;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.Util;
|
||||
using WireMock.Validation;
|
||||
#if !USE_ASPNETCORE
|
||||
@@ -22,6 +25,8 @@ namespace WireMock.Owin.Mappers
|
||||
/// </summary>
|
||||
public class OwinResponseMapper : IOwinResponseMapper
|
||||
{
|
||||
private readonly IRandomizerNumber<double> _randomizerDouble = RandomizerFactory.GetRandomizer(new FieldOptionsDouble { Min = 0, Max = 1 });
|
||||
private readonly IRandomizerBytes _randomizerBytes = RandomizerFactory.GetRandomizer(new FieldOptionsBytes { Min = 100, Max = 200 });
|
||||
private readonly IFileSystemHandler _fileSystemHandler;
|
||||
private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
|
||||
|
||||
@@ -53,8 +58,43 @@ namespace WireMock.Owin.Mappers
|
||||
return;
|
||||
}
|
||||
|
||||
response.StatusCode = responseMessage.StatusCode;
|
||||
byte[] bytes;
|
||||
switch (responseMessage.FaultType)
|
||||
{
|
||||
case FaultType.EMPTY_RESPONSE:
|
||||
bytes = IsFault(responseMessage) ? new byte[0] : GetNormalBody(responseMessage);
|
||||
break;
|
||||
|
||||
case FaultType.MALFORMED_RESPONSE_CHUNK:
|
||||
bytes = GetNormalBody(responseMessage) ?? new byte[0];
|
||||
if (IsFault(responseMessage))
|
||||
{
|
||||
bytes = bytes.Take(bytes.Length / 2).Union(_randomizerBytes.Generate()).ToArray();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
bytes = GetNormalBody(responseMessage);
|
||||
break;
|
||||
}
|
||||
|
||||
response.StatusCode = responseMessage.StatusCode;
|
||||
SetResponseHeaders(responseMessage, response);
|
||||
|
||||
if (bytes != null)
|
||||
{
|
||||
await response.Body.WriteAsync(bytes, 0, bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsFault(ResponseMessage responseMessage)
|
||||
{
|
||||
return responseMessage.FaultPercentage == null || _randomizerDouble.Generate() <= responseMessage.FaultPercentage;
|
||||
}
|
||||
|
||||
private byte[] GetNormalBody(ResponseMessage responseMessage)
|
||||
{
|
||||
byte[] bytes = null;
|
||||
switch (responseMessage.BodyData?.DetectedBodyType)
|
||||
{
|
||||
@@ -63,7 +103,9 @@ namespace WireMock.Owin.Mappers
|
||||
break;
|
||||
|
||||
case BodyType.Json:
|
||||
Formatting formatting = responseMessage.BodyData.BodyAsJsonIndented == true ? Formatting.Indented : Formatting.None;
|
||||
Formatting formatting = responseMessage.BodyData.BodyAsJsonIndented == true
|
||||
? Formatting.Indented
|
||||
: Formatting.None;
|
||||
string jsonBody = JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson, new JsonSerializerSettings { Formatting = formatting, NullValueHandling = NullValueHandling.Ignore });
|
||||
bytes = (responseMessage.BodyData.Encoding ?? _utf8NoBom).GetBytes(jsonBody);
|
||||
break;
|
||||
@@ -77,12 +119,7 @@ namespace WireMock.Owin.Mappers
|
||||
break;
|
||||
}
|
||||
|
||||
SetResponseHeaders(responseMessage, response);
|
||||
|
||||
if (bytes != null)
|
||||
{
|
||||
await response.Body.WriteAsync(bytes, 0, bytes.Length);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private void SetResponseHeaders(ResponseMessage responseMessage, IResponse response)
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace WireMock.Owin
|
||||
}
|
||||
}
|
||||
|
||||
if (_options.AllowPartialMapping)
|
||||
if (_options.AllowPartialMapping == true)
|
||||
{
|
||||
var partialMappings = mappings
|
||||
.Where(pm => (pm.Mapping.IsAdminInterface && pm.RequestMatchResult.IsPerfectMatch) || !pm.Mapping.IsAdminInterface)
|
||||
@@ -49,8 +49,9 @@ namespace WireMock.Owin
|
||||
}
|
||||
|
||||
return mappings
|
||||
.OrderBy(m => m.Mapping.Priority)
|
||||
.FirstOrDefault(m => m.RequestMatchResult.IsPerfectMatch);
|
||||
.Where(m => m.RequestMatchResult.IsPerfectMatch)
|
||||
.OrderBy(m => m.Mapping.Priority).ThenBy(m => m.RequestMatchResult)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ namespace WireMock.Owin
|
||||
|
||||
private async Task InvokeInternal(IContext ctx)
|
||||
{
|
||||
var request = await _requestMapper.MapAsync(ctx.Request);
|
||||
var request = await _requestMapper.MapAsync(ctx.Request, _options);
|
||||
|
||||
bool logRequest = false;
|
||||
ResponseMessage response = null;
|
||||
@@ -99,7 +99,7 @@ namespace WireMock.Owin
|
||||
return;
|
||||
}
|
||||
|
||||
logRequest = !targetMapping.IsAdminInterface;
|
||||
logRequest = targetMapping.LogMapping;
|
||||
|
||||
if (targetMapping.IsAdminInterface && _options.AuthorizationMatcher != null)
|
||||
{
|
||||
@@ -162,7 +162,8 @@ namespace WireMock.Owin
|
||||
|
||||
if (_options.MaxRequestLogCount != null)
|
||||
{
|
||||
foreach (var logEntry in _options.LogEntries.OrderBy(le => le.RequestMessage.DateTime).Take(_options.LogEntries.Count - _options.MaxRequestLogCount.Value).ToList())
|
||||
var logEntries = _options.LogEntries.ToList();
|
||||
foreach (var logEntry in logEntries.OrderBy(le => le.RequestMessage.DateTime).Take(logEntries.Count - _options.MaxRequestLogCount.Value))
|
||||
{
|
||||
_options.LogEntries.Remove(logEntry);
|
||||
}
|
||||
@@ -172,7 +173,7 @@ namespace WireMock.Owin
|
||||
{
|
||||
var checkTime = DateTime.UtcNow.AddHours(-_options.RequestLogExpirationDuration.Value);
|
||||
|
||||
foreach (var logEntry in _options.LogEntries.Where(le => le.RequestMessage.DateTime < checkTime).ToList())
|
||||
foreach (var logEntry in _options.LogEntries.ToList().Where(le => le.RequestMessage.DateTime < checkTime))
|
||||
{
|
||||
_options.LogEntries.Remove(logEntry);
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@ namespace WireMock.Owin
|
||||
|
||||
public IStringMatcher AuthorizationMatcher { get; set; }
|
||||
|
||||
public bool AllowPartialMapping { get; set; }
|
||||
public bool? AllowPartialMapping { get; set; }
|
||||
|
||||
public ConcurrentDictionary<Guid, IMapping> Mappings { get; } = new ConcurrentDictionary<Guid, IMapping>();
|
||||
|
||||
public ConcurrentDictionary<string, ScenarioState> Scenarios { get; } = new ConcurrentDictionary<string, ScenarioState>();
|
||||
|
||||
public ObservableCollection<LogEntry> LogEntries { get; } = new ConcurrentObservableCollection<LogEntry>();
|
||||
public ConcurrentObservableCollection<LogEntry> LogEntries { get; } = new ConcurrentObservableCollection<LogEntry>();
|
||||
|
||||
public int? RequestLogExpirationDuration { get; set; }
|
||||
|
||||
@@ -39,5 +39,8 @@ namespace WireMock.Owin
|
||||
|
||||
/// <inheritdoc cref="IWireMockMiddlewareOptions.FileSystemHandler"/>
|
||||
public IFileSystemHandler FileSystemHandler { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IWireMockMiddlewareOptions.AllowBodyForAllHttpMethods"/>
|
||||
public bool? AllowBodyForAllHttpMethods { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.RequestBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The BodyRequestBuilder interface.
|
||||
/// </summary>
|
||||
public interface IBodyRequestBuilder
|
||||
public interface IBodyRequestBuilder : IRequestMatcher
|
||||
{
|
||||
/// <summary>
|
||||
/// WithBody: IMatcher
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.RequestBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The HeadersAndCookieRequestBuilder interface.
|
||||
/// </summary>
|
||||
public interface IHeadersAndCookiesRequestBuilder : IBodyRequestBuilder, IRequestMatcher, IParamsRequestBuilder
|
||||
public interface IHeadersAndCookiesRequestBuilder : IParamsRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// WithHeader: matching based on name, pattern and matchBehaviour.
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace WireMock.RequestBuilders
|
||||
/// <summary>
|
||||
/// The ParamsRequestBuilder interface.
|
||||
/// </summary>
|
||||
public interface IParamsRequestBuilder
|
||||
public interface IParamsRequestBuilder : IBodyRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// WithParam: matching on key only.
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace WireMock.RequestBuilders
|
||||
/// <returns>A List{T}</returns>
|
||||
public IList<T> GetRequestMessageMatchers<T>() where T : IRequestMatcher
|
||||
{
|
||||
return new ReadOnlyCollection<T>(_requestMatchers.Where(rm => rm is T).Cast<T>().ToList());
|
||||
return new ReadOnlyCollection<T>(_requestMatchers.OfType<T>().ToList());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -50,7 +50,7 @@ namespace WireMock.RequestBuilders
|
||||
/// <returns>A RequestMatcher</returns>
|
||||
public T GetRequestMessageMatcher<T>() where T : IRequestMatcher
|
||||
{
|
||||
return _requestMatchers.Where(rm => rm is T).Cast<T>().FirstOrDefault();
|
||||
return _requestMatchers.OfType<T>().FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IClientIPRequestBuilder.WithClientIP(IStringMatcher[])"/>
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace WireMock
|
||||
|
||||
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
|
||||
Cookies = cookies;
|
||||
RawQuery = WebUtility.UrlDecode(urlDetails.Url.Query);
|
||||
RawQuery = urlDetails.Url.Query;
|
||||
Query = QueryStringParser.Parse(RawQuery);
|
||||
}
|
||||
|
||||
|
||||
23
src/WireMock.Net/ResponseBuilders/FaultType.cs
Normal file
23
src/WireMock.Net/ResponseBuilders/FaultType.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace WireMock.ResponseBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The FaultType enumeration
|
||||
/// </summary>
|
||||
public enum FaultType
|
||||
{
|
||||
/// <summary>
|
||||
/// No Fault
|
||||
/// </summary>
|
||||
NONE,
|
||||
|
||||
/// <summary>
|
||||
/// Return a completely empty response.
|
||||
/// </summary>
|
||||
EMPTY_RESPONSE,
|
||||
|
||||
/// <summary>
|
||||
/// Send a defined status header, then garbage, then close the connection.
|
||||
/// </summary>
|
||||
MALFORMED_RESPONSE_CHUNK
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace WireMock.ResponseBuilders
|
||||
/// <summary>
|
||||
/// The BodyResponseBuilder interface.
|
||||
/// </summary>
|
||||
public interface IBodyResponseBuilder : ITransformResponseBuilder
|
||||
public interface IBodyResponseBuilder : IFaultResponseBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// WithBody : Create a ... response based on a string.
|
||||
|
||||
18
src/WireMock.Net/ResponseBuilders/IFaultRequestBuilder.cs
Normal file
18
src/WireMock.Net/ResponseBuilders/IFaultRequestBuilder.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace WireMock.ResponseBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The FaultRequestBuilder interface.
|
||||
/// </summary>
|
||||
public interface IFaultResponseBuilder : ITransformResponseBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// WithBody : Create a fault response.
|
||||
/// </summary>
|
||||
/// <param name="faultType">The FaultType.</param>
|
||||
/// <param name="percentage">The percentage when this fault should occur. When null, it's always a fault.</param>
|
||||
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
|
||||
IResponseBuilder WithFault(FaultType faultType, [CanBeNull] double? percentage = null);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,6 @@
|
||||
/// <returns>
|
||||
/// The <see cref="IResponseBuilder"/>.
|
||||
/// </returns>
|
||||
IResponseBuilder WithTransformer();
|
||||
IResponseBuilder WithTransformer(bool transformContentFromBodyAsFile = false);
|
||||
}
|
||||
}
|
||||
14
src/WireMock.Net/ResponseBuilders/Response.WithFault.cs
Normal file
14
src/WireMock.Net/ResponseBuilders/Response.WithFault.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace WireMock.ResponseBuilders
|
||||
{
|
||||
public partial class Response
|
||||
{
|
||||
/// <inheritdoc cref="IFaultResponseBuilder.WithFault(FaultType, double?)"/>
|
||||
public IResponseBuilder WithFault(FaultType faultType, double? percentage = null)
|
||||
{
|
||||
ResponseMessage.FaultType = faultType;
|
||||
ResponseMessage.FaultPercentage = percentage;
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/WireMock.Net/ResponseBuilders/Response.WithProxy.cs
Normal file
48
src/WireMock.Net/ResponseBuilders/Response.WithProxy.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Net.Http;
|
||||
using WireMock.Http;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.ResponseBuilders
|
||||
{
|
||||
public partial class Response
|
||||
{
|
||||
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; }
|
||||
|
||||
/// <inheritdoc cref="IProxyResponseBuilder.WithProxy(string, string)"/>
|
||||
public IResponseBuilder WithProxy(string proxyUrl, string clientX509Certificate2ThumbprintOrSubjectName = null)
|
||||
{
|
||||
Check.NotNullOrEmpty(proxyUrl, nameof(proxyUrl));
|
||||
|
||||
var settings = new ProxyAndRecordSettings
|
||||
{
|
||||
Url = proxyUrl,
|
||||
ClientX509Certificate2ThumbprintOrSubjectName = clientX509Certificate2ThumbprintOrSubjectName
|
||||
};
|
||||
|
||||
return WithProxy(settings);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IProxyResponseBuilder.WithProxy(IProxyAndRecordSettings)"/>
|
||||
public IResponseBuilder WithProxy(IProxyAndRecordSettings settings)
|
||||
{
|
||||
Check.NotNull(settings, nameof(settings));
|
||||
|
||||
ProxyUrl = settings.Url;
|
||||
WebProxySettings = settings.WebProxySettings;
|
||||
|
||||
_httpClientForProxy = HttpClientHelper.CreateHttpClient(settings);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,10 +19,8 @@ namespace WireMock.ResponseBuilders
|
||||
/// <summary>
|
||||
/// The Response.
|
||||
/// </summary>
|
||||
public class Response : IResponseBuilder
|
||||
public partial class Response : IResponseBuilder
|
||||
{
|
||||
private HttpClient _httpClientForProxy;
|
||||
|
||||
/// <summary>
|
||||
/// The delay
|
||||
/// </summary>
|
||||
@@ -34,14 +32,9 @@ namespace WireMock.ResponseBuilders
|
||||
public bool UseTransformer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Proxy URL to use.
|
||||
/// Gets a value indicating whether to use the Handlerbars transformer for the content from the referenced BodyAsFile.
|
||||
/// </summary>
|
||||
public string ProxyUrl { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The client X509Certificate2 Thumbprint or SubjectName to use.
|
||||
/// </summary>
|
||||
public string ClientX509Certificate2ThumbprintOrSubjectName { get; private set; }
|
||||
public bool UseTransformerForBodyAsFile { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the response message.
|
||||
@@ -311,10 +304,11 @@ namespace WireMock.ResponseBuilders
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ITransformResponseBuilder.WithTransformer"/>
|
||||
public IResponseBuilder WithTransformer()
|
||||
/// <inheritdoc cref="ITransformResponseBuilder.WithTransformer(bool)"/>
|
||||
public IResponseBuilder WithTransformer(bool transformContentFromBodyAsFile = false)
|
||||
{
|
||||
UseTransformer = true;
|
||||
UseTransformerForBodyAsFile = transformContentFromBodyAsFile;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -333,25 +327,6 @@ namespace WireMock.ResponseBuilders
|
||||
return WithDelay(TimeSpan.FromMilliseconds(milliseconds));
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IProxyResponseBuilder.WithProxy(string, string)"/>
|
||||
public IResponseBuilder WithProxy(string proxyUrl, string clientX509Certificate2ThumbprintOrSubjectName = null)
|
||||
{
|
||||
Check.NotNullOrEmpty(proxyUrl, nameof(proxyUrl));
|
||||
|
||||
ProxyUrl = proxyUrl;
|
||||
ClientX509Certificate2ThumbprintOrSubjectName = clientX509Certificate2ThumbprintOrSubjectName;
|
||||
_httpClientForProxy = HttpClientHelper.CreateHttpClient(clientX509Certificate2ThumbprintOrSubjectName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IProxyResponseBuilder.WithProxy(IProxyAndRecordSettings)"/>
|
||||
public IResponseBuilder WithProxy(IProxyAndRecordSettings settings)
|
||||
{
|
||||
Check.NotNull(settings, nameof(settings));
|
||||
|
||||
return WithProxy(settings.Url, settings.ClientX509Certificate2ThumbprintOrSubjectName);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ICallbackResponseBuilder.WithCallback"/>
|
||||
public IResponseBuilder WithCallback(Func<RequestMessage, ResponseMessage> callbackHandler)
|
||||
{
|
||||
@@ -375,6 +350,7 @@ namespace WireMock.ResponseBuilders
|
||||
public async Task<ResponseMessage> ProvideResponseAsync(RequestMessage requestMessage, IFluentMockServerSettings settings)
|
||||
{
|
||||
Check.NotNull(requestMessage, nameof(requestMessage));
|
||||
Check.NotNull(settings, nameof(settings));
|
||||
|
||||
if (Delay != null)
|
||||
{
|
||||
@@ -413,7 +389,7 @@ namespace WireMock.ResponseBuilders
|
||||
{
|
||||
var factory = new HandlebarsContextFactory(settings.FileSystemHandler, settings.HandlebarsRegistrationCallback);
|
||||
var responseMessageTransformer = new ResponseMessageTransformer(factory);
|
||||
return responseMessageTransformer.Transform(requestMessage, ResponseMessage);
|
||||
return responseMessageTransformer.Transform(requestMessage, ResponseMessage, UseTransformerForBodyAsFile);
|
||||
}
|
||||
|
||||
if (!UseTransformer && ResponseMessage.BodyData?.BodyAsFileIsCached == true)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.Util;
|
||||
using WireMock.Validation;
|
||||
|
||||
@@ -35,6 +36,16 @@ namespace WireMock
|
||||
/// </summary>
|
||||
public BodyData BodyData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The FaultType.
|
||||
/// </summary>
|
||||
public FaultType FaultType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Fault percentage.
|
||||
/// </summary>
|
||||
public double? FaultPercentage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds the header.
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using WireMock.Admin.Mappings;
|
||||
using WireMock.Admin.Requests;
|
||||
using WireMock.Logging;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Serialization
|
||||
@@ -61,6 +62,12 @@ namespace WireMock.Serialization
|
||||
Headers = logEntry.ResponseMessage.Headers
|
||||
};
|
||||
|
||||
if (logEntry.ResponseMessage.FaultType != FaultType.NONE)
|
||||
{
|
||||
logResponseModel.FaultType = logEntry.ResponseMessage.FaultType.ToString();
|
||||
logResponseModel.FaultPercentage = logEntry.ResponseMessage.FaultPercentage;
|
||||
}
|
||||
|
||||
if (logEntry.ResponseMessage.BodyData != null)
|
||||
{
|
||||
logResponseModel.BodyOriginal = logEntry.ResponseMessage.BodyOriginal;
|
||||
@@ -108,14 +115,14 @@ namespace WireMock.Serialization
|
||||
Response = logResponseModel,
|
||||
RequestMatchResult = logEntry.RequestMatchResult != null ? new LogRequestMatchModel
|
||||
{
|
||||
IsPerfectMatch = logEntry.RequestMatchResult.IsPerfectMatch,
|
||||
TotalScore = logEntry.RequestMatchResult.TotalScore,
|
||||
TotalNumber = logEntry.RequestMatchResult.TotalNumber,
|
||||
IsPerfectMatch = logEntry.RequestMatchResult.IsPerfectMatch,
|
||||
AverageTotalScore = logEntry.RequestMatchResult.AverageTotalScore,
|
||||
MatchDetails = logEntry.RequestMatchResult.MatchDetails.Select(x => new
|
||||
MatchDetails = logEntry.RequestMatchResult.MatchDetails.Select(md => new
|
||||
{
|
||||
Name = x.Key.Name.Replace("RequestMessage", string.Empty),
|
||||
Score = x.Value
|
||||
Name = md.MatcherType.Name.Replace("RequestMessage", string.Empty),
|
||||
Score = md.Score
|
||||
} as object).ToList()
|
||||
} : null
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ using WireMock.Admin.Mappings;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.RequestBuilders;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Util;
|
||||
using WireMock.Validation;
|
||||
|
||||
@@ -112,18 +113,26 @@ namespace WireMock.Serialization
|
||||
mappingModel.Response.BodyAsFile = null;
|
||||
mappingModel.Response.BodyAsFileIsCached = null;
|
||||
mappingModel.Response.UseTransformer = null;
|
||||
mappingModel.Response.UseTransformerForBodyAsFile = null;
|
||||
mappingModel.Response.BodyEncoding = null;
|
||||
mappingModel.Response.ProxyUrl = response.ProxyUrl;
|
||||
mappingModel.Response.Fault = null;
|
||||
mappingModel.Response.WebProxy = MapWebProxy(response.WebProxySettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
mappingModel.Response.WebProxy = null;
|
||||
mappingModel.Response.BodyDestination = response.ResponseMessage.BodyDestination;
|
||||
mappingModel.Response.StatusCode = response.ResponseMessage.StatusCode;
|
||||
mappingModel.Response.Headers = Map(response.ResponseMessage.Headers);
|
||||
mappingModel.Response.Headers = MapHeaders(response.ResponseMessage.Headers);
|
||||
if (response.UseTransformer)
|
||||
{
|
||||
mappingModel.Response.UseTransformer = response.UseTransformer;
|
||||
}
|
||||
if (response.UseTransformerForBodyAsFile)
|
||||
{
|
||||
mappingModel.Response.UseTransformerForBodyAsFile = response.UseTransformerForBodyAsFile;
|
||||
}
|
||||
|
||||
if (response.ResponseMessage.BodyData != null)
|
||||
{
|
||||
@@ -161,19 +170,39 @@ namespace WireMock.Serialization
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (response.ResponseMessage.FaultType != FaultType.NONE)
|
||||
{
|
||||
mappingModel.Response.Fault = new FaultModel
|
||||
{
|
||||
Type = response.ResponseMessage.FaultType.ToString(),
|
||||
Percentage = response.ResponseMessage.FaultPercentage
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return mappingModel;
|
||||
}
|
||||
|
||||
private static IDictionary<string, object> Map(IDictionary<string, WireMockList<string>> dictionary)
|
||||
private static WebProxyModel MapWebProxy(IWebProxySettings settings)
|
||||
{
|
||||
return settings != null ? new WebProxyModel
|
||||
{
|
||||
Address = settings.Address,
|
||||
UserName = settings.UserName,
|
||||
Password = settings.Password
|
||||
} : null;
|
||||
}
|
||||
|
||||
private static IDictionary<string, object> MapHeaders(IDictionary<string, WireMockList<string>> dictionary)
|
||||
{
|
||||
var newDictionary = new Dictionary<string, object>();
|
||||
|
||||
if (dictionary == null || dictionary.Count == 0)
|
||||
{
|
||||
return null;
|
||||
return newDictionary;
|
||||
}
|
||||
|
||||
var newDictionary = new Dictionary<string, object>();
|
||||
foreach (var entry in dictionary)
|
||||
{
|
||||
object value = entry.Value.Count == 1 ? (object)entry.Value.ToString() : entry.Value;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using JetBrains.Annotations;
|
||||
using SimMetrics.Net;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using SimMetrics.Net;
|
||||
using WireMock.Admin.Mappings;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Settings;
|
||||
@@ -36,11 +36,19 @@ 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.OfType<string>().ToArray() : new[] { matcher.Pattern as string };
|
||||
MatchBehaviour matchBehaviour = matcher.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch;
|
||||
|
||||
switch (matcherName)
|
||||
{
|
||||
case "CSharpCodeMatcher":
|
||||
if (_settings.AllowCSharpCodeMatcher == true)
|
||||
{
|
||||
return new CSharpCodeMatcher(matchBehaviour, stringPatterns);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("It's not allowed to use the 'CSharpCodeMatcher' because FluentMockServerSettings.AllowCSharpCodeMatcher is not set to 'true'.");
|
||||
|
||||
case "LinqMatcher":
|
||||
return new LinqMatcher(matchBehaviour, stringPatterns);
|
||||
|
||||
@@ -48,8 +56,7 @@ namespace WireMock.Serialization
|
||||
return new ExactMatcher(matchBehaviour, stringPatterns);
|
||||
|
||||
case "ExactObjectMatcher":
|
||||
var bytePattern = Convert.FromBase64String(stringPatterns[0]);
|
||||
return new ExactObjectMatcher(matchBehaviour, bytePattern);
|
||||
return CreateExactObjectMatcher(matchBehaviour, stringPatterns[0]);
|
||||
|
||||
case "RegexMatcher":
|
||||
return new RegexMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true);
|
||||
@@ -64,11 +71,14 @@ namespace WireMock.Serialization
|
||||
return new JmesPathMatcher(matchBehaviour, stringPatterns);
|
||||
|
||||
case "XPathMatcher":
|
||||
return new XPathMatcher(matchBehaviour, (string)matcher.Pattern);
|
||||
return new XPathMatcher(matchBehaviour, stringPatterns);
|
||||
|
||||
case "WildcardMatcher":
|
||||
return new WildcardMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true);
|
||||
|
||||
case "ContentTypeMatcher":
|
||||
return new ContentTypeMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true);
|
||||
|
||||
case "SimMetricsMatcher":
|
||||
SimMetricType type = SimMetricType.Levenstein;
|
||||
if (!string.IsNullOrEmpty(matcherType) && !Enum.TryParse(matcherType, out type))
|
||||
@@ -76,13 +86,28 @@ 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, stringPatterns, type);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"Matcher '{matcherName}' is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
private ExactObjectMatcher CreateExactObjectMatcher(MatchBehaviour matchBehaviour, string stringPattern)
|
||||
{
|
||||
byte[] bytePattern;
|
||||
try
|
||||
{
|
||||
bytePattern = Convert.FromBase64String(stringPattern);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new ArgumentException($"Matcher 'ExactObjectMatcher' has invalid pattern. The pattern value '{stringPattern}' is not a Base64String.", nameof(stringPattern));
|
||||
}
|
||||
|
||||
return new ExactObjectMatcher(matchBehaviour, bytePattern);
|
||||
}
|
||||
|
||||
public MatcherModel[] Map([CanBeNull] IEnumerable<IMatcher> matchers)
|
||||
{
|
||||
return matchers?.Select(Map).Where(m => m != null).ToArray();
|
||||
|
||||
@@ -39,9 +39,11 @@ namespace WireMock.Server
|
||||
private const string AdminRequests = "/__admin/requests";
|
||||
private const string AdminSettings = "/__admin/settings";
|
||||
private const string AdminScenarios = "/__admin/scenarios";
|
||||
private const string QueryParamReloadStaticMappings = "reloadStaticMappings";
|
||||
|
||||
private readonly RegexMatcher _adminMappingsGuidPathMatcher = new RegexMatcher(MatchBehaviour.AcceptOnMatch, @"^\/__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(MatchBehaviour.AcceptOnMatch, @"^\/__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 RegexMatcher _adminRequestContentTypeJson = new ContentTypeMatcher(ContentTypeJson, true);
|
||||
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
|
||||
{
|
||||
@@ -60,19 +62,19 @@ namespace WireMock.Server
|
||||
{
|
||||
// __admin/settings
|
||||
Given(Request.Create().WithPath(AdminSettings).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(SettingsGet));
|
||||
Given(Request.Create().WithPath(AdminSettings).UsingMethod("PUT", "POST").WithHeader(HttpKnownHeaderNames.ContentType, ContentTypeJson)).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(SettingsUpdate));
|
||||
Given(Request.Create().WithPath(AdminSettings).UsingMethod("PUT", "POST").WithHeader(HttpKnownHeaderNames.ContentType, _adminRequestContentTypeJson)).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(SettingsUpdate));
|
||||
|
||||
// __admin/mappings
|
||||
Given(Request.Create().WithPath(AdminMappings).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsGet));
|
||||
Given(Request.Create().WithPath(AdminMappings).UsingPost().WithHeader(HttpKnownHeaderNames.ContentType, ContentTypeJson)).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsPost));
|
||||
Given(Request.Create().WithPath(AdminMappings).UsingPost().WithHeader(HttpKnownHeaderNames.ContentType, _adminRequestContentTypeJson)).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsPost));
|
||||
Given(Request.Create().WithPath(AdminMappings).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsDelete));
|
||||
|
||||
// __admin/mappings/reset
|
||||
Given(Request.Create().WithPath(AdminMappings + "/reset").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsDelete));
|
||||
Given(Request.Create().WithPath(AdminMappings + "/reset").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsReset));
|
||||
|
||||
// __admin/mappings/{guid}
|
||||
Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingGet));
|
||||
Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingPut().WithHeader(HttpKnownHeaderNames.ContentType, ContentTypeJson)).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingPut));
|
||||
Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingPut().WithHeader(HttpKnownHeaderNames.ContentType, _adminRequestContentTypeJson)).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingPut));
|
||||
Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingDelete));
|
||||
|
||||
// __admin/mappings/save
|
||||
@@ -140,7 +142,7 @@ namespace WireMock.Server
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string filename in _settings.FileSystemHandler.EnumerateFiles(folder).OrderBy(f => f))
|
||||
foreach (string filename in _settings.FileSystemHandler.EnumerateFiles(folder, _settings.WatchStaticMappingsInSubdirectories == true).OrderBy(f => f))
|
||||
{
|
||||
_settings.Logger.Info("Reading Static MappingFile : '{0}'", filename);
|
||||
|
||||
@@ -172,9 +174,14 @@ namespace WireMock.Server
|
||||
return;
|
||||
}
|
||||
|
||||
_settings.Logger.Info("Watching folder '{0}' for new, updated and deleted MappingFiles.", folder);
|
||||
bool includeSubdirectories = _settings.WatchStaticMappingsInSubdirectories == true;
|
||||
string includeSubdirectoriesText = includeSubdirectories ? " and Subdirectories" : string.Empty;
|
||||
|
||||
_settings.Logger.Info($"Watching folder '{folder}'{includeSubdirectoriesText} for new, updated and deleted MappingFiles.");
|
||||
|
||||
var watcher = new EnhancedFileSystemWatcher(folder, "*.json", EnhancedFileSystemWatcherTimeoutMs);
|
||||
watcher.IncludeSubdirectories = includeSubdirectories;
|
||||
|
||||
watcher.Created += (sender, args) =>
|
||||
{
|
||||
_settings.Logger.Info("MappingFile created : '{0}', reading file.", args.FullPath);
|
||||
@@ -247,7 +254,7 @@ namespace WireMock.Server
|
||||
|
||||
private void InitProxyAndRecord(IFluentMockServerSettings settings)
|
||||
{
|
||||
_httpClientForProxy = HttpClientHelper.CreateHttpClient(settings.ProxyAndRecordSettings.ClientX509Certificate2ThumbprintOrSubjectName);
|
||||
_httpClientForProxy = HttpClientHelper.CreateHttpClient(settings.ProxyAndRecordSettings);
|
||||
|
||||
var respondProvider = Given(Request.Create().WithPath("/*").UsingAnyMethod());
|
||||
if (settings.StartAdminInterface == true)
|
||||
@@ -266,7 +273,8 @@ namespace WireMock.Server
|
||||
|
||||
var responseMessage = await HttpClientHelper.SendAsync(_httpClientForProxy, requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri);
|
||||
|
||||
if (settings.ProxyAndRecordSettings.SaveMapping || settings.ProxyAndRecordSettings.SaveMappingToFile)
|
||||
if (HttpStatusRangeParser.IsMatch(settings.ProxyAndRecordSettings.SaveMappingForStatusCodePattern, responseMessage.StatusCode) &&
|
||||
(settings.ProxyAndRecordSettings.SaveMapping || settings.ProxyAndRecordSettings.SaveMappingToFile))
|
||||
{
|
||||
var mapping = ToMapping(requestMessage, responseMessage, settings.ProxyAndRecordSettings.BlackListedHeaders ?? new string[] { }, settings.ProxyAndRecordSettings.BlackListedCookies ?? new string[] { });
|
||||
|
||||
@@ -337,7 +345,8 @@ namespace WireMock.Server
|
||||
AllowPartialMapping = _options.AllowPartialMapping,
|
||||
MaxRequestLogCount = _options.MaxRequestLogCount,
|
||||
RequestLogExpirationDuration = _options.RequestLogExpirationDuration,
|
||||
GlobalProcessingDelay = (int?)_options.RequestProcessingDelay?.TotalMilliseconds
|
||||
GlobalProcessingDelay = (int?)_options.RequestProcessingDelay?.TotalMilliseconds,
|
||||
AllowBodyForAllHttpMethods = _options.AllowBodyForAllHttpMethods
|
||||
};
|
||||
|
||||
return ToJson(model);
|
||||
@@ -359,6 +368,11 @@ namespace WireMock.Server
|
||||
_options.RequestProcessingDelay = TimeSpan.FromMilliseconds(settings.GlobalProcessingDelay.Value);
|
||||
}
|
||||
|
||||
if (settings.AllowBodyForAllHttpMethods != null)
|
||||
{
|
||||
_options.AllowBodyForAllHttpMethods = settings.AllowBodyForAllHttpMethods.Value;
|
||||
}
|
||||
|
||||
return ResponseMessageBuilder.Create("Settings updated");
|
||||
}
|
||||
#endregion Settings
|
||||
@@ -543,6 +557,24 @@ namespace WireMock.Server
|
||||
|
||||
return ResponseMessageBuilder.Create("Mappings deleted");
|
||||
}
|
||||
|
||||
private ResponseMessage MappingsReset(RequestMessage requestMessage)
|
||||
{
|
||||
ResetMappings();
|
||||
|
||||
ResetScenarios();
|
||||
|
||||
string message = "Mappings reset";
|
||||
if (requestMessage.Query.ContainsKey(QueryParamReloadStaticMappings) &&
|
||||
bool.TryParse(requestMessage.Query[QueryParamReloadStaticMappings].ToString(), out bool reloadStaticMappings)
|
||||
&& reloadStaticMappings)
|
||||
{
|
||||
ReadStaticMappings();
|
||||
message = $"{message} and static mappings reloaded";
|
||||
}
|
||||
|
||||
return ResponseMessageBuilder.Create(message);
|
||||
}
|
||||
#endregion Mappings
|
||||
|
||||
#region Request/{guid}
|
||||
@@ -653,7 +685,7 @@ namespace WireMock.Server
|
||||
var clientIPModel = JsonUtils.ParseJTokenToObject<ClientIPModel>(requestModel.ClientIP);
|
||||
if (clientIPModel?.Matchers != null)
|
||||
{
|
||||
requestBuilder = requestBuilder.WithPath(clientIPModel.Matchers.Select(_matcherMapper.Map).Cast<IStringMatcher>().ToArray());
|
||||
requestBuilder = requestBuilder.WithPath(clientIPModel.Matchers.Select(_matcherMapper.Map).OfType<IStringMatcher>().ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -671,7 +703,7 @@ namespace WireMock.Server
|
||||
var pathModel = JsonUtils.ParseJTokenToObject<PathModel>(requestModel.Path);
|
||||
if (pathModel?.Matchers != null)
|
||||
{
|
||||
requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(_matcherMapper.Map).Cast<IStringMatcher>().ToArray());
|
||||
requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(_matcherMapper.Map).OfType<IStringMatcher>().ToArray());
|
||||
pathOrUrlmatchersValid = true;
|
||||
}
|
||||
}
|
||||
@@ -688,7 +720,7 @@ namespace WireMock.Server
|
||||
var urlModel = JsonUtils.ParseJTokenToObject<UrlModel>(requestModel.Url);
|
||||
if (urlModel?.Matchers != null)
|
||||
{
|
||||
requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(_matcherMapper.Map).Cast<IStringMatcher>().ToArray());
|
||||
requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(_matcherMapper.Map).OfType<IStringMatcher>().ToArray());
|
||||
pathOrUrlmatchersValid = true;
|
||||
}
|
||||
}
|
||||
@@ -709,7 +741,7 @@ namespace WireMock.Server
|
||||
{
|
||||
foreach (var headerModel in requestModel.Headers.Where(h => h.Matchers != null))
|
||||
{
|
||||
requestBuilder = requestBuilder.WithHeader(headerModel.Name, headerModel.Matchers.Select(_matcherMapper.Map).Cast<IStringMatcher>().ToArray());
|
||||
requestBuilder = requestBuilder.WithHeader(headerModel.Name, headerModel.Matchers.Select(_matcherMapper.Map).OfType<IStringMatcher>().ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -717,7 +749,7 @@ namespace WireMock.Server
|
||||
{
|
||||
foreach (var cookieModel in requestModel.Cookies.Where(c => c.Matchers != null))
|
||||
{
|
||||
requestBuilder = requestBuilder.WithCookie(cookieModel.Name, cookieModel.Matchers.Select(_matcherMapper.Map).Cast<IStringMatcher>().ToArray());
|
||||
requestBuilder = requestBuilder.WithCookie(cookieModel.Name, cookieModel.Matchers.Select(_matcherMapper.Map).OfType<IStringMatcher>().ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -726,7 +758,7 @@ namespace WireMock.Server
|
||||
foreach (var paramModel in requestModel.Params.Where(c => c.Matchers != null))
|
||||
{
|
||||
bool ignoreCase = paramModel?.IgnoreCase ?? false;
|
||||
requestBuilder = requestBuilder.WithParam(paramModel.Name, ignoreCase, paramModel.Matchers.Select(_matcherMapper.Map).Cast<IStringMatcher>().ToArray());
|
||||
requestBuilder = requestBuilder.WithParam(paramModel.Name, ignoreCase, paramModel.Matchers.Select(_matcherMapper.Map).OfType<IStringMatcher>().ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,17 +785,24 @@ namespace WireMock.Server
|
||||
|
||||
if (responseModel.UseTransformer == true)
|
||||
{
|
||||
responseBuilder = responseBuilder.WithTransformer();
|
||||
responseBuilder = responseBuilder.WithTransformer(responseModel.UseTransformerForBodyAsFile == true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(responseModel.ProxyUrl))
|
||||
{
|
||||
if (string.IsNullOrEmpty(responseModel.X509Certificate2ThumbprintOrSubjectName))
|
||||
var proxyAndRecordSettings = new ProxyAndRecordSettings
|
||||
{
|
||||
return responseBuilder.WithProxy(responseModel.ProxyUrl);
|
||||
}
|
||||
Url = responseModel.ProxyUrl,
|
||||
ClientX509Certificate2ThumbprintOrSubjectName = responseModel.X509Certificate2ThumbprintOrSubjectName,
|
||||
WebProxySettings = responseModel.WebProxy != null ? new WebProxySettings
|
||||
{
|
||||
Address = responseModel.WebProxy.Address,
|
||||
UserName = responseModel.WebProxy.UserName,
|
||||
Password = responseModel.WebProxy.Password
|
||||
} : null
|
||||
};
|
||||
|
||||
return responseBuilder.WithProxy(responseModel.ProxyUrl, responseModel.X509Certificate2ThumbprintOrSubjectName);
|
||||
return responseBuilder.WithProxy(proxyAndRecordSettings);
|
||||
}
|
||||
|
||||
if (responseModel.StatusCode.HasValue)
|
||||
@@ -812,6 +851,11 @@ namespace WireMock.Server
|
||||
responseBuilder = responseBuilder.WithBodyFromFile(responseModel.BodyAsFile);
|
||||
}
|
||||
|
||||
if (responseModel.Fault != null && Enum.TryParse(responseModel.Fault.Type, out FaultType faultType))
|
||||
{
|
||||
responseBuilder.WithFault(faultType, responseModel.Fault.Percentage);
|
||||
}
|
||||
|
||||
return responseBuilder;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Matchers.Request;
|
||||
using System.Linq;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.Server
|
||||
{
|
||||
@@ -19,7 +19,21 @@ namespace WireMock.Server
|
||||
[PublicAPI]
|
||||
public event NotifyCollectionChangedEventHandler LogEntriesChanged
|
||||
{
|
||||
add => _options.LogEntries.CollectionChanged += value;
|
||||
add
|
||||
{
|
||||
_options.LogEntries.CollectionChanged += (sender, eventRecordArgs) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
value(sender, eventRecordArgs);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_options.Logger.Error("Error calling the LogEntriesChanged event handler: {0}", exception.Message);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
remove => _options.LogEntries.CollectionChanged -= value;
|
||||
}
|
||||
|
||||
@@ -27,7 +41,7 @@ namespace WireMock.Server
|
||||
/// Gets the request logs.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public IEnumerable<LogEntry> LogEntries => new ReadOnlyCollection<LogEntry>(_options.LogEntries.ToArray());
|
||||
public IEnumerable<LogEntry> LogEntries => new ReadOnlyCollection<LogEntry>(_options.LogEntries.ToList());
|
||||
|
||||
/// <summary>
|
||||
/// The search log-entries based on matchers.
|
||||
@@ -73,7 +87,7 @@ namespace WireMock.Server
|
||||
public bool DeleteLogEntry(Guid guid)
|
||||
{
|
||||
// Check a logentry exists with the same GUID, if so, remove it.
|
||||
var existing = _options.LogEntries.FirstOrDefault(m => m.Guid == guid);
|
||||
var existing = _options.LogEntries.ToList().FirstOrDefault(m => m.Guid == guid);
|
||||
if (existing != null)
|
||||
{
|
||||
_options.LogEntries.Remove(existing);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using WireMock.Admin.Mappings;
|
||||
using WireMock.Exceptions;
|
||||
using WireMock.Handlers;
|
||||
@@ -256,6 +256,12 @@ namespace WireMock.Server
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.AllowBodyForAllHttpMethods == true)
|
||||
{
|
||||
_options.AllowBodyForAllHttpMethods = _settings.AllowBodyForAllHttpMethods;
|
||||
_settings.Logger.Info("AllowBodyForAllHttpMethods is set to {0}", _settings.AllowBodyForAllHttpMethods == true);
|
||||
}
|
||||
|
||||
if (settings.AllowPartialMapping == true)
|
||||
{
|
||||
AllowPartialMapping();
|
||||
|
||||
@@ -61,6 +61,13 @@ namespace WireMock.Server
|
||||
/// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
|
||||
IRespondWithAProvider InScenario(string scenario);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the the scenario with an integer value.
|
||||
/// </summary>
|
||||
/// <param name="scenario">The scenario.</param>
|
||||
/// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
|
||||
IRespondWithAProvider InScenario(int scenario);
|
||||
|
||||
/// <summary>
|
||||
/// Execute this respond only in case the current state is equal to specified one.
|
||||
/// </summary>
|
||||
@@ -68,11 +75,25 @@ namespace WireMock.Server
|
||||
/// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
|
||||
IRespondWithAProvider WhenStateIs(string state);
|
||||
|
||||
/// <summary>
|
||||
/// Execute this respond only in case the current state is equal to specified one.
|
||||
/// </summary>
|
||||
/// <param name="state">Any object which identifies the current state</param>
|
||||
/// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
|
||||
IRespondWithAProvider WhenStateIs(int 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(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(int state);
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,13 @@ namespace WireMock.Server
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WhenStateIs"/>
|
||||
/// <see cref="IRespondWithAProvider.InScenario(int)"/>
|
||||
public IRespondWithAProvider InScenario(int scenario)
|
||||
{
|
||||
return InScenario(scenario.ToString());
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WhenStateIs(string)"/>
|
||||
public IRespondWithAProvider WhenStateIs(string state)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_scenario))
|
||||
@@ -106,7 +112,13 @@ namespace WireMock.Server
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WillSetStateTo"/>
|
||||
/// <see cref="IRespondWithAProvider.WhenStateIs(int)"/>
|
||||
public IRespondWithAProvider WhenStateIs(int state)
|
||||
{
|
||||
return WhenStateIs(state.ToString());
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WillSetStateTo(string)"/>
|
||||
public IRespondWithAProvider WillSetStateTo(string state)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_scenario))
|
||||
@@ -118,5 +130,11 @@ namespace WireMock.Server
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WillSetStateTo(int)"/>
|
||||
public IRespondWithAProvider WillSetStateTo(int state)
|
||||
{
|
||||
return WillSetStateTo(state.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,10 @@ namespace WireMock.Settings
|
||||
[PublicAPI]
|
||||
public bool? WatchStaticMappings { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IFluentMockServerSettings.WatchStaticMappingsInSubdirectories"/>
|
||||
[PublicAPI]
|
||||
public bool? WatchStaticMappingsInSubdirectories { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IFluentMockServerSettings.ProxyAndRecordSettings"/>
|
||||
[PublicAPI]
|
||||
public IProxyAndRecordSettings ProxyAndRecordSettings { get; set; }
|
||||
@@ -89,5 +93,13 @@ namespace WireMock.Settings
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public Action<IHandlebars, IFileSystemHandler> HandlebarsRegistrationCallback { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IFluentMockServerSettings.AllowCSharpCodeMatcher"/>
|
||||
[PublicAPI]
|
||||
public bool? AllowCSharpCodeMatcher { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IFluentMockServerSettings.AllowBodyForAllHttpMethods"/>
|
||||
[PublicAPI]
|
||||
public bool? AllowBodyForAllHttpMethods { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using HandlebarsDotNet;
|
||||
using System;
|
||||
using HandlebarsDotNet;
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Logging;
|
||||
|
||||
@@ -42,6 +42,12 @@ namespace WireMock.Settings
|
||||
[PublicAPI]
|
||||
bool? WatchStaticMappings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A value indicating whether subdirectories within the static mappings path should be monitored.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? WatchStaticMappingsInSubdirectories { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the proxy and record settings.
|
||||
/// </summary>
|
||||
@@ -115,9 +121,21 @@ namespace WireMock.Settings
|
||||
IFileSystemHandler FileSystemHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action which can be used to add additional is Handlebar registrations. [Optional]
|
||||
/// Action which can be used to add additional Handlebars registrations. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
Action<IHandlebars, IFileSystemHandler> HandlebarsRegistrationCallback { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow the usage of CSharpCodeMatcher (default is not allowed).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? AllowCSharpCodeMatcher { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow a Body for all HTTP Methods. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? AllowBodyForAllHttpMethods { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace WireMock.Settings
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace WireMock.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// IProxyAndRecordSettings
|
||||
@@ -16,7 +18,14 @@
|
||||
bool SaveMapping { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Save the mapping for each request/response to also file. (Note that SaveMapping must also be set to true.)
|
||||
/// 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.)
|
||||
/// The pattern can contain a single value like "200", but also ranges like "2xx", "100,300,600" or "100-299,6xx" are supported.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
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.)
|
||||
/// </summary>
|
||||
bool SaveMappingToFile { get; set; }
|
||||
|
||||
@@ -35,5 +44,15 @@
|
||||
/// Defines a list of cookies which will excluded from the saved mappings.
|
||||
/// </summary>
|
||||
string[] BlackListedCookies { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines the WebProxySettings.
|
||||
/// </summary>
|
||||
IWebProxySettings WebProxySettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Proxy requests should follow redirection (30x).
|
||||
/// </summary>
|
||||
bool? AllowAutoRedirect { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/WireMock.Net/Settings/IWebProxySettings.cs
Normal file
20
src/WireMock.Net/Settings/IWebProxySettings.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace WireMock.Settings
|
||||
{
|
||||
public interface IWebProxySettings
|
||||
{
|
||||
/// <summary>
|
||||
/// A string instance that contains the address of the proxy server.
|
||||
/// </summary>
|
||||
string Address { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user name associated with the credentials.
|
||||
/// </summary>
|
||||
string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The password for the user name associated with the credentials.
|
||||
/// </summary>
|
||||
string Password { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,10 @@ namespace WireMock.Settings
|
||||
[PublicAPI]
|
||||
public bool SaveMapping { get; set; } = true;
|
||||
|
||||
/// <inheritdoc cref="IProxyAndRecordSettings.SaveMappingForStatusCodePattern"/>
|
||||
[PublicAPI]
|
||||
public string SaveMappingForStatusCodePattern { get; set; } = "*";
|
||||
|
||||
/// <inheritdoc cref="IProxyAndRecordSettings.SaveMappingToFile"/>
|
||||
[PublicAPI]
|
||||
public bool SaveMappingToFile { get; set; } = true;
|
||||
@@ -30,5 +34,13 @@ namespace WireMock.Settings
|
||||
/// <inheritdoc cref="IProxyAndRecordSettings.BlackListedCookies"/>
|
||||
[PublicAPI]
|
||||
public string[] BlackListedCookies { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IProxyAndRecordSettings.WebProxySettings"/>
|
||||
[PublicAPI]
|
||||
public IWebProxySettings WebProxySettings { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IProxyAndRecordSettings.AllowAutoRedirect"/>
|
||||
[PublicAPI]
|
||||
public bool? AllowAutoRedirect { get; set; }
|
||||
}
|
||||
}
|
||||
19
src/WireMock.Net/Settings/WebProxySettings.cs
Normal file
19
src/WireMock.Net/Settings/WebProxySettings.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace WireMock.Settings
|
||||
{
|
||||
public class WebProxySettings : IWebProxySettings
|
||||
{
|
||||
/// <inheritdoc cref="IWebProxySettings.Address"/>
|
||||
[PublicAPI]
|
||||
public string Address { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IWebProxySettings.UserName"/>
|
||||
[PublicAPI]
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IWebProxySettings.Password"/>
|
||||
[PublicAPI]
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using HandlebarsDotNet;
|
||||
using HandlebarsDotNet;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using WireMock.Util;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Transformers
|
||||
@@ -13,7 +15,7 @@ namespace WireMock.Transformers
|
||||
{
|
||||
handlebarsContext.RegisterHelper("JsonPath.SelectToken", (writer, context, arguments) =>
|
||||
{
|
||||
(JObject valueToProcess, string jsonPath) = ParseArguments(arguments);
|
||||
(JToken valueToProcess, string jsonPath) = ParseArguments(arguments);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -28,7 +30,7 @@ namespace WireMock.Transformers
|
||||
|
||||
handlebarsContext.RegisterHelper("JsonPath.SelectTokens", (writer, options, context, arguments) =>
|
||||
{
|
||||
(JObject valueToProcess, string jsonPath) = ParseArguments(arguments);
|
||||
(JToken valueToProcess, string jsonPath) = ParseArguments(arguments);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -45,29 +47,33 @@ namespace WireMock.Transformers
|
||||
});
|
||||
}
|
||||
|
||||
private static (JObject valueToProcess, string jsonpath) ParseArguments(object[] arguments)
|
||||
private static (JToken valueToProcess, string jsonpath) ParseArguments(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;
|
||||
JToken valueToProcess;
|
||||
|
||||
switch (arguments[0])
|
||||
{
|
||||
case string jsonAsString:
|
||||
valueToProcess = JObject.Parse(jsonAsString);
|
||||
case JToken tokenValue:
|
||||
valueToProcess = tokenValue;
|
||||
break;
|
||||
|
||||
case JObject jsonAsJObject:
|
||||
valueToProcess = jsonAsJObject;
|
||||
case string stringValue:
|
||||
valueToProcess = JsonUtils.Parse(stringValue);
|
||||
break;
|
||||
|
||||
case IEnumerable enumerableValue:
|
||||
valueToProcess = JArray.FromObject(enumerableValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"The value '{arguments[0]}' with type '{arguments[0]?.GetType()}' cannot be used in Handlebars JsonPath.");
|
||||
}
|
||||
|
||||
return (valueToProcess, (string) arguments[1]);
|
||||
return (valueToProcess, (string)arguments[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/WireMock.Net/Transformers/HandlebarsContext.cs
Normal file
11
src/WireMock.Net/Transformers/HandlebarsContext.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using HandlebarsDotNet;
|
||||
using WireMock.Handlers;
|
||||
|
||||
namespace WireMock.Transformers
|
||||
{
|
||||
internal class HandlebarsContext : IHandlebarsContext
|
||||
{
|
||||
public IHandlebars Handlebars { get; set; }
|
||||
public IFileSystemHandler FileSystemHandler { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -20,15 +20,19 @@ namespace WireMock.Transformers
|
||||
_action = action;
|
||||
}
|
||||
|
||||
public IHandlebars Create()
|
||||
public IHandlebarsContext Create()
|
||||
{
|
||||
var handlebarsContext = Handlebars.Create(HandlebarsConfiguration);
|
||||
var handlebars = Handlebars.Create(HandlebarsConfiguration);
|
||||
|
||||
HandlebarsHelpers.Register(handlebarsContext, _fileSystemHandler);
|
||||
HandlebarsHelpers.Register(handlebars, _fileSystemHandler);
|
||||
|
||||
_action?.Invoke(handlebarsContext, _fileSystemHandler);
|
||||
_action?.Invoke(handlebars, _fileSystemHandler);
|
||||
|
||||
return handlebarsContext;
|
||||
return new HandlebarsContext
|
||||
{
|
||||
Handlebars = handlebars,
|
||||
FileSystemHandler = _fileSystemHandler
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/WireMock.Net/Transformers/IHandlebarsContext.cs
Normal file
12
src/WireMock.Net/Transformers/IHandlebarsContext.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using HandlebarsDotNet;
|
||||
using WireMock.Handlers;
|
||||
|
||||
namespace WireMock.Transformers
|
||||
{
|
||||
interface IHandlebarsContext
|
||||
{
|
||||
IHandlebars Handlebars { get; set; }
|
||||
|
||||
IFileSystemHandler FileSystemHandler { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,6 @@ namespace WireMock.Transformers
|
||||
{
|
||||
interface IHandlebarsContextFactory
|
||||
{
|
||||
IHandlebars Create();
|
||||
IHandlebarsContext Create();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using HandlebarsDotNet;
|
||||
using JetBrains.Annotations;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
@@ -21,7 +20,7 @@ namespace WireMock.Transformers
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public ResponseMessage Transform(RequestMessage requestMessage, ResponseMessage original)
|
||||
public ResponseMessage Transform(RequestMessage requestMessage, ResponseMessage original, bool useTransformerForBodyAsFile)
|
||||
{
|
||||
var handlebarsContext = _factory.Create();
|
||||
|
||||
@@ -36,7 +35,7 @@ namespace WireMock.Transformers
|
||||
break;
|
||||
|
||||
case BodyType.File:
|
||||
TransformBodyAsFile(handlebarsContext, template, original, responseMessage);
|
||||
TransformBodyAsFile(handlebarsContext, template, original, responseMessage, useTransformerForBodyAsFile);
|
||||
break;
|
||||
|
||||
case BodyType.String:
|
||||
@@ -45,13 +44,16 @@ namespace WireMock.Transformers
|
||||
break;
|
||||
}
|
||||
|
||||
responseMessage.FaultType = original.FaultType;
|
||||
responseMessage.FaultPercentage = original.FaultPercentage;
|
||||
|
||||
// Headers
|
||||
var newHeaders = new Dictionary<string, WireMockList<string>>();
|
||||
foreach (var header in original.Headers)
|
||||
{
|
||||
var templateHeaderKey = handlebarsContext.Compile(header.Key);
|
||||
var templateHeaderKey = handlebarsContext.Handlebars.Compile(header.Key);
|
||||
var templateHeaderValues = header.Value
|
||||
.Select(handlebarsContext.Compile)
|
||||
.Select(handlebarsContext.Handlebars.Compile)
|
||||
.Select(func => func(template))
|
||||
.ToArray();
|
||||
|
||||
@@ -63,7 +65,7 @@ namespace WireMock.Transformers
|
||||
return responseMessage;
|
||||
}
|
||||
|
||||
private static void TransformBodyAsJson(IHandlebars handlebarsContext, object template, ResponseMessage original, ResponseMessage responseMessage)
|
||||
private static void TransformBodyAsJson(IHandlebarsContext handlebarsContext, object template, ResponseMessage original, ResponseMessage responseMessage)
|
||||
{
|
||||
JToken jToken;
|
||||
switch (original.BodyData.BodyAsJson)
|
||||
@@ -91,7 +93,7 @@ namespace WireMock.Transformers
|
||||
};
|
||||
}
|
||||
|
||||
private static void WalkNode(IHandlebars handlebarsContext, JToken node, object context)
|
||||
private static void WalkNode(IHandlebarsContext handlebarsContext, JToken node, object context)
|
||||
{
|
||||
if (node.Type == JTokenType.Object)
|
||||
{
|
||||
@@ -118,7 +120,7 @@ namespace WireMock.Transformers
|
||||
return;
|
||||
}
|
||||
|
||||
var templateForStringValue = handlebarsContext.Compile(stringValue);
|
||||
var templateForStringValue = handlebarsContext.Handlebars.Compile(stringValue);
|
||||
string transformedString = templateForStringValue(context);
|
||||
if (!string.Equals(stringValue, transformedString))
|
||||
{
|
||||
@@ -150,9 +152,9 @@ namespace WireMock.Transformers
|
||||
node.Replace(value);
|
||||
}
|
||||
|
||||
private static void TransformBodyAsString(IHandlebars handlebarsContext, object template, ResponseMessage original, ResponseMessage responseMessage)
|
||||
private static void TransformBodyAsString(IHandlebarsContext handlebarsContext, object template, ResponseMessage original, ResponseMessage responseMessage)
|
||||
{
|
||||
var templateBodyAsString = handlebarsContext.Compile(original.BodyData.BodyAsString);
|
||||
var templateBodyAsString = handlebarsContext.Handlebars.Compile(original.BodyData.BodyAsString);
|
||||
|
||||
responseMessage.BodyData = new BodyData
|
||||
{
|
||||
@@ -162,16 +164,33 @@ namespace WireMock.Transformers
|
||||
};
|
||||
}
|
||||
|
||||
private static void TransformBodyAsFile(IHandlebars handlebarsContext, object template, ResponseMessage original, ResponseMessage responseMessage)
|
||||
private void TransformBodyAsFile(IHandlebarsContext handlebarsContext, object template, ResponseMessage original, ResponseMessage responseMessage, bool useTransformerForBodyAsFile)
|
||||
{
|
||||
var templateBodyAsFile = handlebarsContext.Compile(original.BodyData.BodyAsFile);
|
||||
var templateBodyAsFile = handlebarsContext.Handlebars.Compile(original.BodyData.BodyAsFile);
|
||||
string transformedBodyAsFilename = templateBodyAsFile(template);
|
||||
|
||||
responseMessage.BodyData = new BodyData
|
||||
if (!useTransformerForBodyAsFile)
|
||||
{
|
||||
DetectedBodyType = original.BodyData.DetectedBodyType,
|
||||
DetectedBodyTypeFromContentType = original.BodyData.DetectedBodyTypeFromContentType,
|
||||
BodyAsFile = templateBodyAsFile(template)
|
||||
};
|
||||
responseMessage.BodyData = new BodyData
|
||||
{
|
||||
DetectedBodyType = original.BodyData.DetectedBodyType,
|
||||
DetectedBodyTypeFromContentType = original.BodyData.DetectedBodyTypeFromContentType,
|
||||
BodyAsFile = transformedBodyAsFilename
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
string text = handlebarsContext.FileSystemHandler.ReadResponseBodyAsString(transformedBodyAsFilename);
|
||||
var templateBodyAsString = handlebarsContext.Handlebars.Compile(text);
|
||||
|
||||
responseMessage.BodyData = new BodyData
|
||||
{
|
||||
DetectedBodyType = BodyType.String,
|
||||
DetectedBodyTypeFromContentType = original.BodyData.DetectedBodyTypeFromContentType,
|
||||
BodyAsString = templateBodyAsString(template),
|
||||
BodyAsFile = transformedBodyAsFilename
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,32 @@
|
||||
using JetBrains.Annotations;
|
||||
using MimeKit;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Util
|
||||
{
|
||||
internal static class BodyParser
|
||||
{
|
||||
private static readonly Encoding DefaultEncoding = Encoding.UTF8;
|
||||
private static readonly Encoding[] SupportedBodyAsStringEncodingForMultipart = { Encoding.UTF8, Encoding.ASCII };
|
||||
|
||||
/*
|
||||
HEAD - No defined body semantics.
|
||||
GET - No defined body semantics.
|
||||
PUT - Body supported.
|
||||
POST - Body supported.
|
||||
DELETE - No defined body semantics.
|
||||
TRACE - Body not supported.
|
||||
OPTIONS - Body supported but no semantics on usage (maybe in the future).
|
||||
CONNECT - No defined body semantics
|
||||
PATCH - Body supported.
|
||||
*/
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Util
|
||||
{
|
||||
internal static class BodyParser
|
||||
{
|
||||
private static readonly Encoding DefaultEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
|
||||
private static readonly Encoding[] SupportedBodyAsStringEncodingForMultipart = { DefaultEncoding, Encoding.ASCII };
|
||||
|
||||
/*
|
||||
HEAD - No defined body semantics.
|
||||
GET - No defined body semantics.
|
||||
PUT - Body supported.
|
||||
POST - Body supported.
|
||||
DELETE - No defined body semantics.
|
||||
TRACE - Body not supported.
|
||||
OPTIONS - Body supported but no semantics on usage (maybe in the future).
|
||||
CONNECT - No defined body semantics
|
||||
PATCH - Body supported.
|
||||
*/
|
||||
private static readonly IDictionary<string, bool> BodyAllowedForMethods = new Dictionary<string, bool>
|
||||
{
|
||||
{ "HEAD", false },
|
||||
@@ -39,134 +38,138 @@ namespace WireMock.Util
|
||||
{ "OPTIONS", true },
|
||||
{ "CONNECT", false },
|
||||
{ "PATCH", true }
|
||||
};
|
||||
|
||||
private static readonly IStringMatcher[] MultipartContentTypesMatchers = {
|
||||
new WildcardMatcher("multipart/*", true)
|
||||
};
|
||||
|
||||
private static readonly IStringMatcher[] JsonContentTypesMatchers = {
|
||||
new WildcardMatcher("application/json", true),
|
||||
new WildcardMatcher("application/vnd.*+json", true)
|
||||
};
|
||||
|
||||
private static readonly IStringMatcher[] TextContentTypeMatchers =
|
||||
{
|
||||
new WildcardMatcher("text/*", true),
|
||||
new RegexMatcher("^application\\/(java|type)script$", true),
|
||||
new WildcardMatcher("application/*xml", true),
|
||||
new WildcardMatcher("application/x-www-form-urlencoded", true)
|
||||
};
|
||||
|
||||
public static bool ParseBodyAsIsValid([CanBeNull] string parseBodyAs)
|
||||
{
|
||||
return Enum.TryParse(parseBodyAs, out BodyType _);
|
||||
}
|
||||
|
||||
public static bool ShouldParseBody([CanBeNull] string method)
|
||||
{
|
||||
if (String.IsNullOrEmpty(method))
|
||||
};
|
||||
|
||||
private static readonly IStringMatcher[] MultipartContentTypesMatchers = {
|
||||
new WildcardMatcher("multipart/*", true)
|
||||
};
|
||||
|
||||
private static readonly IStringMatcher[] JsonContentTypesMatchers = {
|
||||
new WildcardMatcher("application/json", true),
|
||||
new WildcardMatcher("application/vnd.*+json", true)
|
||||
};
|
||||
|
||||
private static readonly IStringMatcher[] TextContentTypeMatchers =
|
||||
{
|
||||
new WildcardMatcher("text/*", true),
|
||||
new RegexMatcher("^application\\/(java|type)script$", true),
|
||||
new WildcardMatcher("application/*xml", true),
|
||||
new WildcardMatcher("application/x-www-form-urlencoded", true)
|
||||
};
|
||||
|
||||
private static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings { DateParseHandling = DateParseHandling.None };
|
||||
|
||||
public static bool ShouldParseBody([CanBeNull] string httpMethod, bool allowBodyForAllHttpMethods)
|
||||
{
|
||||
if (string.IsNullOrEmpty(httpMethod))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (BodyAllowedForMethods.TryGetValue(method.ToUpper(), out var allowed))
|
||||
}
|
||||
|
||||
if (allowBodyForAllHttpMethods)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (BodyAllowedForMethods.TryGetValue(httpMethod.ToUpper(), out bool allowed))
|
||||
{
|
||||
return allowed;
|
||||
}
|
||||
// If we don't have any knowledge of this method, we should assume that a body *may*
|
||||
// be present, so we should parse it if it is. Therefore, if a new method is added to
|
||||
// the HTTP Method Registry, we only really need to add it to BodyAllowedForMethods if
|
||||
// we want to make it clear that a body is *not* allowed.
|
||||
return true;
|
||||
}
|
||||
|
||||
public static BodyType DetectBodyTypeFromContentType([CanBeNull] string contentTypeValue)
|
||||
{
|
||||
if (string.IsNullOrEmpty(contentTypeValue) || !ContentType.TryParse(contentTypeValue, out ContentType contentType))
|
||||
{
|
||||
return BodyType.Bytes;
|
||||
}
|
||||
|
||||
if (TextContentTypeMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MimeType))))
|
||||
{
|
||||
return BodyType.String;
|
||||
}
|
||||
|
||||
if (JsonContentTypesMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MimeType))))
|
||||
{
|
||||
return BodyType.Json;
|
||||
}
|
||||
|
||||
if (MultipartContentTypesMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MimeType))))
|
||||
{
|
||||
return BodyType.MultiPart;
|
||||
}
|
||||
|
||||
return BodyType.Bytes;
|
||||
}
|
||||
|
||||
public static async Task<BodyData> Parse([NotNull] Stream stream, [CanBeNull] string contentType)
|
||||
{
|
||||
Check.NotNull(stream, nameof(stream));
|
||||
|
||||
var data = new BodyData
|
||||
{
|
||||
BodyAsBytes = await ReadBytesAsync(stream),
|
||||
DetectedBodyType = BodyType.Bytes,
|
||||
DetectedBodyTypeFromContentType = DetectBodyTypeFromContentType(contentType)
|
||||
};
|
||||
|
||||
// In case of MultiPart: check if the BodyAsBytes is a valid UTF8 or ASCII string, in that case read as String else keep as-is
|
||||
if (data.DetectedBodyTypeFromContentType == BodyType.MultiPart)
|
||||
{
|
||||
if (BytesEncodingUtils.TryGetEncoding(data.BodyAsBytes, out Encoding encoding) &&
|
||||
SupportedBodyAsStringEncodingForMultipart.Select(x => x.Equals(encoding)).Any())
|
||||
{
|
||||
data.BodyAsString = encoding.GetString(data.BodyAsBytes);
|
||||
data.Encoding = encoding;
|
||||
data.DetectedBodyType = BodyType.String;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Try to get the body as String
|
||||
try
|
||||
{
|
||||
data.BodyAsString = DefaultEncoding.GetString(data.BodyAsBytes);
|
||||
data.Encoding = DefaultEncoding;
|
||||
data.DetectedBodyType = BodyType.String;
|
||||
|
||||
// If string is not null or empty, try to get as Json
|
||||
if (!string.IsNullOrEmpty(data.BodyAsString))
|
||||
{
|
||||
try
|
||||
{
|
||||
data.BodyAsJson = JsonConvert.DeserializeObject(data.BodyAsString, new JsonSerializerSettings { Formatting = Formatting.Indented });
|
||||
data.DetectedBodyType = BodyType.Json;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// JsonConvert failed, just ignore.
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Reading as string failed, just ignore
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
private static async Task<byte[]> ReadBytesAsync(Stream stream)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
await stream.CopyToAsync(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have any knowledge of this method, we should assume that a body *may*
|
||||
// be present, so we should parse it if it is. Therefore, if a new method is added to
|
||||
// the HTTP Method Registry, we only really need to add it to BodyAllowedForMethods if
|
||||
// we want to make it clear that a body is *not* allowed.
|
||||
return true;
|
||||
}
|
||||
|
||||
public static BodyType DetectBodyTypeFromContentType([CanBeNull] string contentTypeValue)
|
||||
{
|
||||
if (string.IsNullOrEmpty(contentTypeValue) || !MediaTypeHeaderValue.TryParse(contentTypeValue, out MediaTypeHeaderValue contentType))
|
||||
{
|
||||
return BodyType.Bytes;
|
||||
}
|
||||
|
||||
if (TextContentTypeMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType))))
|
||||
{
|
||||
return BodyType.String;
|
||||
}
|
||||
|
||||
if (JsonContentTypesMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType))))
|
||||
{
|
||||
return BodyType.Json;
|
||||
}
|
||||
|
||||
if (MultipartContentTypesMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType))))
|
||||
{
|
||||
return BodyType.MultiPart;
|
||||
}
|
||||
|
||||
return BodyType.Bytes;
|
||||
}
|
||||
|
||||
public static async Task<BodyData> Parse([NotNull] Stream stream, [CanBeNull] string contentType)
|
||||
{
|
||||
Check.NotNull(stream, nameof(stream));
|
||||
|
||||
var data = new BodyData
|
||||
{
|
||||
BodyAsBytes = await ReadBytesAsync(stream),
|
||||
DetectedBodyType = BodyType.Bytes,
|
||||
DetectedBodyTypeFromContentType = DetectBodyTypeFromContentType(contentType)
|
||||
};
|
||||
|
||||
// In case of MultiPart: check if the BodyAsBytes is a valid UTF8 or ASCII string, in that case read as String else keep as-is
|
||||
if (data.DetectedBodyTypeFromContentType == BodyType.MultiPart)
|
||||
{
|
||||
if (BytesEncodingUtils.TryGetEncoding(data.BodyAsBytes, out Encoding encoding) &&
|
||||
SupportedBodyAsStringEncodingForMultipart.Select(x => x.Equals(encoding)).Any())
|
||||
{
|
||||
data.BodyAsString = encoding.GetString(data.BodyAsBytes);
|
||||
data.Encoding = encoding;
|
||||
data.DetectedBodyType = BodyType.String;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Try to get the body as String
|
||||
try
|
||||
{
|
||||
data.BodyAsString = DefaultEncoding.GetString(data.BodyAsBytes);
|
||||
data.Encoding = DefaultEncoding;
|
||||
data.DetectedBodyType = BodyType.String;
|
||||
|
||||
// If string is not null or empty, try to deserialize the string to a JObject
|
||||
if (!string.IsNullOrEmpty(data.BodyAsString))
|
||||
{
|
||||
try
|
||||
{
|
||||
data.BodyAsJson = JsonConvert.DeserializeObject(data.BodyAsString, JsonSerializerSettings);
|
||||
data.DetectedBodyType = BodyType.Json;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// JsonConvert failed, just ignore.
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Reading as string failed, just ignore
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
private static async Task<byte[]> ReadBytesAsync(Stream stream)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
await stream.CopyToAsync(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace WireMock.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// A special Collection that overrides methods of <see cref="ObservableCollection{T}"/> to make them thread safe
|
||||
/// A special Collection that overrides methods of <see cref="ObservableCollection{T}"/> to make them thread safe.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements in the collection.</typeparam>
|
||||
/// <inheritdoc cref="ObservableCollection{T}" />
|
||||
public class ConcurrentObservableCollection<T> : ObservableCollection<T>
|
||||
internal class ConcurrentObservableCollection<T> : ObservableCollection<T>
|
||||
{
|
||||
private readonly object _lockObject = new object();
|
||||
|
||||
@@ -73,5 +74,13 @@ namespace WireMock.Util
|
||||
base.MoveItem(oldIndex, newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public List<T> ToList()
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
return Items.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
71
src/WireMock.Net/Util/HttpStatusRangeParser.cs
Normal file
71
src/WireMock.Net/Util/HttpStatusRangeParser.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace WireMock.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// Based on https://github.com/tmenier/Flurl/blob/129565361e135e639f1d44a35a78aea4302ac6ca/src/Flurl.Http/HttpStatusRangeParser.cs
|
||||
/// </summary>
|
||||
internal static class HttpStatusRangeParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether the specified pattern is match.
|
||||
/// </summary>
|
||||
/// <param name="pattern">The pattern. (Can be null, in that case it's allowed.)</param>
|
||||
/// <param name="httpStatusCode">The value.</param>
|
||||
/// <exception cref="ArgumentException"><paramref name="pattern"/> is invalid.</exception>
|
||||
public static bool IsMatch(string pattern, HttpStatusCode httpStatusCode)
|
||||
{
|
||||
return IsMatch(pattern, (int)httpStatusCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified pattern is match.
|
||||
/// </summary>
|
||||
/// <param name="pattern">The pattern. (Can be null, in that case it's allowed.)</param>
|
||||
/// <param name="httpStatusCode">The value.</param>
|
||||
/// <exception cref="ArgumentException"><paramref name="pattern"/> is invalid.</exception>
|
||||
public static bool IsMatch(string pattern, int httpStatusCode)
|
||||
{
|
||||
if (pattern == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var range in pattern.Split(',').Select(p => p.Trim()))
|
||||
{
|
||||
switch (range)
|
||||
{
|
||||
case "":
|
||||
continue;
|
||||
|
||||
case "*":
|
||||
return true; // special case - allow everything
|
||||
}
|
||||
|
||||
string[] bounds = range.Split('-');
|
||||
int lower = 0;
|
||||
int upper = 0;
|
||||
|
||||
bool valid =
|
||||
bounds.Length <= 2 &&
|
||||
int.TryParse(Regex.Replace(bounds.First().Trim(), "[*xX]", "0"), out lower) &&
|
||||
int.TryParse(Regex.Replace(bounds.Last().Trim(), "[*xX]", "9"), out upper);
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
throw new ArgumentException($"Invalid range pattern: \"{pattern}\". Examples of allowed patterns: \"400\", \"4xx\", \"300,400-403\", \"*\".");
|
||||
}
|
||||
|
||||
if (httpStatusCode >= lower && httpStatusCode <= upper)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -8,6 +9,22 @@ namespace WireMock.Util
|
||||
{
|
||||
internal static class JsonUtils
|
||||
{
|
||||
private static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings
|
||||
{
|
||||
DateParseHandling = DateParseHandling.None
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Load a Newtonsoft.Json.Linq.JObject from a string that contains JSON.
|
||||
/// Using : DateParseHandling = DateParseHandling.None
|
||||
/// </summary>
|
||||
/// <param name="json">A System.String that contains JSON.</param>
|
||||
/// <returns>A Newtonsoft.Json.Linq.JToken populated from the string that contains JSON.</returns>
|
||||
public static JToken Parse(string json)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<JToken>(json, JsonSerializerSettings);
|
||||
}
|
||||
|
||||
public static T ParseJTokenToObject<T>(object value)
|
||||
{
|
||||
switch (value)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
namespace WireMock.Util
|
||||
{
|
||||
@@ -30,7 +31,7 @@ namespace WireMock.Util
|
||||
.Split(new[] { '&', ';' }, StringSplitOptions.RemoveEmptyEntries) // Support "?key=value;key=anotherValue" and "?key=value&key=anotherValue"
|
||||
.Select(parameter => parameter.Split(new[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries))
|
||||
.GroupBy(parts => parts[0], JoinParts)
|
||||
.ToDictionary(grouping => grouping.Key, grouping => new WireMockList<string>(grouping.SelectMany(x => x)));
|
||||
.ToDictionary(grouping => grouping.Key, grouping => new WireMockList<string>(grouping.SelectMany(x => x).Select(WebUtility.UrlDecode)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +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;netcoreapp2.1</TargetFrameworks>-->
|
||||
<TargetFrameworks>net451;net452;net46;net461;netstandard1.3;netstandard2.0</TargetFrameworks>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<AssemblyName>WireMock.Net</AssemblyName>
|
||||
@@ -11,14 +12,14 @@
|
||||
<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>
|
||||
<PackageLicenseUrl>https://raw.githubusercontent.com/WireMock-Net/WireMock.Net/master/LICENSE</PackageLicenseUrl>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<RepositoryUrl>https://github.com/WireMock-Net/WireMock.Net</RepositoryUrl>
|
||||
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
|
||||
<RootNamespace>WireMock</RootNamespace>
|
||||
<DebugType>full</DebugType>
|
||||
<!--<DebugType>full</DebugType>
|
||||
<IncludeSource>True</IncludeSource>
|
||||
<IncludeSymbols>True</IncludeSymbols>
|
||||
<IncludeSymbols>True</IncludeSymbols>-->
|
||||
<ProjectGuid>{D3804228-91F4-4502-9595-39584E5A01AD}</ProjectGuid>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
|
||||
@@ -31,6 +32,13 @@
|
||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--<ItemGroup>
|
||||
<None Include="WireMock.Net-Logo.png" Pack="true" PackagePath="../../"/>
|
||||
</ItemGroup>-->
|
||||
|
||||
<!--https://github.com/aspnet/RoslynCodeDomProvider/issues/51-->
|
||||
<Target Name="CheckIfShouldKillVBCSCompiler" />
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
<PathMap>$(MSBuildProjectDirectory)=/</PathMap>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
@@ -40,37 +48,46 @@
|
||||
<DefineConstants>NETSTANDARD;USE_ASPNETCORE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp2.1' or '$(TargetFramework)' == 'netcoreapp2.2'">
|
||||
<DefineConstants>USE_ASPNETCORE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'net461'">
|
||||
<DefineConstants>USE_ASPNETCORE;NET46</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="RequestBuilders\Request.WithFault.cs" />
|
||||
<Compile Remove="Util\CloneUtils.cs" />
|
||||
<Compile Remove="Util\IndexableDictionary.cs" />
|
||||
<Compile Remove="Util\NamedReaderWriterLocker.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="ResponseBuilders\Response.WithFault.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2018.2.1">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<!--<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />-->
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
|
||||
<PackageReference Include="RestEase" Version="1.4.7" />
|
||||
<PackageReference Include="MimeKitLite" Version="2.0.7" />
|
||||
<PackageReference Include="SonarAnalyzer.CSharp" Version="7.8.0.7320">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.12" />
|
||||
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.8" />
|
||||
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.10" />
|
||||
<PackageReference Include="JmesPath.Net" Version="1.0.125" />
|
||||
<!--<PackageReference Include="CloneExtensionsEx" Version="1.0.2" />-->
|
||||
<!--<PackageReference Include="FastDeepCloner" Version="1.2.5" />-->
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
|
||||
<PackageReference Include="Handlebars.Net" Version="1.9.0" />
|
||||
<PackageReference Include="Handlebars.Net" Version="[1.9.0]" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' != 'net451' ">
|
||||
@@ -87,6 +104,7 @@
|
||||
|
||||
<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' ">
|
||||
@@ -95,6 +113,7 @@
|
||||
|
||||
<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' ">
|
||||
@@ -104,10 +123,12 @@
|
||||
<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' ">
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.1.2" />
|
||||
<PackageReference Include="CS-Script" Version="3.29.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
|
||||
@@ -118,7 +139,8 @@
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0'">
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.1.4" />
|
||||
<PackageReference Include="CS-Script.Core" Version="1.1.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -171,7 +171,7 @@ namespace WireMock.Net.Tests
|
||||
var staticMappingHandlerMock = new Mock<IFileSystemHandler>();
|
||||
staticMappingHandlerMock.Setup(m => m.GetMappingFolder()).Returns("folder");
|
||||
staticMappingHandlerMock.Setup(m => m.FolderExists(It.IsAny<string>())).Returns(true);
|
||||
staticMappingHandlerMock.Setup(m => m.EnumerateFiles(It.IsAny<string>())).Returns(new string[0]);
|
||||
staticMappingHandlerMock.Setup(m => m.EnumerateFiles(It.IsAny<string>(), It.IsAny<bool>())).Returns(new string[0]);
|
||||
|
||||
var server = FluentMockServer.Start(new FluentMockServerSettings
|
||||
{
|
||||
@@ -184,7 +184,7 @@ namespace WireMock.Net.Tests
|
||||
// Assert and Verify
|
||||
staticMappingHandlerMock.Verify(m => m.GetMappingFolder(), Times.Once);
|
||||
staticMappingHandlerMock.Verify(m => m.FolderExists("folder"), Times.Once);
|
||||
staticMappingHandlerMock.Verify(m => m.EnumerateFiles("folder"), Times.Once);
|
||||
staticMappingHandlerMock.Verify(m => m.EnumerateFiles("folder", false), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.RequestBuilders;
|
||||
using WireMock.ResponseBuilders;
|
||||
@@ -17,6 +18,35 @@ namespace WireMock.Net.Tests
|
||||
{
|
||||
public class FluentMockServerProxyTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task FluentMockServer_Proxy_Should_log_proxied_requests()
|
||||
{
|
||||
// Assign
|
||||
var settings = new FluentMockServerSettings
|
||||
{
|
||||
ProxyAndRecordSettings = new ProxyAndRecordSettings
|
||||
{
|
||||
Url = "http://www.google.com",
|
||||
SaveMapping = true,
|
||||
SaveMappingToFile = false
|
||||
}
|
||||
};
|
||||
var server = FluentMockServer.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 FluentMockServer_Proxy_Should_proxy_responses()
|
||||
{
|
||||
@@ -39,6 +69,7 @@ namespace WireMock.Net.Tests
|
||||
|
||||
// Assert
|
||||
Check.That(server.Mappings).HasSize(1);
|
||||
Check.That(server.LogEntries).HasSize(1);
|
||||
Check.That(content).Contains("google");
|
||||
}
|
||||
|
||||
@@ -308,6 +339,43 @@ namespace WireMock.Net.Tests
|
||||
Check.That(receivedRequest.Cookies).ContainsPair("name", "value");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send some binary content in a request through the proxy and check that the same content
|
||||
/// arrived at the target. As example a JPEG/JIFF header is used, which is not representable
|
||||
/// in UTF8 and breaks if it is not treated as binary content.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task FluentMockServer_Proxy_Should_preserve_binary_request_content()
|
||||
{
|
||||
// arrange
|
||||
var jpegHeader = new byte[] {0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00};
|
||||
var brokenJpegHeader = new byte[]
|
||||
{0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00};
|
||||
|
||||
bool HasCorrectHeader(byte[] bytes) => bytes.SequenceEqual(jpegHeader);
|
||||
bool HasBrokenHeader(byte[] bytes) => bytes.SequenceEqual(brokenJpegHeader);
|
||||
|
||||
var serverForProxyForwarding = FluentMockServer.Start();
|
||||
serverForProxyForwarding
|
||||
.Given(Request.Create().WithBody(HasCorrectHeader))
|
||||
.RespondWith(Response.Create().WithSuccess());
|
||||
|
||||
serverForProxyForwarding
|
||||
.Given(Request.Create().WithBody(HasBrokenHeader))
|
||||
.RespondWith(Response.Create().WithStatusCode(HttpStatusCode.InternalServerError));
|
||||
|
||||
var server = FluentMockServer.Start();
|
||||
server
|
||||
.Given(Request.Create())
|
||||
.RespondWith(Response.Create().WithProxy(serverForProxyForwarding.Urls[0]));
|
||||
|
||||
// act
|
||||
var response = await new HttpClient().PostAsync(server.Urls[0], new ByteArrayContent(jpegHeader));
|
||||
|
||||
// assert
|
||||
Check.That(response.StatusCode).IsEqualTo(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FluentMockServer_Proxy_Should_set_BodyAsJson_in_proxied_response()
|
||||
{
|
||||
|
||||
@@ -116,7 +116,25 @@ namespace WireMock.Net.Tests
|
||||
|
||||
// Assert
|
||||
var options = server.GetPrivateFieldValue<IWireMockMiddlewareOptions>("_options");
|
||||
Check.That(options.AllowPartialMapping).IsTrue();
|
||||
Check.That(options.AllowPartialMapping).Equals(true);
|
||||
|
||||
// Verify
|
||||
_loggerMock.Verify(l => l.Info(It.IsAny<string>(), It.IsAny<bool>()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FluentMockServer_FluentMockServerSettings_AllowBodyForAllHttpMethods()
|
||||
{
|
||||
// Assign and Act
|
||||
var server = FluentMockServer.Start(new FluentMockServerSettings
|
||||
{
|
||||
Logger = _loggerMock.Object,
|
||||
AllowBodyForAllHttpMethods = true
|
||||
});
|
||||
|
||||
// Assert
|
||||
var options = server.GetPrivateFieldValue<IWireMockMiddlewareOptions>("_options");
|
||||
Check.That(options.AllowBodyForAllHttpMethods).Equals(true);
|
||||
|
||||
// Verify
|
||||
_loggerMock.Verify(l => l.Info(It.IsAny<string>(), It.IsAny<bool>()));
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using NFluent;
|
||||
using System;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using NFluent;
|
||||
using WireMock.RequestBuilders;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.Server;
|
||||
@@ -187,7 +188,7 @@ namespace WireMock.Net.Tests
|
||||
var server = FluentMockServer.Start();
|
||||
|
||||
server
|
||||
.Given(Request.Create().WithBody(b => true))
|
||||
.Given(Request.Create().WithBody((byte[] bodyBytes) => bodyBytes != null))
|
||||
.AtPriority(0)
|
||||
.RespondWith(Response.Create().WithStatusCode(400));
|
||||
server
|
||||
@@ -203,7 +204,7 @@ namespace WireMock.Net.Tests
|
||||
// Assert
|
||||
Check.That(response.StatusCode).Equals(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData("POST")]
|
||||
[InlineData("PUT")]
|
||||
@@ -233,5 +234,38 @@ namespace WireMock.Net.Tests
|
||||
// Assert
|
||||
Check.That(response.StatusCode).Equals(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/json")]
|
||||
[InlineData("application/json; charset=ascii")]
|
||||
[InlineData("application/json; charset=utf-8")]
|
||||
[InlineData("application/json; charset=UTF-8")]
|
||||
public async Task WireMockServer_Should_AcceptPostMappingsWithContentTypeJsonAndAnyCharset(string contentType)
|
||||
{
|
||||
// Arrange
|
||||
string message = @"{
|
||||
""request"": {
|
||||
""method"": ""GET"",
|
||||
""url"": ""/some/thing""
|
||||
},
|
||||
""response"": {
|
||||
""status"": 200,
|
||||
""body"": ""Hello world!"",
|
||||
""headers"": {
|
||||
""Content-Type"": ""text/plain""
|
||||
}
|
||||
}
|
||||
}";
|
||||
var stringContent = new StringContent(message);
|
||||
stringContent.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType);
|
||||
var server = FluentMockServer.StartWithAdminInterface();
|
||||
|
||||
// Act
|
||||
var response = await new HttpClient().PostAsync($"{server.Urls[0]}/__admin/mappings", stringContent);
|
||||
|
||||
// Assert
|
||||
Check.That(response.StatusCode).Equals(HttpStatusCode.Created);
|
||||
Check.That(await response.Content.ReadAsStringAsync()).Contains("Mapping added");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,7 +137,7 @@ namespace WireMock.Net.Tests.Http
|
||||
var message = HttpRequestMessageHelper.Create(request, "http://url");
|
||||
|
||||
// Assert
|
||||
Check.That(message.Content.Headers.GetValues("Content-Type")).ContainsExactly("application/xml; charset=utf-8");
|
||||
Check.That(message.Content.Headers.GetValues("Content-Type")).ContainsExactly("application/xml; charset=UTF-8");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -156,7 +156,7 @@ namespace WireMock.Net.Tests.Http
|
||||
var message = HttpRequestMessageHelper.Create(request, "http://url");
|
||||
|
||||
// Assert
|
||||
Check.That(message.Content.Headers.GetValues("Content-Type")).ContainsExactly("application/xml; charset=us-ascii");
|
||||
Check.That(message.Content.Headers.GetValues("Content-Type")).ContainsExactly("application/xml; charset=Ascii");
|
||||
}
|
||||
}
|
||||
}
|
||||
39
test/WireMock.Net.Tests/Http/StringContentHelperTests.cs
Normal file
39
test/WireMock.Net.Tests/Http/StringContentHelperTests.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Net.Http.Headers;
|
||||
using FluentAssertions;
|
||||
using WireMock.Http;
|
||||
using Xunit;
|
||||
|
||||
namespace WireMock.Net.Tests.Http
|
||||
{
|
||||
public class StringContentHelperTests
|
||||
{
|
||||
[Fact]
|
||||
public void StringContentHelper_Create_WithNullContentType()
|
||||
{
|
||||
// Act
|
||||
var result = StringContentHelper.Create("test", null);
|
||||
|
||||
// Assert
|
||||
result.Headers.ContentType.Should().BeNull();
|
||||
result.ReadAsStringAsync().Result.Should().Be("test");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/json", "application/json")]
|
||||
[InlineData("application/soap+xml", "application/soap+xml")]
|
||||
[InlineData("application/soap+xml;charset=UTF-8", "application/soap+xml; charset=UTF-8")]
|
||||
[InlineData("application/soap+xml;charset=UTF-8;action=\"http://myCompany.Customer.Contract/ICustomerService/GetSomeConfiguration\"", "application/soap+xml; charset=UTF-8; action=\"http://myCompany.Customer.Contract/ICustomerService/GetSomeConfiguration\"")]
|
||||
public void StringContentHelper_Create(string test, string expected)
|
||||
{
|
||||
// Arrange
|
||||
var contentType = MediaTypeHeaderValue.Parse(test);
|
||||
|
||||
// Act
|
||||
var result = StringContentHelper.Create("test", contentType);
|
||||
|
||||
// Assert
|
||||
result.Headers.ContentType.ToString().Should().Be(expected);
|
||||
result.ReadAsStringAsync().Result.Should().Be("test");
|
||||
}
|
||||
}
|
||||
}
|
||||
92
test/WireMock.Net.Tests/Matchers/CSharpCodeMatcherTests.cs
Normal file
92
test/WireMock.Net.Tests/Matchers/CSharpCodeMatcherTests.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using NFluent;
|
||||
using WireMock.Matchers;
|
||||
using Xunit;
|
||||
|
||||
namespace WireMock.Net.Tests.Matchers
|
||||
{
|
||||
public class CSharpCodeMatcherTests
|
||||
{
|
||||
[Fact]
|
||||
public void CSharpCodeMatcher_For_String_SinglePattern_IsMatch_Positive()
|
||||
{
|
||||
// Assign
|
||||
string input = "x";
|
||||
|
||||
// Act
|
||||
var matcher = new CSharpCodeMatcher("return it == \"x\";");
|
||||
|
||||
// Assert
|
||||
Check.That(matcher.IsMatch(input)).IsEqualTo(1.0d);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CSharpCodeMatcher_For_String_IsMatch_Negative()
|
||||
{
|
||||
// Assign
|
||||
string input = "y";
|
||||
|
||||
// Act
|
||||
var matcher = new CSharpCodeMatcher("return it == \"x\";");
|
||||
|
||||
// Assert
|
||||
Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CSharpCodeMatcher_For_String_IsMatch_RejectOnMatch()
|
||||
{
|
||||
// Assign
|
||||
string input = "x";
|
||||
|
||||
// Act
|
||||
var matcher = new CSharpCodeMatcher(MatchBehaviour.RejectOnMatch, "return it == \"x\";");
|
||||
|
||||
// Assert
|
||||
Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CSharpCodeMatcher_For_Object_IsMatch()
|
||||
{
|
||||
// Assign
|
||||
var input = new
|
||||
{
|
||||
Id = 9,
|
||||
Name = "Test"
|
||||
};
|
||||
|
||||
// Act
|
||||
var matcher = new CSharpCodeMatcher("return it.Id > 1 && it.Name == \"Test\";");
|
||||
double match = matcher.IsMatch(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1.0, match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CSharpCodeMatcher_GetName()
|
||||
{
|
||||
// Assign
|
||||
var matcher = new CSharpCodeMatcher("x");
|
||||
|
||||
// Act
|
||||
string name = matcher.Name;
|
||||
|
||||
// Assert
|
||||
Check.That(name).Equals("CSharpCodeMatcher");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CSharpCodeMatcher_GetPatterns()
|
||||
{
|
||||
// Assign
|
||||
var matcher = new CSharpCodeMatcher("x");
|
||||
|
||||
// Act
|
||||
string[] patterns = matcher.GetPatterns();
|
||||
|
||||
// Assert
|
||||
Check.That(patterns).ContainsExactly("x");
|
||||
}
|
||||
}
|
||||
}
|
||||
58
test/WireMock.Net.Tests/Matchers/ContentTypeMatcherTests.cs
Normal file
58
test/WireMock.Net.Tests/Matchers/ContentTypeMatcherTests.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using NFluent;
|
||||
using WireMock.Matchers;
|
||||
using Xunit;
|
||||
|
||||
namespace WireMock.Net.Tests.Matchers
|
||||
{
|
||||
public class ContentTypeMatcherTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("application/json")]
|
||||
[InlineData("application/json; charset=ascii")]
|
||||
[InlineData("application/json; charset=utf-8")]
|
||||
[InlineData("application/json; charset=UTF-8")]
|
||||
public void ContentTypeMatcher_IsMatchWithIgnoreCaseFalse_Positive(string contentType)
|
||||
{
|
||||
var matcher = new ContentTypeMatcher("application/json");
|
||||
Check.That(matcher.IsMatch(contentType)).IsEqualTo(1.0d);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/json")]
|
||||
[InlineData("application/JSON")]
|
||||
[InlineData("application/json; CharSet=ascii")]
|
||||
[InlineData("application/json; charset=utf-8")]
|
||||
[InlineData("application/json; charset=UTF-8")]
|
||||
public void ContentTypeMatcher_IsMatchWithIgnoreCaseTrue_Positive(string contentType)
|
||||
{
|
||||
var matcher = new ContentTypeMatcher("application/json", true);
|
||||
Check.That(matcher.IsMatch(contentType)).IsEqualTo(1.0d);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ContentTypeMatcher_GetName()
|
||||
{
|
||||
// Assign
|
||||
var matcher = new ContentTypeMatcher("x");
|
||||
|
||||
// Act
|
||||
string name = matcher.Name;
|
||||
|
||||
// Assert
|
||||
Check.That(name).Equals("ContentTypeMatcher");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ContentTypeMatcher_GetPatterns()
|
||||
{
|
||||
// Assign
|
||||
var matcher = new ContentTypeMatcher("x");
|
||||
|
||||
// Act
|
||||
string[] patterns = matcher.GetPatterns();
|
||||
|
||||
// Assert
|
||||
Check.That(patterns).ContainsExactly("x");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,24 @@ namespace WireMock.Net.Tests.Matchers
|
||||
Check.That(match).IsEqualTo(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonMatcher_IsMatch_JArray()
|
||||
{
|
||||
// Assign
|
||||
var matcher = new JsonMatcher(new[] { "x", "y" });
|
||||
|
||||
// Act
|
||||
var jArray = new JArray
|
||||
{
|
||||
"x",
|
||||
"y"
|
||||
};
|
||||
double match = matcher.IsMatch(jArray);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1.0, match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonMatcher_IsMatch_JObject()
|
||||
{
|
||||
@@ -139,6 +157,24 @@ namespace WireMock.Net.Tests.Matchers
|
||||
Assert.Equal(1.0, match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonMatcher_IsMatch_JArrayAsString()
|
||||
{
|
||||
// Assign
|
||||
var matcher = new JsonMatcher("[ \"x\", \"y\" ]");
|
||||
|
||||
// Act
|
||||
var jArray = new JArray
|
||||
{
|
||||
"x",
|
||||
"y"
|
||||
};
|
||||
double match = matcher.IsMatch(jArray);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1.0, match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonMatcher_IsMatch_JObjectAsString()
|
||||
{
|
||||
@@ -192,5 +228,22 @@ namespace WireMock.Net.Tests.Matchers
|
||||
// Assert
|
||||
Assert.Equal(0.0, match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonMatcher_IsMatch_JObjectWithDateTimeOffsetAsString()
|
||||
{
|
||||
// Assign
|
||||
var matcher = new JsonMatcher("{ \"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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user