From 1f33e6a671fd93173aa468e6e63fded1961a9152 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 27 Jan 2017 21:19:30 +0100 Subject: [PATCH] Add a new stub mapping --- README.md | 44 ++-- .../Program.cs | 1 + .../Admin/Mappings/MappingModel.cs | 2 +- .../Admin/Mappings/MatcherModel.cs | 8 + .../Admin/Mappings/RequestModel.cs | 4 +- .../Admin/Mappings/ResponseModel.cs | 26 +- src/WireMock.Net/Admin/Mappings/UrlModel.cs | 2 +- src/WireMock.Net/DynamicResponseProvider.cs | 6 +- .../HttpListenerResponseMapper.cs | 19 +- src/WireMock.Net/Mapping.cs | 17 +- .../Request/RequestMessageCookieMatcher.cs | 15 ++ .../Request/RequestMessageHeaderMatcher.cs | 15 ++ .../RequestBuilders/IBodyRequestBuilder.cs | 30 +-- .../IHeadersAndCookiesRequestBuilder.cs | 47 ++-- .../RequestBuilders/IMethodRequestBuilder.cs | 28 +-- .../RequestBuilders/IParamsRequestBuilder.cs | 10 +- .../IUrlAndPathRequestBuilder.cs | 24 +- src/WireMock.Net/RequestBuilders/Request.cs | 136 +++++----- .../ResponseBuilders/IBodyResponseBuilder.cs | 15 +- .../IHeadersResponseBuilder.cs | 15 +- .../IStatusCodeResponseBuilder.cs | 12 +- .../ITransformResponseBuilder.cs | 4 +- src/WireMock.Net/ResponseBuilders/Response.cs | 68 +++-- .../Server/FluentMockServer.Admin.cs | 236 ++++++++++++++---- src/WireMock.Net/Server/FluentMockServer.cs | 4 +- .../Server/IRespondWithAProviderGuid.cs | 17 ++ .../Server/RespondWithAProvider.cs | 22 +- .../FluentMockServerTests.cs | 13 +- 28 files changed, 576 insertions(+), 264 deletions(-) create mode 100644 src/WireMock.Net/Server/IRespondWithAProviderGuid.cs diff --git a/README.md b/README.md index 5cd9d7b8..8a5cab6c 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,29 @@ A C# .NET version based on https://github.com/alexvictoor/WireMock which tries t [![Version](https://img.shields.io/nuget/v/WireMock.Net.svg)](https://www.nuget.org/packages/WireMock.Net) -Based on class HttpListener from the .net framework, it is very lightweight and have no external dependencies. +Based on class HttpListener from the .net framework, it is very lightweight and have no external dependencies. + +## Admin API Reference +The WireMock admin API provides functionality to define the mappings via a http interface. The following interfaces are supported: + +### /__admin/mappings +The mappings defined in the mock service. +* `GET /__admin/mappings` --> Gets all defined mappings +* `DELETE /__admin/mappings` --> Create a new stub mapping +* `POST /__admin/mappings` --> TODO +* `DELETE /__admin/mappings` --> TODO + +### /__admin/requests +Logged requests and responses received by the mock service. +* `GET /__admin/requests` --> Get received requests +* `GET /__admin/requests/{requestId}` --> TODO +* `POST /__admin/requests/reset` --> TODO +* `POST /__admin/requests/count` --> TODO +* `POST /__admin/requests/find` --> TODO +* `GET /__admin/requests/unmatched` --> TODO +* `GET /__admin/requests/unmatched/near-misses` --> TODO + + ## Stubbing A core feature of WireMock is the ability to return canned HTTP responses for requests matching criteria. @@ -303,25 +325,5 @@ var server = FluentMockServer.Start(port: 8443, ssl: true); ``` Obviously you need a certificate registered on your box, properly associated with your application and the port number that will be used. This is not really specific to WireMock, not very straightforward and hence the following stackoverflow thread might come handy: [Httplistener with https support](http://stackoverflow.com/questions/11403333/httplistener-with-https-support) -## Admin API Reference -The WireMock admin API provides functionality to define the mappings via a http interface. The following interfaces are supported: - -### /__admin/mappings -The mappings defined in the mock service. -* `GET /__admin/mappings` --> Gets all defined mappings. -* `DELETE /__admin/mappings` --> TODO -* `POST /__admin/mappings` --> TODO -* `DELETE /__admin/mappings` --> TODO - -### /__admin/requests -Logged requests and responses received by the mock service. -* `GET /__admin/requests` --> Get received requests -* `GET /__admin/requests/{requestId}` --> TODO -* `POST /__admin/requests/reset` --> TODO -* `POST /__admin/requests/count` --> TODO -* `POST /__admin/requests/find` --> TODO -* `GET /__admin/requests/unmatched` --> TODO -* `GET /__admin/requests/unmatched/near-misses` --> TODO - ## Simulating faults Currently not done - need to get rid of HttpListener and use lower level TcpListener in order to be able to implement this properly diff --git a/examples/WireMock.Net.ConsoleApplication/Program.cs b/examples/WireMock.Net.ConsoleApplication/Program.cs index 0ba61fbb..50be2766 100644 --- a/examples/WireMock.Net.ConsoleApplication/Program.cs +++ b/examples/WireMock.Net.ConsoleApplication/Program.cs @@ -28,6 +28,7 @@ namespace WireMock.Net.ConsoleApplication // http://localhost:8080/gffgfgf/sddsds?start=1000&stop=1&stop=2 server .Given(Request.Create().WithUrl("/*").UsingGet().WithParam("start")) + .WithGuid(Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05")) .RespondWith(Response.Create() .WithStatusCode(200) .WithHeader("Content-Type", "application/json") diff --git a/src/WireMock.Net/Admin/Mappings/MappingModel.cs b/src/WireMock.Net/Admin/Mappings/MappingModel.cs index 6ce00853..84f100a9 100644 --- a/src/WireMock.Net/Admin/Mappings/MappingModel.cs +++ b/src/WireMock.Net/Admin/Mappings/MappingModel.cs @@ -13,7 +13,7 @@ namespace WireMock.Admin.Mappings /// /// The unique identifier. /// - public Guid Guid { get; set; } + public Guid? Guid { get; set; } /// /// Gets or sets the request. diff --git a/src/WireMock.Net/Admin/Mappings/MatcherModel.cs b/src/WireMock.Net/Admin/Mappings/MatcherModel.cs index 790188e2..3bceaf13 100644 --- a/src/WireMock.Net/Admin/Mappings/MatcherModel.cs +++ b/src/WireMock.Net/Admin/Mappings/MatcherModel.cs @@ -20,5 +20,13 @@ /// The pattern. /// public string Pattern { get; set; } + + /// + /// Gets or sets the ignore case. + /// + /// + /// The ignore case. + /// + public bool? IgnoreCase { get; set; } } } diff --git a/src/WireMock.Net/Admin/Mappings/RequestModel.cs b/src/WireMock.Net/Admin/Mappings/RequestModel.cs index d70d79d3..34f07599 100644 --- a/src/WireMock.Net/Admin/Mappings/RequestModel.cs +++ b/src/WireMock.Net/Admin/Mappings/RequestModel.cs @@ -8,12 +8,12 @@ namespace WireMock.Admin.Mappings public class RequestModel { /// - /// Gets or sets the URL. + /// Gets or sets the URL. (Can be a string or a UrlModel) /// /// /// The URL. /// - public UrlModel Url { get; set; } + public object Url { get; set; } /// /// The methods diff --git a/src/WireMock.Net/Admin/Mappings/ResponseModel.cs b/src/WireMock.Net/Admin/Mappings/ResponseModel.cs index b5e6c8f8..f433c1c0 100644 --- a/src/WireMock.Net/Admin/Mappings/ResponseModel.cs +++ b/src/WireMock.Net/Admin/Mappings/ResponseModel.cs @@ -13,7 +13,7 @@ namespace WireMock.Admin.Mappings /// /// The HTTP status. /// - public int StatusCode { get; set; } + public int? StatusCode { get; set; } /// /// Gets or sets the body. @@ -23,6 +23,30 @@ namespace WireMock.Admin.Mappings /// public string Body { get; set; } + /// + /// Gets or sets the body. + /// + /// + /// The body. + /// + public string BodyAsBase64 { get; set; } + + /// + /// Gets or sets the body (as JSON object). + /// + /// + /// The body. + /// + public object BodyAsJson { get; set; } + + /// + /// Gets or sets a value indicating whether [use transformer]. + /// + /// + /// true if [use transformer]; otherwise, false. + /// + public bool UseTransformer { get; set; } + /// /// Gets or sets the headers. /// diff --git a/src/WireMock.Net/Admin/Mappings/UrlModel.cs b/src/WireMock.Net/Admin/Mappings/UrlModel.cs index fd7af3e4..f710a827 100644 --- a/src/WireMock.Net/Admin/Mappings/UrlModel.cs +++ b/src/WireMock.Net/Admin/Mappings/UrlModel.cs @@ -13,6 +13,6 @@ namespace WireMock.Admin.Mappings /// /// The matchers. /// - public IList Matchers { get; set; } + public MatcherModel[] Matchers { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net/DynamicResponseProvider.cs b/src/WireMock.Net/DynamicResponseProvider.cs index 9fd64afa..ac31f004 100644 --- a/src/WireMock.Net/DynamicResponseProvider.cs +++ b/src/WireMock.Net/DynamicResponseProvider.cs @@ -7,9 +7,9 @@ namespace WireMock { internal class DynamicResponseProvider : IResponseProvider { - private readonly Func _responseMessageFunc; + private readonly Func _responseMessageFunc; - public DynamicResponseProvider([NotNull] Func responseMessageFunc) + public DynamicResponseProvider([NotNull] Func responseMessageFunc) { Check.NotNull(responseMessageFunc, nameof(responseMessageFunc)); @@ -18,7 +18,7 @@ namespace WireMock public Task ProvideResponse(RequestMessage requestMessage) { - return Task.FromResult(_responseMessageFunc()); + return Task.FromResult(_responseMessageFunc(requestMessage)); } } } \ No newline at end of file diff --git a/src/WireMock.Net/HttpListenerResponseMapper.cs b/src/WireMock.Net/HttpListenerResponseMapper.cs index 05be93a9..6a0897b8 100644 --- a/src/WireMock.Net/HttpListenerResponseMapper.cs +++ b/src/WireMock.Net/HttpListenerResponseMapper.cs @@ -9,25 +9,28 @@ namespace WireMock /// public class HttpListenerResponseMapper { + private readonly Encoding _utf8NoBom = new UTF8Encoding(false); + /// /// The map. /// /// /// The response. /// - /// - /// The result. - /// - public void Map(ResponseMessage responseMessage, HttpListenerResponse result) + /// The listenerResponse. + public void Map(ResponseMessage responseMessage, HttpListenerResponse listenerResponse) { - result.StatusCode = responseMessage.StatusCode; + listenerResponse.StatusCode = responseMessage.StatusCode; - responseMessage.Headers.ToList().ForEach(pair => result.AddHeader(pair.Key, pair.Value)); + responseMessage.Headers.ToList().ForEach(pair => listenerResponse.AddHeader(pair.Key, pair.Value)); if (responseMessage.Body != null) { - var content = Encoding.UTF8.GetBytes(responseMessage.Body); - result.OutputStream.Write(content, 0, content.Length); + byte[] buffer = _utf8NoBom.GetBytes(responseMessage.Body); + listenerResponse.ContentEncoding = _utf8NoBom; + listenerResponse.ContentLength64 = buffer.Length; + listenerResponse.OutputStream.Write(buffer, 0, buffer.Length); + listenerResponse.OutputStream.Flush(); } } } diff --git a/src/WireMock.Net/Mapping.cs b/src/WireMock.Net/Mapping.cs index 4ae6d86a..b3dfdb64 100644 --- a/src/WireMock.Net/Mapping.cs +++ b/src/WireMock.Net/Mapping.cs @@ -1,13 +1,22 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using WireMock.Matchers.Request; namespace WireMock { /// - /// The route. + /// The Mapping. /// public class Mapping { + /// + /// Gets the unique identifier. + /// + /// + /// The unique identifier. + /// + public Guid Guid { get; } + /// /// The Request matcher. /// @@ -21,10 +30,12 @@ namespace WireMock /// /// Initializes a new instance of the class. /// + /// The the unique identifier. /// The request matcher. /// The provider. - public Mapping(IRequestMatcher requestMatcher, IResponseProvider provider) + public Mapping(Guid guid, IRequestMatcher requestMatcher, IResponseProvider provider) { + Guid = guid; RequestMatcher = requestMatcher; Provider = provider; } diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs index ce277113..f25f1f9c 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs @@ -41,6 +41,20 @@ namespace WireMock.Matchers.Request Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) }; } + /// + /// Initializes a new instance of the class. + /// + /// The name. + /// The matchers. + public RequestMessageCookieMatcher([NotNull] string name, [NotNull] params IMatcher[] matchers) + { + Check.NotNull(name, nameof(name)); + Check.NotNull(matchers, nameof(matchers)); + + Name = name; + Matchers = matchers; + } + /// /// Initializes a new instance of the class. /// @@ -48,6 +62,7 @@ namespace WireMock.Matchers.Request public RequestMessageCookieMatcher([NotNull] params Func, bool>[] funcs) { Check.NotNull(funcs, nameof(funcs)); + _cookieFuncs = funcs; } diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs index 702b57e2..a09b7223 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs @@ -41,6 +41,20 @@ namespace WireMock.Matchers.Request Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) }; } + /// + /// Initializes a new instance of the class. + /// + /// The name. + /// The matchers. + public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] params IMatcher[] matchers) + { + Check.NotNull(name, nameof(name)); + Check.NotNull(matchers, nameof(matchers)); + + Name = name; + Matchers = matchers; + } + /// /// Initializes a new instance of the class. /// @@ -48,6 +62,7 @@ namespace WireMock.Matchers.Request public RequestMessageHeaderMatcher([NotNull] params Func, bool>[] funcs) { Check.NotNull(funcs, nameof(funcs)); + _headerFuncs = funcs; } diff --git a/src/WireMock.Net/RequestBuilders/IBodyRequestBuilder.cs b/src/WireMock.Net/RequestBuilders/IBodyRequestBuilder.cs index d2c018ee..6757698e 100644 --- a/src/WireMock.Net/RequestBuilders/IBodyRequestBuilder.cs +++ b/src/WireMock.Net/RequestBuilders/IBodyRequestBuilder.cs @@ -16,10 +16,8 @@ namespace WireMock.RequestBuilders /// /// The matcher. /// - /// - /// The . - /// - IRequestMatcher WithBody([NotNull] IMatcher matcher); + /// The . + IRequestBuilder WithBody([NotNull] IMatcher matcher); /// /// The with body. @@ -27,10 +25,8 @@ namespace WireMock.RequestBuilders /// /// The body. /// - /// - /// The . - /// - IRequestMatcher WithBody(string body); + /// The . + IRequestBuilder WithBody(string body); /// /// The with body byte[]. @@ -38,10 +34,8 @@ namespace WireMock.RequestBuilders /// /// The body as byte[]. /// - /// - /// The . - /// - IRequestMatcher WithBody(byte[] body); + /// The . + IRequestBuilder WithBody(byte[] body); /// /// The with body string func. @@ -49,10 +43,8 @@ namespace WireMock.RequestBuilders /// /// The body string function. /// - /// - /// The . - /// - IRequestMatcher WithBody(Func body); + /// The . + IRequestBuilder WithBody(Func body); /// /// The with body byte[] func. @@ -60,9 +52,7 @@ namespace WireMock.RequestBuilders /// /// The body byte[] function. /// - /// - /// The . - /// - IRequestMatcher WithBody(Func body); + /// The . + IRequestBuilder WithBody(Func body); } } \ No newline at end of file diff --git a/src/WireMock.Net/RequestBuilders/IHeadersAndCookiesRequestBuilder.cs b/src/WireMock.Net/RequestBuilders/IHeadersAndCookiesRequestBuilder.cs index 4c98d83a..cd158fdf 100644 --- a/src/WireMock.Net/RequestBuilders/IHeadersAndCookiesRequestBuilder.cs +++ b/src/WireMock.Net/RequestBuilders/IHeadersAndCookiesRequestBuilder.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using JetBrains.Annotations; +using WireMock.Matchers; using WireMock.Matchers.Request; namespace WireMock.RequestBuilders @@ -16,30 +17,46 @@ namespace WireMock.RequestBuilders /// The name. /// The pattern. /// ignore Case - /// The . - IHeadersAndCookiesRequestBuilder WithHeader(string name, string pattern, bool ignoreCase = true); - - /// - /// The with header. - /// - /// The headers funcs. - /// The . - IHeadersAndCookiesRequestBuilder WithHeader([NotNull] params Func, bool>[] funcs); + /// The . + IRequestBuilder WithHeader([NotNull] string name, string pattern, bool ignoreCase = true); /// /// The with header. /// /// The name. - /// The pattern. - /// ignore Case - /// The . - IHeadersAndCookiesRequestBuilder WithCookie(string name, string pattern, bool ignoreCase = true); + /// The matchers. + /// The . + IRequestBuilder WithHeader([NotNull] string name, [NotNull] params IMatcher[] matchers); /// /// The with header. /// + /// The headers funcs. + /// The . + IRequestBuilder WithHeader([NotNull] params Func, bool>[] funcs); + + /// + /// The with cookie. + /// + /// The name. + /// The pattern. + /// ignore Case + /// The . + IRequestBuilder WithCookie([NotNull] string name, string pattern, bool ignoreCase = true); + + /// + /// The with cookie. + /// + /// The name. + /// The matchers. + /// The . + IRequestBuilder WithCookie([NotNull] string name, [NotNull] params IMatcher[] matchers); + + /// + /// The with cookie. + /// /// The funcs. - /// The . - IHeadersAndCookiesRequestBuilder WithCookie([NotNull] params Func, bool>[] cookieFuncs); + /// The . + IRequestBuilder WithCookie([NotNull] params Func, bool>[] cookieFuncs); } } \ No newline at end of file diff --git a/src/WireMock.Net/RequestBuilders/IMethodRequestBuilder.cs b/src/WireMock.Net/RequestBuilders/IMethodRequestBuilder.cs index 64c28952..5b1b1806 100644 --- a/src/WireMock.Net/RequestBuilders/IMethodRequestBuilder.cs +++ b/src/WireMock.Net/RequestBuilders/IMethodRequestBuilder.cs @@ -11,55 +11,55 @@ namespace WireMock.RequestBuilders /// The using get. /// /// - /// The . + /// The . /// - IHeadersAndCookiesRequestBuilder UsingGet(); + IRequestBuilder UsingGet(); /// /// The using post. /// /// - /// The . + /// The . /// - IHeadersAndCookiesRequestBuilder UsingPost(); + IRequestBuilder UsingPost(); /// /// The using delete. /// /// - /// The . + /// The . /// - IHeadersAndCookiesRequestBuilder UsingDelete(); + IRequestBuilder UsingDelete(); /// /// The using put. /// /// - /// The . + /// The . /// - IHeadersAndCookiesRequestBuilder UsingPut(); + IRequestBuilder UsingPut(); /// /// The using head. /// /// - /// The . + /// The . /// - IHeadersAndCookiesRequestBuilder UsingHead(); + IRequestBuilder UsingHead(); /// /// The using any verb. /// /// - /// The . + /// The . /// - IHeadersAndCookiesRequestBuilder UsingAnyVerb(); + IRequestBuilder UsingAnyVerb(); /// /// The using verb. /// /// The verb. - /// The . - IHeadersAndCookiesRequestBuilder UsingVerb([NotNull] params string[] verbs); + /// The . + IRequestBuilder UsingVerb([NotNull] params string[] verbs); } } \ No newline at end of file diff --git a/src/WireMock.Net/RequestBuilders/IParamsRequestBuilder.cs b/src/WireMock.Net/RequestBuilders/IParamsRequestBuilder.cs index 3c6b563c..97fedf1d 100644 --- a/src/WireMock.Net/RequestBuilders/IParamsRequestBuilder.cs +++ b/src/WireMock.Net/RequestBuilders/IParamsRequestBuilder.cs @@ -20,16 +20,14 @@ namespace WireMock.RequestBuilders /// /// The values. /// - /// - /// The . - /// - IRequestMatcher WithParam([NotNull] string key, params string[] values); + /// The . + IRequestBuilder WithParam([NotNull] string key, params string[] values); /// /// The with parameters. /// /// The funcs. - /// The . - IRequestMatcher WithParam([NotNull] params Func>, bool>[] funcs); + /// The . + IRequestBuilder WithParam([NotNull] params Func>, bool>[] funcs); } } \ No newline at end of file diff --git a/src/WireMock.Net/RequestBuilders/IUrlAndPathRequestBuilder.cs b/src/WireMock.Net/RequestBuilders/IUrlAndPathRequestBuilder.cs index 6093ad55..31e61886 100644 --- a/src/WireMock.Net/RequestBuilders/IUrlAndPathRequestBuilder.cs +++ b/src/WireMock.Net/RequestBuilders/IUrlAndPathRequestBuilder.cs @@ -13,42 +13,42 @@ namespace WireMock.RequestBuilders /// The with url. /// /// The matchers. - /// The . - IUrlAndPathRequestBuilder WithUrl([NotNull] params IMatcher[] matchers); + /// The . + IRequestBuilder WithUrl([NotNull] params IMatcher[] matchers); /// /// The with url. /// /// The urls. - /// The . - IUrlAndPathRequestBuilder WithUrl([NotNull] params string[] urls); + /// The . + IRequestBuilder WithUrl([NotNull] params string[] urls); /// /// The with url. /// /// The url funcs. - /// The . - IUrlAndPathRequestBuilder WithUrl([NotNull] params Func[] funcs); + /// The . + IRequestBuilder WithUrl([NotNull] params Func[] funcs); /// /// The with path. /// /// The matchers. - /// The . - IUrlAndPathRequestBuilder WithPath([NotNull] params IMatcher[] matchers); + /// The . + IRequestBuilder WithPath([NotNull] params IMatcher[] matchers); /// /// The with path. /// /// The paths. - /// The . - IUrlAndPathRequestBuilder WithPath([NotNull] params string[] paths); + /// The . + IRequestBuilder WithPath([NotNull] params string[] paths); /// /// The with path. /// /// The path func. - /// The . - IUrlAndPathRequestBuilder WithPath([NotNull] params Func[] func); + /// The . + IRequestBuilder WithPath([NotNull] params Func[] func); } } \ No newline at end of file diff --git a/src/WireMock.Net/RequestBuilders/Request.cs b/src/WireMock.Net/RequestBuilders/Request.cs index 9c613a5b..0f75c863 100644 --- a/src/WireMock.Net/RequestBuilders/Request.cs +++ b/src/WireMock.Net/RequestBuilders/Request.cs @@ -57,8 +57,8 @@ namespace WireMock.RequestBuilders /// The with url. /// /// The matchers. - /// The . - public IUrlAndPathRequestBuilder WithUrl(params IMatcher[] matchers) + /// The . + public IRequestBuilder WithUrl(params IMatcher[] matchers) { _requestMatchers.Add(new RequestMessageUrlMatcher(matchers)); return this; @@ -68,8 +68,8 @@ namespace WireMock.RequestBuilders /// The with url. /// /// The urls. - /// The . - public IUrlAndPathRequestBuilder WithUrl(params string[] urls) + /// The . + public IRequestBuilder WithUrl(params string[] urls) { _requestMatchers.Add(new RequestMessageUrlMatcher(urls)); return this; @@ -79,8 +79,8 @@ namespace WireMock.RequestBuilders /// The with url. /// /// The url func. - /// The . - public IUrlAndPathRequestBuilder WithUrl(params Func[] funcs) + /// The . + public IRequestBuilder WithUrl(params Func[] funcs) { _requestMatchers.Add(new RequestMessageUrlMatcher(funcs)); return this; @@ -90,8 +90,8 @@ namespace WireMock.RequestBuilders /// The with url. /// /// The matcher. - /// The . - public IUrlAndPathRequestBuilder WithPath(params IMatcher[] matcher) + /// The . + public IRequestBuilder WithPath(params IMatcher[] matcher) { _requestMatchers.Add(new RequestMessagePathMatcher(matcher)); return this; @@ -101,8 +101,8 @@ namespace WireMock.RequestBuilders /// The with path. /// /// The path. - /// The . - public IUrlAndPathRequestBuilder WithPath(params string[] paths) + /// The . + public IRequestBuilder WithPath(params string[] paths) { _requestMatchers.Add(new RequestMessagePathMatcher(paths)); return this; @@ -112,8 +112,8 @@ namespace WireMock.RequestBuilders /// The with path. /// /// The path func. - /// The . - public IUrlAndPathRequestBuilder WithPath(params Func[] funcs) + /// The . + public IRequestBuilder WithPath(params Func[] funcs) { _requestMatchers.Add(new RequestMessagePathMatcher(funcs)); return this; @@ -123,9 +123,9 @@ namespace WireMock.RequestBuilders /// The using get. /// /// - /// The . + /// The . /// - public IHeadersAndCookiesRequestBuilder UsingGet() + public IRequestBuilder UsingGet() { _requestMatchers.Add(new RequestMessageMethodMatcher("get")); return this; @@ -135,9 +135,9 @@ namespace WireMock.RequestBuilders /// The using post. /// /// - /// The . + /// The . /// - public IHeadersAndCookiesRequestBuilder UsingPost() + public IRequestBuilder UsingPost() { _requestMatchers.Add(new RequestMessageMethodMatcher("post")); return this; @@ -147,9 +147,9 @@ namespace WireMock.RequestBuilders /// The using put. /// /// - /// The . + /// The . /// - public IHeadersAndCookiesRequestBuilder UsingPut() + public IRequestBuilder UsingPut() { _requestMatchers.Add(new RequestMessageMethodMatcher("put")); return this; @@ -159,9 +159,9 @@ namespace WireMock.RequestBuilders /// The using delete. /// /// - /// The . + /// The . /// - public IHeadersAndCookiesRequestBuilder UsingDelete() + public IRequestBuilder UsingDelete() { _requestMatchers.Add(new RequestMessageMethodMatcher("delete")); return this; @@ -170,10 +170,8 @@ namespace WireMock.RequestBuilders /// /// The using head. /// - /// - /// The . - /// - public IHeadersAndCookiesRequestBuilder UsingHead() + /// The . + public IRequestBuilder UsingHead() { _requestMatchers.Add(new RequestMessageMethodMatcher("head")); return this; @@ -183,9 +181,9 @@ namespace WireMock.RequestBuilders /// The using any verb. /// /// - /// The . + /// The . /// - public IHeadersAndCookiesRequestBuilder UsingAnyVerb() + public IRequestBuilder UsingAnyVerb() { var matchers = _requestMatchers.Where(m => m is RequestMessageMethodMatcher).ToList(); foreach (var matcher in matchers) @@ -200,8 +198,8 @@ namespace WireMock.RequestBuilders /// The using verb. /// /// The verbs. - /// The . - public IHeadersAndCookiesRequestBuilder UsingVerb(params string[] verbs) + /// The . + public IRequestBuilder UsingVerb(params string[] verbs) { _requestMatchers.Add(new RequestMessageMethodMatcher(verbs)); return this; @@ -213,10 +211,8 @@ namespace WireMock.RequestBuilders /// /// The body. /// - /// - /// The . - /// - public IRequestMatcher WithBody(string body) + /// The . + public IRequestBuilder WithBody(string body) { _requestMatchers.Add(new RequestMessageBodyMatcher(body)); return this; @@ -228,10 +224,8 @@ namespace WireMock.RequestBuilders /// /// The body as byte[]. /// - /// - /// The . - /// - public IRequestMatcher WithBody(byte[] body) + /// The . + public IRequestBuilder WithBody(byte[] body) { _requestMatchers.Add(new RequestMessageBodyMatcher(body)); return this; @@ -243,10 +237,8 @@ namespace WireMock.RequestBuilders /// /// The body function. /// - /// - /// The . - /// - public IRequestMatcher WithBody(Func func) + /// The . + public IRequestBuilder WithBody(Func func) { _requestMatchers.Add(new RequestMessageBodyMatcher(func)); return this; @@ -258,10 +250,8 @@ namespace WireMock.RequestBuilders /// /// The body function. /// - /// - /// The . - /// - public IRequestMatcher WithBody(Func func) + /// The . + public IRequestBuilder WithBody(Func func) { _requestMatchers.Add(new RequestMessageBodyMatcher(func)); return this; @@ -271,10 +261,8 @@ namespace WireMock.RequestBuilders /// The with body. /// /// The matcher. - /// - /// The . - /// - public IRequestMatcher WithBody(IMatcher matcher) + /// The . + public IRequestBuilder WithBody(IMatcher matcher) { _requestMatchers.Add(new RequestMessageBodyMatcher(matcher)); return this; @@ -289,12 +277,10 @@ namespace WireMock.RequestBuilders /// /// The values. /// - /// - /// The . - /// - public IRequestMatcher WithParam(string key, params string[] values) + /// The . + public IRequestBuilder WithParam(string key, params string[] values) { - _requestMatchers.Add(new RequestMessageParamMatcher(key, values.ToList())); + _requestMatchers.Add(new RequestMessageParamMatcher(key, values)); return this; } @@ -302,8 +288,8 @@ namespace WireMock.RequestBuilders /// The with parameters. /// /// The funcs. - /// The . - public IRequestMatcher WithParam(params Func>, bool>[] funcs) + /// The . + public IRequestBuilder WithParam(params Func>, bool>[] funcs) { _requestMatchers.Add(new RequestMessageParamMatcher(funcs)); return this; @@ -315,19 +301,31 @@ namespace WireMock.RequestBuilders /// The name. /// The pattern. /// if set to true [ignore case]. - /// - public IHeadersAndCookiesRequestBuilder WithHeader(string name, string pattern, bool ignoreCase = true) + /// The . + public IRequestBuilder WithHeader(string name, string pattern, bool ignoreCase = true) { _requestMatchers.Add(new RequestMessageHeaderMatcher(name, pattern, ignoreCase)); return this; } + /// + /// With header. + /// + /// The name. + /// The matchers. + /// The . + public IRequestBuilder WithHeader(string name, params IMatcher[] matchers) + { + _requestMatchers.Add(new RequestMessageHeaderMatcher(name, matchers)); + return this; + } + /// /// With header. /// /// The funcs. - /// - public IHeadersAndCookiesRequestBuilder WithHeader(params Func, bool>[] funcs) + /// The . + public IRequestBuilder WithHeader(params Func, bool>[] funcs) { _requestMatchers.Add(new RequestMessageHeaderMatcher(funcs)); return this; @@ -339,19 +337,31 @@ namespace WireMock.RequestBuilders /// The name. /// The pattern. /// if set to true [ignore case]. - /// - public IHeadersAndCookiesRequestBuilder WithCookie(string name, string pattern, bool ignoreCase = true) + /// The . + public IRequestBuilder WithCookie(string name, string pattern, bool ignoreCase = true) { _requestMatchers.Add(new RequestMessageCookieMatcher(name, pattern, ignoreCase)); return this; } + /// + /// With cookie. + /// + /// The name. + /// The matchers. + /// The . + public IRequestBuilder WithCookie(string name, params IMatcher[] matchers) + { + _requestMatchers.Add(new RequestMessageCookieMatcher(name, matchers)); + return this; + } + /// /// With header. /// /// The funcs. - /// - public IHeadersAndCookiesRequestBuilder WithCookie(params Func, bool>[] funcs) + /// The . + public IRequestBuilder WithCookie(params Func, bool>[] funcs) { _requestMatchers.Add(new RequestMessageCookieMatcher(funcs)); return this; diff --git a/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs index e40ba557..8c589be4 100644 --- a/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs +++ b/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs @@ -12,15 +12,22 @@ namespace WireMock.ResponseBuilders /// The with body. /// /// The body. - /// A . - ITransformResponseBuilder WithBody([NotNull] string body); + /// A . + IResponseBuilder WithBody([NotNull] string body); + + /// + /// The with body. + /// + /// The body. + /// A . + IResponseBuilder WithBodyAsJson([NotNull] object body); /// /// The with body as base64. /// /// The body asbase64. /// The Encoding. - /// A . - ITransformResponseBuilder WithBodyAsBase64([NotNull] string bodyAsbase64, [CanBeNull] Encoding encoding = null); + /// A . + IResponseBuilder WithBodyAsBase64([NotNull] string bodyAsbase64, [CanBeNull] Encoding encoding = null); } } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/IHeadersResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/IHeadersResponseBuilder.cs index 3d62b949..32300e1d 100644 --- a/src/WireMock.Net/ResponseBuilders/IHeadersResponseBuilder.cs +++ b/src/WireMock.Net/ResponseBuilders/IHeadersResponseBuilder.cs @@ -1,4 +1,6 @@ -using JetBrains.Annotations; +using System.Collections; +using System.Collections.Generic; +using JetBrains.Annotations; namespace WireMock.ResponseBuilders { @@ -12,7 +14,14 @@ namespace WireMock.ResponseBuilders /// /// The name. /// The value. - /// The . - IHeadersResponseBuilder WithHeader([NotNull] string name, string value); + /// The . + IResponseBuilder WithHeader([NotNull] string name, string value); + + /// + /// The with headers. + /// + /// The headers. + /// The . + IResponseBuilder WithHeaders([NotNull] IDictionary headers); } } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/IStatusCodeResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/IStatusCodeResponseBuilder.cs index 64ae0461..664aeaae 100644 --- a/src/WireMock.Net/ResponseBuilders/IStatusCodeResponseBuilder.cs +++ b/src/WireMock.Net/ResponseBuilders/IStatusCodeResponseBuilder.cs @@ -13,8 +13,8 @@ namespace WireMock.ResponseBuilders /// /// The code. /// - /// The . - IHeadersResponseBuilder WithStatusCode(int code); + /// The . + IResponseBuilder WithStatusCode(int code); /// /// The with status code. @@ -22,19 +22,19 @@ namespace WireMock.ResponseBuilders /// /// The code. /// - /// The . - IHeadersResponseBuilder WithStatusCode(HttpStatusCode code); + /// The . + IResponseBuilder WithStatusCode(HttpStatusCode code); /// /// The with Success status code (200). /// /// The . - IHeadersResponseBuilder WithSuccess(); + IResponseBuilder WithSuccess(); /// /// The with NotFound status code (404). /// /// The . - IHeadersResponseBuilder WithNotFound(); + IResponseBuilder WithNotFound(); } } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/ITransformResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/ITransformResponseBuilder.cs index ff4725a2..0db91f2c 100644 --- a/src/WireMock.Net/ResponseBuilders/ITransformResponseBuilder.cs +++ b/src/WireMock.Net/ResponseBuilders/ITransformResponseBuilder.cs @@ -9,8 +9,8 @@ /// The with transformer. /// /// - /// The . + /// The . /// - IDelayResponseBuilder WithTransformer(); + IResponseBuilder WithTransformer(); } } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/Response.cs b/src/WireMock.Net/ResponseBuilders/Response.cs index f63bcacc..4ad980e1 100644 --- a/src/WireMock.Net/ResponseBuilders/Response.cs +++ b/src/WireMock.Net/ResponseBuilders/Response.cs @@ -1,10 +1,13 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; using System.Net; using System.Text; using System.Threading.Tasks; using HandlebarsDotNet; using JetBrains.Annotations; +using Newtonsoft.Json; using WireMock.Validation; namespace WireMock.ResponseBuilders @@ -15,7 +18,14 @@ namespace WireMock.ResponseBuilders public class Response : IResponseBuilder { private TimeSpan _delay = TimeSpan.Zero; - private bool _useTransformer; + + /// + /// Gets a value indicating whether [use transformer]. + /// + /// + /// true if [use transformer]; otherwise, false. + /// + public bool UseTransformer { get; private set; } /// /// Gets the response message. @@ -64,9 +74,9 @@ namespace WireMock.ResponseBuilders /// The with status code. /// /// The code. - /// A .\ + /// A .\ [PublicAPI] - public IHeadersResponseBuilder WithStatusCode(int code) + public IResponseBuilder WithStatusCode(int code) { ResponseMessage.StatusCode = code; return this; @@ -76,9 +86,9 @@ namespace WireMock.ResponseBuilders /// The with status code. /// /// The code. - /// A . + /// A . [PublicAPI] - public IHeadersResponseBuilder WithStatusCode(HttpStatusCode code) + public IResponseBuilder WithStatusCode(HttpStatusCode code) { return WithStatusCode((int)code); } @@ -86,9 +96,9 @@ namespace WireMock.ResponseBuilders /// /// The with Success status code (200). /// - /// + /// A . [PublicAPI] - public IHeadersResponseBuilder WithSuccess() + public IResponseBuilder WithSuccess() { return WithStatusCode((int)HttpStatusCode.OK); } @@ -98,7 +108,7 @@ namespace WireMock.ResponseBuilders /// /// The . [PublicAPI] - public IHeadersResponseBuilder WithNotFound() + public IResponseBuilder WithNotFound() { return WithStatusCode((int)HttpStatusCode.NotFound); } @@ -108,8 +118,8 @@ namespace WireMock.ResponseBuilders /// /// The name. /// The value. - /// The . - public IHeadersResponseBuilder WithHeader(string name, string value) + /// The . + public IResponseBuilder WithHeader(string name, string value) { Check.NotNull(name, nameof(name)); @@ -117,12 +127,23 @@ namespace WireMock.ResponseBuilders return this; } + /// + /// The with headers. + /// + /// The headers. + /// + public IResponseBuilder WithHeaders(IDictionary headers) + { + ResponseMessage.Headers = headers; + return this; + } + /// /// The with body. /// /// The body. - /// A . - public ITransformResponseBuilder WithBody(string body) + /// A . + public IResponseBuilder WithBody(string body) { Check.NotNull(body, nameof(body)); @@ -130,13 +151,26 @@ namespace WireMock.ResponseBuilders return this; } + /// + /// The with body (AsJson object). + /// + /// The body. + /// A . + public IResponseBuilder WithBodyAsJson(object body) + { + Check.NotNull(body, nameof(body)); + + ResponseMessage.Body = JsonConvert.SerializeObject(body, new JsonSerializerSettings { Formatting = Formatting.None, NullValueHandling = NullValueHandling.Ignore } ); + return this; + } + /// /// The with body as base64. /// /// The body asbase64. /// The Encoding. - /// A . - public ITransformResponseBuilder WithBodyAsBase64(string bodyAsbase64, Encoding encoding = null) + /// A . + public IResponseBuilder WithBodyAsBase64(string bodyAsbase64, Encoding encoding = null) { Check.NotNull(bodyAsbase64, nameof(bodyAsbase64)); @@ -150,9 +184,9 @@ namespace WireMock.ResponseBuilders /// /// The . /// - public IDelayResponseBuilder WithTransformer() + public IResponseBuilder WithTransformer() { - _useTransformer = true; + UseTransformer = true; return this; } @@ -183,7 +217,7 @@ namespace WireMock.ResponseBuilders public async Task ProvideResponse(RequestMessage requestMessage) { ResponseMessage responseMessage; - if (_useTransformer) + if (UseTransformer) { responseMessage = new ResponseMessage { StatusCode = ResponseMessage.StatusCode, BodyOriginal = ResponseMessage.Body }; diff --git a/src/WireMock.Net/Server/FluentMockServer.Admin.cs b/src/WireMock.Net/Server/FluentMockServer.Admin.cs index 5b2b7375..233f0c99 100644 --- a/src/WireMock.Net/Server/FluentMockServer.Admin.cs +++ b/src/WireMock.Net/Server/FluentMockServer.Admin.cs @@ -17,14 +17,128 @@ namespace WireMock.Server /// public partial class FluentMockServer { + private readonly JsonSerializerSettings _settings = new JsonSerializerSettings + { + Formatting = Formatting.None, + NullValueHandling = NullValueHandling.Ignore + }; + private void InitAdmin() { Given(Request.Create().WithUrl("/__admin/mappings").UsingGet()).RespondWith(new DynamicResponseProvider(MappingsGet)); + Given(Request.Create().WithUrl("/__admin/mappings").UsingPost()).RespondWith(new DynamicResponseProvider(MappingsPost)); Given(Request.Create().WithUrl("/__admin/requests").UsingGet()).RespondWith(new DynamicResponseProvider(RequestsGet)); } - private ResponseMessage RequestsGet() + private ResponseMessage MappingsGet(RequestMessage requestMessage) + { + var result = new List(); + foreach (var mapping in Mappings.Where(m => !(m.Provider is DynamicResponseProvider))) + { + var model = ToMappingModel(mapping); + result.Add(model); + } + + return ToJson(result); + } + + private ResponseMessage MappingsPost(RequestMessage requestMessage) + { + var mappingModel = JsonConvert.DeserializeObject(requestMessage.Body); + + if (mappingModel.Request == null) + return new ResponseMessage { StatusCode = 400, Body = "Request missing" }; + + if (mappingModel.Response == null) + return new ResponseMessage { StatusCode = 400, Body = "Response missing" }; + + var requestBuilder = InitRequestBuilder(mappingModel); + var responseBuilder = InitResponseBuilder(mappingModel); + + IRespondWithAProviderGuid respondProvider = Given(requestBuilder); + + if (mappingModel.Guid != null && mappingModel.Guid != Guid.Empty) + respondProvider = respondProvider.WithGuid(mappingModel.Guid.Value); + + respondProvider.RespondWith(responseBuilder); + + return new ResponseMessage { Body = "Mapping added" }; + } + + private IRequestBuilder InitRequestBuilder(MappingModel mappingModel) + { + IRequestBuilder requestBuilder = Request.Create(); + string url = mappingModel.Request.Url as string; + if (url != null) + requestBuilder = requestBuilder.WithUrl(url); + else + requestBuilder = requestBuilder.WithUrl("/*"); + //UrlModel urlModel = mappingModel.Request.Url as UrlModel; + //if (urlModel?.Matchers != null) + // builder = builder.WithUrl(urlModel.Matchers.Select(Map).ToArray()); + + if (mappingModel.Request.Methods != null) + requestBuilder = requestBuilder.UsingVerb(mappingModel.Request.Methods); + else + requestBuilder = requestBuilder.UsingAnyVerb(); + + if (mappingModel.Request.Headers != null) + { + foreach (var headerModel in mappingModel.Request.Headers.Where(h => h.Matchers != null)) + { + requestBuilder = requestBuilder.WithHeader(headerModel.Name, headerModel.Matchers.Select(Map).ToArray()); + } + } + + if (mappingModel.Request.Cookies != null) + { + foreach (var cookieModel in mappingModel.Request.Cookies.Where(c => c.Matchers != null)) + { + requestBuilder = requestBuilder.WithCookie(cookieModel.Name, cookieModel.Matchers.Select(Map).ToArray()); + } + } + + if (mappingModel.Request.Params != null) + { + foreach (var paramModel in mappingModel.Request.Params.Where(p => p.Values != null)) + { + requestBuilder = requestBuilder.WithParam(paramModel.Name, paramModel.Values.ToArray()); + } + } + + if (mappingModel.Request.Body?.Matcher != null) + { + var bodyMatcher = Map(mappingModel.Request.Body.Matcher); + requestBuilder = requestBuilder.WithBody(bodyMatcher); + } + return requestBuilder; + } + + + private IResponseBuilder InitResponseBuilder(MappingModel mappingModel) + { + IResponseBuilder responseBuilder = Response.Create(); + + if (mappingModel.Response.StatusCode.HasValue) + responseBuilder = responseBuilder.WithStatusCode(mappingModel.Response.StatusCode.Value); + + if (mappingModel.Response.Headers != null) + responseBuilder = responseBuilder.WithHeaders(mappingModel.Response.Headers); + + if (mappingModel.Response.Body != null) + responseBuilder = responseBuilder.WithBody(mappingModel.Response.Body); + else if (mappingModel.Response.BodyAsJson != null) + responseBuilder = responseBuilder.WithBodyAsJson(mappingModel.Response.BodyAsJson); + else if (mappingModel.Response.BodyAsBase64 != null) + responseBuilder = responseBuilder.WithBodyAsBase64(mappingModel.Response.BodyAsBase64); + + if (mappingModel.Response.UseTransformer) + responseBuilder = responseBuilder.WithTransformer(); + return responseBuilder; + } + + private ResponseMessage RequestsGet(RequestMessage requestMessage) { var result = new List(); foreach (var logEntry in LogEntries.Where(r => !r.RequestMessage.Path.StartsWith("/__admin/"))) @@ -58,68 +172,61 @@ namespace WireMock.Server return ToJson(result); } - private ResponseMessage MappingsGet() + private MappingModel ToMappingModel(Mapping mapping) { - var result = new List(); - foreach (var mapping in Mappings.Where(m => !(m.Provider is DynamicResponseProvider))) + var request = (Request)mapping.RequestMatcher; + var response = (Response)mapping.Provider; + + var urlMatchers = request.GetRequestMessageMatchers(); + var headerMatchers = request.GetRequestMessageMatchers(); + var cookieMatchers = request.GetRequestMessageMatchers(); + var paramsMatchers = request.GetRequestMessageMatchers(); + var bodyMatcher = request.GetRequestMessageMatcher(); + var methodMatcher = request.GetRequestMessageMatcher(); + + return new MappingModel { - var request = (Request) mapping.RequestMatcher; - var urlMatchers = request.GetRequestMessageMatchers(); - var headerMatchers = request.GetRequestMessageMatchers(); - var cookieMatchers = request.GetRequestMessageMatchers(); - var paramsMatchers = request.GetRequestMessageMatchers(); - var bodyMatcher = request.GetRequestMessageMatcher(); - var methodMatcher = request.GetRequestMessageMatcher(); - - var response = (Response) mapping.Provider; - - var model = new MappingModel + Guid = mapping.Guid, + Request = new RequestModel { - Guid = Guid.NewGuid(), - Request = new RequestModel + Url = new UrlModel { - Url = new UrlModel - { - Matchers = urlMatchers != null ? Map(urlMatchers.Where(m => m.Matchers != null).SelectMany(m => m.Matchers)) : null - }, - Methods = methodMatcher != null ? methodMatcher.Methods : new [] { "any" }, - Headers = headerMatchers?.Select(hm => new HeaderModel - { - Name = hm.Name, - Matchers = Map(hm.Matchers) - }).ToList(), - Cookies = cookieMatchers?.Select(hm => new CookieModel - { - Name = hm.Name, - Matchers = Map(hm.Matchers) - }).ToList(), - Params = paramsMatchers?.Select(hm => new ParamModel - { - Name = hm.Key, - Values = hm.Values?.ToList() - }).ToList(), - Body = new BodyModel - { - Matcher = bodyMatcher != null ? Map(bodyMatcher.Matcher) : null - } + Matchers = urlMatchers != null ? Map(urlMatchers.Where(m => m.Matchers != null).SelectMany(m => m.Matchers)) : null }, - Response = new ResponseModel + Methods = methodMatcher != null ? methodMatcher.Methods : new[] { "any" }, + Headers = headerMatchers?.Select(hm => new HeaderModel { - StatusCode = response.ResponseMessage.StatusCode, - Headers = response.ResponseMessage.Headers, - Body = response.ResponseMessage.Body + Name = hm.Name, + Matchers = Map(hm.Matchers) + }).ToList(), + Cookies = cookieMatchers?.Select(hm => new CookieModel + { + Name = hm.Name, + Matchers = Map(hm.Matchers) + }).ToList(), + Params = paramsMatchers?.Select(hm => new ParamModel + { + Name = hm.Key, + Values = hm.Values?.ToList() + }).ToList(), + Body = new BodyModel + { + Matcher = bodyMatcher != null ? Map(bodyMatcher.Matcher) : null } - }; - - result.Add(model); - } - - return ToJson(result); + }, + Response = new ResponseModel + { + StatusCode = response.ResponseMessage.StatusCode, + Headers = response.ResponseMessage.Headers, + Body = response.ResponseMessage.Body, + UseTransformer = response.UseTransformer + } + }; } - private IList Map([CanBeNull] IEnumerable matchers) + private MatcherModel[] Map([CanBeNull] IEnumerable matchers) { - return matchers?.Select(Map).Where(x => x != null).ToList(); + return matchers?.Select(Map).Where(x => x != null).ToArray(); } private MatcherModel Map([CanBeNull] IMatcher matcher) @@ -134,11 +241,32 @@ namespace WireMock.Server }; } + private IMatcher Map([CanBeNull] MatcherModel matcher) + { + if (matcher == null) + return null; + + switch (matcher.Name) + { + case "RegExMatcher": + return new RegexMatcher(matcher.Pattern); + + case "JsonPathMatcher": + return new JsonPathMatcher(matcher.Pattern); + + case "XPathMatcher": + return new XPathMatcher(matcher.Pattern); + + default: + return new WildcardMatcher(matcher.Pattern, matcher.IgnoreCase == true); + } + } + private ResponseMessage ToJson(T result) { return new ResponseMessage { - Body = JsonConvert.SerializeObject(result, Formatting.Indented), + Body = JsonConvert.SerializeObject(result, _settings), StatusCode = 200, Headers = new Dictionary { { "Content-Type", "application/json" } } }; diff --git a/src/WireMock.Net/Server/FluentMockServer.cs b/src/WireMock.Net/Server/FluentMockServer.cs index a5e667a5..2fd4dcbf 100644 --- a/src/WireMock.Net/Server/FluentMockServer.cs +++ b/src/WireMock.Net/Server/FluentMockServer.cs @@ -167,8 +167,8 @@ namespace WireMock.Server /// The given. /// /// The request matcher. - /// The . - public IRespondWithAProvider Given(IRequestMatcher requestMatcher) + /// The . + public IRespondWithAProviderGuid Given(IRequestMatcher requestMatcher) { return new RespondWithAProvider(RegisterMapping, requestMatcher); } diff --git a/src/WireMock.Net/Server/IRespondWithAProviderGuid.cs b/src/WireMock.Net/Server/IRespondWithAProviderGuid.cs new file mode 100644 index 00000000..b3ba38e0 --- /dev/null +++ b/src/WireMock.Net/Server/IRespondWithAProviderGuid.cs @@ -0,0 +1,17 @@ +using System; + +namespace WireMock.Server +{ + /// + /// IRespondWithAProviderGuid + /// + public interface IRespondWithAProviderGuid : IRespondWithAProvider + { + /// + /// Define a unique identifier for this mapping. + /// + /// The unique identifier. + /// The . + IRespondWithAProviderGuid WithGuid(Guid guid); + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Server/RespondWithAProvider.cs b/src/WireMock.Net/Server/RespondWithAProvider.cs index 2cb78aad..d99b4657 100644 --- a/src/WireMock.Net/Server/RespondWithAProvider.cs +++ b/src/WireMock.Net/Server/RespondWithAProvider.cs @@ -1,12 +1,15 @@ -using WireMock.Matchers.Request; +using System; +using WireMock.Matchers.Request; namespace WireMock.Server { /// /// The respond with a provider. /// - internal class RespondWithAProvider : IRespondWithAProvider + internal class RespondWithAProvider : IRespondWithAProviderGuid { + private Guid? _guid; + /// /// The _registration callback. /// @@ -36,7 +39,20 @@ namespace WireMock.Server /// public void RespondWith(IResponseProvider provider) { - _registrationCallback(new Mapping(_requestMatcher, provider)); + var mappingGuid = _guid ?? Guid.NewGuid(); + _registrationCallback(new Mapping(mappingGuid, _requestMatcher, provider)); + } + + /// + /// Define a unique identifier for this mapping. + /// + /// The unique identifier. + /// The . + public IRespondWithAProviderGuid WithGuid(Guid guid) + { + _guid = guid; + + return this; } } } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/FluentMockServerTests.cs b/test/WireMock.Net.Tests/FluentMockServerTests.cs index aa54eaf5..db80df85 100644 --- a/test/WireMock.Net.Tests/FluentMockServerTests.cs +++ b/test/WireMock.Net.Tests/FluentMockServerTests.cs @@ -22,9 +22,11 @@ namespace WireMock.Net.Tests [Test] public void FluentMockServer_get_routes() { + var guid = Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05"); _server = FluentMockServer.Start(); _server.Given(Request.Create().WithUrl("/foo1").UsingGet()) + .WithGuid(guid) .RespondWith(Response.Create().WithStatusCode(201).WithBody("1")); _server.Given(Request.Create().WithUrl("/foo2").UsingGet()) @@ -32,9 +34,14 @@ namespace WireMock.Net.Tests var routes = _server.Mappings; - Check.That(routes).HasSize(2); - Check.That(routes.First().RequestMatcher).IsNotNull(); - Check.That(routes.First().Provider).IsNotNull(); + var enumerable = routes.ToArray(); + Check.That(enumerable).HasSize(2); + + Check.That(enumerable.First().RequestMatcher).IsNotNull(); + Check.That(enumerable.First().Provider).IsNotNull(); + Check.That(enumerable.First().Guid).Equals(guid); + + Check.That(enumerable[1].Guid).Not.Equals(guid); } [Test]