diff --git a/examples/WireMock.Net.Client/Properties/launchSettings.json b/examples/WireMock.Net.Client/Properties/launchSettings.json new file mode 100644 index 00000000..33504c94 --- /dev/null +++ b/examples/WireMock.Net.Client/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "WSL": { + "commandName": "WSL2", + "distributionName": "" + } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Http/WebhookSender.cs b/src/WireMock.Net/Http/WebhookSender.cs index 73295844..e7444816 100644 --- a/src/WireMock.Net/Http/WebhookSender.cs +++ b/src/WireMock.Net/Http/WebhookSender.cs @@ -44,37 +44,41 @@ internal class WebhookSender IBodyData? bodyData; IDictionary>? headers; + string webhookRequestUrl; if (webhookRequest.UseTransformer == true) { - ITransformer responseMessageTransformer; + ITransformer transformer; switch (webhookRequest.TransformerType) { case TransformerType.Handlebars: var factoryHandlebars = new HandlebarsContextFactory(_settings.FileSystemHandler, _settings.HandlebarsRegistrationCallback); - responseMessageTransformer = new Transformer(factoryHandlebars); + transformer = new Transformer(factoryHandlebars); break; case TransformerType.Scriban: case TransformerType.ScribanDotLiquid: var factoryDotLiquid = new ScribanContextFactory(_settings.FileSystemHandler, webhookRequest.TransformerType); - responseMessageTransformer = new Transformer(factoryDotLiquid); + transformer = new Transformer(factoryDotLiquid); break; default: throw new NotImplementedException($"TransformerType '{webhookRequest.TransformerType}' is not supported."); } - (bodyData, headers) = responseMessageTransformer.Transform(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.BodyData, webhookRequest.Headers, webhookRequest.TransformerReplaceNodeOptions); + bodyData = transformer.TransformBody(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.BodyData, webhookRequest.TransformerReplaceNodeOptions); + headers = transformer.TransformHeaders(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.Headers); + webhookRequestUrl = transformer.TransformString(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.Url); } else { bodyData = webhookRequest.BodyData; headers = webhookRequest.Headers; + webhookRequestUrl = webhookRequest.Url; } // Create RequestMessage var requestMessage = new RequestMessage( - new UrlDetails(webhookRequest.Url), + new UrlDetails(webhookRequestUrl), webhookRequest.Method, ClientIp, bodyData, diff --git a/src/WireMock.Net/Transformers/ITransformer.cs b/src/WireMock.Net/Transformers/ITransformer.cs index 69ecf3c9..b1797135 100644 --- a/src/WireMock.Net/Transformers/ITransformer.cs +++ b/src/WireMock.Net/Transformers/ITransformer.cs @@ -8,5 +8,9 @@ interface ITransformer { ResponseMessage Transform(IMapping mapping, IRequestMessage requestMessage, IResponseMessage original, bool useTransformerForBodyAsFile, ReplaceNodeOptions options); - (IBodyData? BodyData, IDictionary>? Headers) Transform(IMapping mapping, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage, IBodyData? bodyData, IDictionary>? headers, ReplaceNodeOptions options); + IBodyData? TransformBody(IMapping mapping, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage, IBodyData? bodyData, ReplaceNodeOptions options); + + IDictionary>? TransformHeaders(IMapping mapping, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage, IDictionary>? headers); + + string TransformString(IMapping mapping, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage, string? value); } \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/TransformModel.cs b/src/WireMock.Net/Transformers/TransformModel.cs new file mode 100644 index 00000000..b089baeb --- /dev/null +++ b/src/WireMock.Net/Transformers/TransformModel.cs @@ -0,0 +1,13 @@ +using System.Diagnostics.CodeAnalysis; + +namespace WireMock.Transformers; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +internal struct TransformModel +{ + public IMapping mapping { get; set; } + + public IRequestMessage request { get; set; } + + public IResponseMessage? response { get; set; } +} \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/Transformer.cs b/src/WireMock.Net/Transformers/Transformer.cs index 73e3a303..d53d4e45 100644 --- a/src/WireMock.Net/Transformers/Transformer.cs +++ b/src/WireMock.Net/Transformers/Transformer.cs @@ -1,9 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Stef.Validation; +using System; +using System.Collections.Generic; +using System.Linq; using WireMock.Types; using WireMock.Util; @@ -18,22 +18,14 @@ internal class Transformer : ITransformer _factory = Guard.NotNull(factory); } - public (IBodyData? BodyData, IDictionary>? Headers) Transform( + public IBodyData? TransformBody( IMapping mapping, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage, IBodyData? bodyData, - IDictionary>? headers, ReplaceNodeOptions options) { - var transformerContext = _factory.Create(); - - var model = new - { - mapping, - request = originalRequestMessage, - response = originalResponseMessage - }; + var (transformerContext, model) = Create(mapping, originalRequestMessage, originalResponseMessage); IBodyData? newBodyData = null; if (bodyData?.DetectedBodyType != null) @@ -41,20 +33,42 @@ internal class Transformer : ITransformer newBodyData = TransformBodyData(transformerContext, options, model, bodyData, false); } - return (newBodyData, TransformHeaders(transformerContext, model, headers)); + return newBodyData; + } + + public IDictionary>? TransformHeaders( + IMapping mapping, + IRequestMessage originalRequestMessage, + IResponseMessage originalResponseMessage, + IDictionary>? headers + ) + { + var (transformerContext, model) = Create(mapping, originalRequestMessage, originalResponseMessage); + + return TransformHeaders(transformerContext, model, headers); + } + + public string TransformString( + IMapping mapping, + IRequestMessage originalRequestMessage, + IResponseMessage originalResponseMessage, + string? value + ) + { + if (value is null) + { + return string.Empty; + } + + var (transformerContext, model) = Create(mapping, originalRequestMessage, originalResponseMessage); + return transformerContext.ParseAndRender(value, model); } public ResponseMessage Transform(IMapping mapping, IRequestMessage requestMessage, IResponseMessage original, bool useTransformerForBodyAsFile, ReplaceNodeOptions options) { - var transformerContext = _factory.Create(); - var responseMessage = new ResponseMessage(); - var model = new - { - mapping, - request = requestMessage - }; + var (transformerContext, model) = Create(mapping, requestMessage, null); if (original.BodyData?.DetectedBodyType != null) { @@ -85,7 +99,17 @@ internal class Transformer : ITransformer return responseMessage; } - private static IBodyData? TransformBodyData(ITransformerContext transformerContext, ReplaceNodeOptions options, object model, IBodyData original, bool useTransformerForBodyAsFile) + private (ITransformerContext TransformerContext, TransformModel Model) Create(IMapping mapping, IRequestMessage request, IResponseMessage? response) + { + return (_factory.Create(), new TransformModel + { + mapping = mapping, + request = request, + response = response + }); + } + + private static IBodyData? TransformBodyData(ITransformerContext transformerContext, ReplaceNodeOptions options, TransformModel model, IBodyData original, bool useTransformerForBodyAsFile) { return original.DetectedBodyType switch { @@ -96,7 +120,7 @@ internal class Transformer : ITransformer }; } - private static IDictionary> TransformHeaders(ITransformerContext transformerContext, object model, IDictionary>? original) + private static IDictionary> TransformHeaders(ITransformerContext transformerContext, TransformModel model, IDictionary>? original) { if (original == null) { diff --git a/test/WireMock.Net.Tests/WireMockServer.WebhookTests.cs b/test/WireMock.Net.Tests/WireMockServer.WebhookTests.cs index 253f0ce6..abeb192f 100644 --- a/test/WireMock.Net.Tests/WireMockServer.WebhookTests.cs +++ b/test/WireMock.Net.Tests/WireMockServer.WebhookTests.cs @@ -12,190 +12,190 @@ using WireMock.Types; using WireMock.Util; using Xunit; -namespace WireMock.Net.Tests +namespace WireMock.Net.Tests; + +public class WireMockServerWebhookTests { - public class WireMockServerWebhookTests + [Fact] + public async Task WireMockServer_WithWebhooks_Should_Send_Message_To_Webhooks() { - [Fact] - public async Task WireMockServer_WithWebhooks_Should_Send_Message_To_Webhooks() + // Assign + var serverReceivingTheWebhook1 = WireMockServer.Start(); + serverReceivingTheWebhook1.Given(Request.Create().UsingPost()).RespondWith(Response.Create().WithStatusCode(200)); + + var serverReceivingTheWebhook2 = WireMockServer.Start(); + serverReceivingTheWebhook2.Given(Request.Create().UsingPost()).RespondWith(Response.Create().WithStatusCode(200)); + + var webhook1 = new Webhook { - // Assign - var serverReceivingTheWebhook1 = WireMockServer.Start(); - serverReceivingTheWebhook1.Given(Request.Create().UsingPost()).RespondWith(Response.Create().WithStatusCode(200)); + Request = new WebhookRequest + { + Url = serverReceivingTheWebhook1.Urls[0], + Method = "post", + BodyData = new BodyData + { + BodyAsString = "1", + DetectedBodyType = BodyType.String, + DetectedBodyTypeFromContentType = BodyType.String + } + } + }; - var serverReceivingTheWebhook2 = WireMockServer.Start(); - serverReceivingTheWebhook2.Given(Request.Create().UsingPost()).RespondWith(Response.Create().WithStatusCode(200)); + var webhook2 = new Webhook + { + Request = new WebhookRequest + { + Url = serverReceivingTheWebhook2.Urls[0], + Method = "post", + BodyData = new BodyData + { + BodyAsString = "2", + DetectedBodyType = BodyType.String, + DetectedBodyTypeFromContentType = BodyType.String + } + } + }; - var webhook1 = new Webhook + // Act + var server = WireMockServer.Start(); + server.Given(Request.Create().UsingPost()) + .WithWebhook(webhook1, webhook2) + .RespondWith(Response.Create().WithBody("a-response")); + + var request = new HttpRequestMessage + { + Method = HttpMethod.Post, + RequestUri = new Uri($"{server.Urls[0]}/TST"), + Content = new StringContent("test") + }; + + // Assert + var response = await new HttpClient().SendAsync(request).ConfigureAwait(false); + string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + response.StatusCode.Should().Be(HttpStatusCode.OK); + content.Should().Be("a-response"); + + serverReceivingTheWebhook1.LogEntries.Should().HaveCount(1); + serverReceivingTheWebhook2.LogEntries.Should().HaveCount(1); + + server.Dispose(); + serverReceivingTheWebhook1.Dispose(); + serverReceivingTheWebhook2.Dispose(); + } + + [Fact] + public async Task WireMockServer_WithWebhook_Should_Send_Message_To_Webhook() + { + // Assign + var serverReceivingTheWebhook = WireMockServer.Start(); + serverReceivingTheWebhook.Given(Request.Create().WithPath("x").UsingPost()).RespondWith(Response.Create().WithStatusCode(200)); + + // Act + var server = WireMockServer.Start(); + server.Given(Request.Create().UsingPost()) + .WithWebhook(new Webhook { Request = new WebhookRequest { - Url = serverReceivingTheWebhook1.Urls[0], + Url = serverReceivingTheWebhook.Url! + "/{{request.Query.q}}", Method = "post", BodyData = new BodyData { - BodyAsString = "1", + BodyAsString = "abc", DetectedBodyType = BodyType.String, DetectedBodyTypeFromContentType = BodyType.String - } + }, + UseTransformer = true } - }; + }) + .RespondWith(Response.Create().WithBody("a-response")); - var webhook2 = new Webhook - { - Request = new WebhookRequest - { - Url = serverReceivingTheWebhook2.Urls[0], - Method = "post", - BodyData = new BodyData - { - BodyAsString = "2", - DetectedBodyType = BodyType.String, - DetectedBodyTypeFromContentType = BodyType.String - } - } - }; - - // Act - var server = WireMockServer.Start(); - server.Given(Request.Create().UsingPost()) - .WithWebhook(webhook1, webhook2) - .RespondWith(Response.Create().WithBody("a-response")); - - var request = new HttpRequestMessage - { - Method = HttpMethod.Post, - RequestUri = new Uri($"{server.Urls[0]}/TST"), - Content = new StringContent("test") - }; - - // Assert - var response = await new HttpClient().SendAsync(request).ConfigureAwait(false); - string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - response.StatusCode.Should().Be(HttpStatusCode.OK); - content.Should().Be("a-response"); - - serverReceivingTheWebhook1.LogEntries.Should().HaveCount(1); - serverReceivingTheWebhook2.LogEntries.Should().HaveCount(1); - - server.Dispose(); - serverReceivingTheWebhook1.Dispose(); - serverReceivingTheWebhook2.Dispose(); - } - - [Fact] - public async Task WireMockServer_WithWebhook_Should_Send_Message_To_Webhook() + var request = new HttpRequestMessage { - // Assign - var serverReceivingTheWebhook = WireMockServer.Start(); - serverReceivingTheWebhook.Given(Request.Create().UsingPost()).RespondWith(Response.Create().WithStatusCode(200)); + Method = HttpMethod.Post, + RequestUri = new Uri($"{server.Urls[0]}/TST?q=x"), + Content = new StringContent("test") + }; - // Act - var server = WireMockServer.Start(); - server.Given(Request.Create().UsingPost()) - .WithWebhook(new Webhook - { - Request = new WebhookRequest - { - Url = serverReceivingTheWebhook.Urls[0], - Method = "post", - BodyData = new BodyData - { - BodyAsString = "abc", - DetectedBodyType = BodyType.String, - DetectedBodyTypeFromContentType = BodyType.String - } - } - }) - .RespondWith(Response.Create().WithBody("a-response")); + // Assert + var response = await new HttpClient().SendAsync(request).ConfigureAwait(false); + string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var request = new HttpRequestMessage - { - Method = HttpMethod.Post, - RequestUri = new Uri($"{server.Urls[0]}/TST"), - Content = new StringContent("test") - }; + response.StatusCode.Should().Be(HttpStatusCode.OK); + content.Should().Be("a-response"); - // Assert - var response = await new HttpClient().SendAsync(request).ConfigureAwait(false); - string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + serverReceivingTheWebhook.LogEntries.Should().HaveCount(1); - response.StatusCode.Should().Be(HttpStatusCode.OK); - content.Should().Be("a-response"); + server.Dispose(); + serverReceivingTheWebhook.Dispose(); + } - serverReceivingTheWebhook.LogEntries.Should().HaveCount(1); + [Fact] + public async Task WireMockServer_WithWebhookArgs_Should_Send_StringMessage_To_Webhook() + { + // Assign + var serverReceivingTheWebhook = WireMockServer.Start(); + serverReceivingTheWebhook.Given(Request.Create().UsingPost()).RespondWith(Response.Create().WithStatusCode(200)); - server.Dispose(); - serverReceivingTheWebhook.Dispose(); - } + // Act + var server = WireMockServer.Start(); + server.Given(Request.Create().UsingPost()) + .WithWebhook(serverReceivingTheWebhook.Urls[0], "post", null, "OK !", true, TransformerType.Handlebars) + .RespondWith(Response.Create().WithBody("a-response")); - [Fact] - public async Task WireMockServer_WithWebhookArgs_Should_Send_StringMessage_To_Webhook() + var request = new HttpRequestMessage { - // Assign - var serverReceivingTheWebhook = WireMockServer.Start(); - serverReceivingTheWebhook.Given(Request.Create().UsingPost()).RespondWith(Response.Create().WithStatusCode(200)); + Method = HttpMethod.Post, + RequestUri = new Uri($"{server.Urls[0]}/TST"), + Content = new StringContent("test") + }; - // Act - var server = WireMockServer.Start(); - server.Given(Request.Create().UsingPost()) - .WithWebhook(serverReceivingTheWebhook.Urls[0], "post", null, "OK !", true, TransformerType.Handlebars) - .RespondWith(Response.Create().WithBody("a-response")); + // Assert + var response = await new HttpClient().SendAsync(request).ConfigureAwait(false); + string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var request = new HttpRequestMessage - { - Method = HttpMethod.Post, - RequestUri = new Uri($"{server.Urls[0]}/TST"), - Content = new StringContent("test") - }; + response.StatusCode.Should().Be(HttpStatusCode.OK); + content.Should().Be("a-response"); - // Assert - var response = await new HttpClient().SendAsync(request).ConfigureAwait(false); - string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + serverReceivingTheWebhook.LogEntries.Should().HaveCount(1); + serverReceivingTheWebhook.LogEntries.First().RequestMessage.Body.Should().Be("OK !"); - response.StatusCode.Should().Be(HttpStatusCode.OK); - content.Should().Be("a-response"); + server.Dispose(); + serverReceivingTheWebhook.Dispose(); + } - serverReceivingTheWebhook.LogEntries.Should().HaveCount(1); - serverReceivingTheWebhook.LogEntries.First().RequestMessage.Body.Should().Be("OK !"); + [Fact] + public async Task WireMockServer_WithWebhookArgs_Should_Send_JsonMessage_To_Webhook() + { + // Assign + var serverReceivingTheWebhook = WireMockServer.Start(); + serverReceivingTheWebhook.Given(Request.Create().UsingPost()).RespondWith(Response.Create().WithStatusCode(200)); - server.Dispose(); - serverReceivingTheWebhook.Dispose(); - } + // Act + var server = WireMockServer.Start(); + server.Given(Request.Create().UsingPost()) + .WithWebhook(serverReceivingTheWebhook.Urls[0], "post", null, new { Status = "OK" }, true, TransformerType.Handlebars) + .RespondWith(Response.Create().WithBody("a-response")); - [Fact] - public async Task WireMockServer_WithWebhookArgs_Should_Send_JsonMessage_To_Webhook() + var request = new HttpRequestMessage { - // Assign - var serverReceivingTheWebhook = WireMockServer.Start(); - serverReceivingTheWebhook.Given(Request.Create().UsingPost()).RespondWith(Response.Create().WithStatusCode(200)); + Method = HttpMethod.Post, + RequestUri = new Uri($"{server.Urls[0]}/TST"), + Content = new StringContent("test") + }; - // Act - var server = WireMockServer.Start(); - server.Given(Request.Create().UsingPost()) - .WithWebhook(serverReceivingTheWebhook.Urls[0], "post", null, new { Status = "OK" }, true, TransformerType.Handlebars) - .RespondWith(Response.Create().WithBody("a-response")); + // Assert + var response = await new HttpClient().SendAsync(request).ConfigureAwait(false); + string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var request = new HttpRequestMessage - { - Method = HttpMethod.Post, - RequestUri = new Uri($"{server.Urls[0]}/TST"), - Content = new StringContent("test") - }; + response.StatusCode.Should().Be(HttpStatusCode.OK); + content.Should().Be("a-response"); - // Assert - var response = await new HttpClient().SendAsync(request).ConfigureAwait(false); - string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + serverReceivingTheWebhook.LogEntries.Should().HaveCount(1); + serverReceivingTheWebhook.LogEntries.First().RequestMessage.Body.Should().Be("{\"Status\":\"OK\"}"); - response.StatusCode.Should().Be(HttpStatusCode.OK); - content.Should().Be("a-response"); - - serverReceivingTheWebhook.LogEntries.Should().HaveCount(1); - serverReceivingTheWebhook.LogEntries.First().RequestMessage.Body.Should().Be("{\"Status\":\"OK\"}"); - - server.Dispose(); - serverReceivingTheWebhook.Dispose(); - } + server.Dispose(); + serverReceivingTheWebhook.Dispose(); } } \ No newline at end of file