From 77a162afe405c56c36d17077ed26163dc12006bf Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 3 May 2019 13:48:14 +0200 Subject: [PATCH 1/4] Dynamic response files using Handlebars templating (#270) --- Directory.Build.props | 2 +- src/WireMock.Net/ResponseBuilders/Response.cs | 2 +- .../Server/FluentMockServer.Admin.cs | 10 ++-- .../ResponseMessageTransformer.cs | 49 ++++++++++++------- .../ResponseWithHandlebarsTests.cs | 17 +++++++ 5 files changed, 55 insertions(+), 25 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 36db2bfbe..085afa887 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ - 1.0.14 + 1.0.15 diff --git a/src/WireMock.Net/ResponseBuilders/Response.cs b/src/WireMock.Net/ResponseBuilders/Response.cs index 3df506907..82ba0852e 100644 --- a/src/WireMock.Net/ResponseBuilders/Response.cs +++ b/src/WireMock.Net/ResponseBuilders/Response.cs @@ -224,7 +224,7 @@ public IResponseBuilder WithBodyFromFile(string filename, bool cache = true) BodyAsFileIsCached = cache }; - if (cache) + if (cache && !UseTransformer) { ResponseMessage.BodyData.DetectedBodyType = BodyType.Bytes; ResponseMessage.BodyData.BodyAsBytes = _fileSystemHandler.ReadResponseBodyAsFile(filename); diff --git a/src/WireMock.Net/Server/FluentMockServer.Admin.cs b/src/WireMock.Net/Server/FluentMockServer.Admin.cs index 3ba9ebff1..1da20c3c5 100644 --- a/src/WireMock.Net/Server/FluentMockServer.Admin.cs +++ b/src/WireMock.Net/Server/FluentMockServer.Admin.cs @@ -722,6 +722,11 @@ private IResponseBuilder InitResponseBuilder(ResponseModel responseModel) responseBuilder = responseBuilder.WithDelay(responseModel.Delay.Value); } + if (responseModel.UseTransformer) + { + responseBuilder = responseBuilder.WithTransformer(); + } + if (!string.IsNullOrEmpty(responseModel.ProxyUrl)) { if (string.IsNullOrEmpty(responseModel.X509Certificate2ThumbprintOrSubjectName)) @@ -778,11 +783,6 @@ private IResponseBuilder InitResponseBuilder(ResponseModel responseModel) responseBuilder = responseBuilder.WithBodyFromFile(responseModel.BodyAsFile); } - if (responseModel.UseTransformer) - { - responseBuilder = responseBuilder.WithTransformer(); - } - return responseBuilder; } diff --git a/src/WireMock.Net/Transformers/ResponseMessageTransformer.cs b/src/WireMock.Net/Transformers/ResponseMessageTransformer.cs index cdd8ae823..e2c742dc4 100644 --- a/src/WireMock.Net/Transformers/ResponseMessageTransformer.cs +++ b/src/WireMock.Net/Transformers/ResponseMessageTransformer.cs @@ -1,9 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using HandlebarsDotNet; +using HandlebarsDotNet; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; using WireMock.Util; namespace WireMock.Transformers @@ -24,23 +24,24 @@ static ResponseMessageTransformer() public static ResponseMessage Transform(RequestMessage requestMessage, ResponseMessage original) { - bool bodyIsJson = original.BodyData.DetectedBodyType == BodyType.Json; var responseMessage = new ResponseMessage { StatusCode = original.StatusCode }; - if (!bodyIsJson) - { - responseMessage.BodyOriginal = original.BodyData.BodyAsString; - } - var template = new { request = requestMessage }; - if (!bodyIsJson) - { - TransformBodyAsString(template, original, responseMessage); - } - else + switch (original.BodyData.DetectedBodyType) { - TransformBodyAsJson(template, original, responseMessage); + case BodyType.Json: + TransformBodyAsJson(template, original, responseMessage); + break; + + case BodyType.File: + TransformBodyAsFile(template, original, responseMessage); + break; + + case BodyType.String: + responseMessage.BodyOriginal = original.BodyData.BodyAsString; + TransformBodyAsString(template, original, responseMessage); + break; } // Headers @@ -150,13 +151,25 @@ private static void ReplaceNodeValue(JToken node, string stringValue) private static void TransformBodyAsString(object template, ResponseMessage original, ResponseMessage responseMessage) { - var templateBody = HandlebarsContext.Compile(original.BodyData.BodyAsString); + var templateBodyAsString = HandlebarsContext.Compile(original.BodyData.BodyAsString); + + responseMessage.BodyData = new BodyData + { + DetectedBodyType = original.BodyData.DetectedBodyType, + DetectedBodyTypeFromContentType = original.BodyData.DetectedBodyTypeFromContentType, + BodyAsString = templateBodyAsString(template) + }; + } + + private static void TransformBodyAsFile(object template, ResponseMessage original, ResponseMessage responseMessage) + { + var templateBodyAsFile = HandlebarsContext.Compile(original.BodyData.BodyAsFile); responseMessage.BodyData = new BodyData { DetectedBodyType = original.BodyData.DetectedBodyType, DetectedBodyTypeFromContentType = original.BodyData.DetectedBodyTypeFromContentType, - BodyAsString = templateBody(template) + BodyAsFile = templateBodyAsFile(template) }; } } diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs index d609be147..31011f5b1 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs @@ -214,5 +214,22 @@ public async Task Response_ProvideResponse_Handlebars_WithBodyAsJson_ResultAsArr // Assert Check.That(JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson)).Equals("[\"first\",\"/foo_array\",\"test 1\",\"test 2\",\"last\"]"); } + + [Fact] + public async Task Response_ProvideResponse_Handlebars_WithBodyAsFile() + { + // Assign + var request = new RequestMessage(new UrlDetails("http://localhost/foo?MyUniqueNumber=1"), "GET", ClientIp); + + var response = Response.Create() + .WithTransformer() + .WithBodyFromFile(@"c:\\{{request.query.MyUniqueNumber}}\test.xml"); // why use a \\ here ? + + // Act + var responseMessage = await response.ProvideResponseAsync(request); + + // Assert + Check.That(responseMessage.BodyData.BodyAsFile).Equals(@"c:\1\test.xml"); + } } } \ No newline at end of file From a298738bc1bc3b269944d5edb5f301b46441b444 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 3 May 2019 16:00:14 +0200 Subject: [PATCH 2/4] * Response templating / transformation using Handlebars and extensions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 82988722a..bfa2eae5c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) w * Record/playback of stubs (proxying) * Per-request conditional proxying * Stateful behaviour simulation -* Response transformation +* Response templating / transformation using Handlebars and extensions ## Info | | | From d5499a773cca5057aee43e5b12c279e61aa01e67 Mon Sep 17 00:00:00 2001 From: Denis Storti Da Silva Date: Sat, 4 May 2019 18:02:36 +1000 Subject: [PATCH 3/4] Add unit test for JsonPath and BodyAsFile mapping (#272) --- .../ResponseWithHandlebarsTests.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs index 31011f5b1..fad6d28da 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs @@ -231,5 +231,32 @@ public async Task Response_ProvideResponse_Handlebars_WithBodyAsFile() // Assert Check.That(responseMessage.BodyData.BodyAsFile).Equals(@"c:\1\test.xml"); } + + [Fact] + public async Task Response_ProvideResponse_Handlebars_WithBodyAsFile_JsonPath() + { + // Assign + string jsonString = "{ \"MyUniqueNumber\": \"1\" }"; + var bodyData = new BodyData + { + BodyAsString = jsonString, + BodyAsJson = JsonConvert.DeserializeObject(jsonString), + DetectedBodyType = BodyType.Json, + DetectedBodyTypeFromContentType = BodyType.Json, + Encoding = Encoding.UTF8 + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, bodyData); + + string jsonPath = "\"$.MyUniqueNumber\""; + var response = Response.Create() + .WithTransformer() + .WithBodyFromFile(@"c:\\{{JsonPath.SelectToken request.body " + jsonPath + "}}\\test.json"); // why use a \\ here ? + + // Act + var responseMessage = await response.ProvideResponseAsync(request); + + // Assert + Check.That(responseMessage.BodyData.BodyAsFile).Equals(@"c:\1\test.json"); + } } } \ No newline at end of file From 062f0140b71989480a6d9bf4e2685fd5cf186980 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 4 May 2019 10:11:55 +0200 Subject: [PATCH 4/4] fix merge issue --- .../ResponseWithHandlebarsTests.cs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs index 121353ea4..fad6d28da 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs @@ -258,22 +258,5 @@ public async Task Response_ProvideResponse_Handlebars_WithBodyAsFile_JsonPath() // Assert Check.That(responseMessage.BodyData.BodyAsFile).Equals(@"c:\1\test.json"); } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_WithBodyAsFile() - { - // Assign - var request = new RequestMessage(new UrlDetails("http://localhost/foo?MyUniqueNumber=1"), "GET", ClientIp); - - var response = Response.Create() - .WithTransformer() - .WithBodyFromFile(@"c:\\{{request.query.MyUniqueNumber}}\test.xml"); // why use a \\ here ? - - // Act - var responseMessage = await response.ProvideResponseAsync(request); - - // Assert - Check.That(responseMessage.BodyData.BodyAsFile).Equals(@"c:\1\test.xml"); - } } } \ No newline at end of file