diff --git a/WireMock.Net Solution.sln.DotSettings b/WireMock.Net Solution.sln.DotSettings index 79eca48e..c366605a 100644 --- a/WireMock.Net Solution.sln.DotSettings +++ b/WireMock.Net Solution.sln.DotSettings @@ -16,4 +16,6 @@ True True True + True + True \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs index b1d5274f..620e00d9 100644 --- a/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs @@ -57,5 +57,10 @@ namespace WireMock.Admin.Mappings /// The Webhook. /// public WebhookModel Webhook { get; set; } + + /// + /// The Webhooks. + /// + public WebhookModel[] Webhooks { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net/IMapping.cs b/src/WireMock.Net/IMapping.cs index 01e557f0..9d17844b 100644 --- a/src/WireMock.Net/IMapping.cs +++ b/src/WireMock.Net/IMapping.cs @@ -95,9 +95,9 @@ namespace WireMock bool LogMapping { get; } /// - /// The Webhook. + /// The Webhooks. /// - IWebhook Webhook { get; } + IWebhook[] Webhooks { get; } /// /// ProvideResponseAsync diff --git a/src/WireMock.Net/Mapping.cs b/src/WireMock.Net/Mapping.cs index f253b922..d9e15942 100644 --- a/src/WireMock.Net/Mapping.cs +++ b/src/WireMock.Net/Mapping.cs @@ -1,7 +1,6 @@ using System; using System.Threading.Tasks; using JetBrains.Annotations; -using WireMock.Admin.Mappings; using WireMock.Matchers.Request; using WireMock.Models; using WireMock.ResponseProviders; @@ -56,8 +55,8 @@ namespace WireMock /// public bool LogMapping => !(Provider is DynamicResponseProvider || Provider is DynamicAsyncResponseProvider); - /// - public IWebhook Webhook { get; } + /// + public IWebhook[] Webhooks { get; } /// /// Initializes a new instance of the class. @@ -73,7 +72,7 @@ namespace WireMock /// State in which the current mapping can occur. [Optional] /// The next state which will occur after the current mapping execution. [Optional] /// Only when the current state is executed this number, the next state which will occur. [Optional] - /// The Webhook. [Optional] + /// The Webhooks. [Optional] public Mapping( Guid guid, [CanBeNull] string title, @@ -86,7 +85,7 @@ namespace WireMock [CanBeNull] string executionConditionState, [CanBeNull] string nextState, [CanBeNull] int? stateTimes, - [CanBeNull] IWebhook webhook) + [CanBeNull] IWebhook[] webhooks) { Guid = guid; Title = title; @@ -99,7 +98,7 @@ namespace WireMock ExecutionConditionState = executionConditionState; NextState = nextState; StateTimes = stateTimes; - Webhook = webhook; + Webhooks = webhooks; } /// diff --git a/src/WireMock.Net/Models/Webhook.cs b/src/WireMock.Net/Models/Webhook.cs index b5583d24..7e2fef8b 100644 --- a/src/WireMock.Net/Models/Webhook.cs +++ b/src/WireMock.Net/Models/Webhook.cs @@ -1,8 +1,4 @@ -using System.Collections.Generic; -using JetBrains.Annotations; -using WireMock.Types; - -namespace WireMock.Models +namespace WireMock.Models { /// /// Webhook diff --git a/src/WireMock.Net/Owin/WireMockMiddleware.cs b/src/WireMock.Net/Owin/WireMockMiddleware.cs index 3c49679a..8a9d8c9e 100644 --- a/src/WireMock.Net/Owin/WireMockMiddleware.cs +++ b/src/WireMock.Net/Owin/WireMockMiddleware.cs @@ -156,9 +156,9 @@ namespace WireMock.Owin UpdateScenarioState(targetMapping); } - if (!targetMapping.IsAdminInterface && targetMapping.Webhook != null) + if (!targetMapping.IsAdminInterface && targetMapping.Webhooks?.Length > 0) { - await SendToWebhookAsync(targetMapping, request, response).ConfigureAwait(false); + await SendToWebhooksAsync(targetMapping, request, response).ConfigureAwait(false); } } catch (Exception ex) @@ -191,18 +191,21 @@ namespace WireMock.Owin await CompletedTask; } - private async Task SendToWebhookAsync(IMapping mapping, RequestMessage request, ResponseMessage response) + private async Task SendToWebhooksAsync(IMapping mapping, RequestMessage request, ResponseMessage response) { - var httpClientForWebhook = HttpClientBuilder.Build(mapping.Settings.WebhookSettings ?? new WebhookSettings()); - var webhookSender = new WebhookSender(mapping.Settings); + for (int index = 0; index < mapping.Webhooks.Length; index++) + { + var httpClientForWebhook = HttpClientBuilder.Build(mapping.Settings.WebhookSettings ?? new WebhookSettings()); + var webhookSender = new WebhookSender(mapping.Settings); - try - { - await webhookSender.SendAsync(httpClientForWebhook, mapping.Webhook.Request, request, response).ConfigureAwait(false); - } - catch (Exception ex) - { - _options.Logger.Error($"Sending message to Webhook Mapping '{mapping.Guid}' failed. Exception: {ex}"); + try + { + await webhookSender.SendAsync(httpClientForWebhook, mapping.Webhooks[index].Request, request, response).ConfigureAwait(false); + } + catch (Exception ex) + { + _options.Logger.Error($"Sending message to Webhook [{index}] from Mapping '{mapping.Guid}' failed. Exception: {ex}"); + } } } diff --git a/src/WireMock.Net/Serialization/MappingConverter.cs b/src/WireMock.Net/Serialization/MappingConverter.cs index cc08c161..229d4ad4 100644 --- a/src/WireMock.Net/Serialization/MappingConverter.cs +++ b/src/WireMock.Net/Serialization/MappingConverter.cs @@ -84,10 +84,18 @@ namespace WireMock.Serialization Response = new ResponseModel { Delay = (int?)response.Delay?.TotalMilliseconds - }, - Webhook = WebhookMapper.Map(mapping.Webhook) + } }; + if (mapping.Webhooks?.Length == 1) + { + mappingModel.Webhook = WebhookMapper.Map(mapping.Webhooks[0]); + } + else if (mapping.Webhooks?.Length > 1) + { + mappingModel.Webhooks = mapping.Webhooks.Select(WebhookMapper.Map).ToArray(); + } + if (bodyMatcher?.Matchers != null) { mappingModel.Request.Body = new BodyModel(); diff --git a/src/WireMock.Net/Server/IRespondWithAProvider.cs b/src/WireMock.Net/Server/IRespondWithAProvider.cs index 560b3562..f58d063f 100644 --- a/src/WireMock.Net/Server/IRespondWithAProvider.cs +++ b/src/WireMock.Net/Server/IRespondWithAProvider.cs @@ -103,14 +103,14 @@ namespace WireMock.Server IRespondWithAProvider WillSetStateTo(int state, int? times = 1); /// - /// Add a Webbook to call after the response has been generated. + /// Add (multiple) Webhook(s) to call after the response has been generated. /// - /// The Webhook + /// The Webhooks /// The . - IRespondWithAProvider WithWebhook(IWebhook webhook); + IRespondWithAProvider WithWebhook(params IWebhook[] webhooks); /// - /// Add a Webbook to call after the response has been generated. + /// Add a Webhook to call after the response has been generated. /// /// The Webhook Url /// The method to use. [optional] @@ -129,7 +129,7 @@ namespace WireMock.Server ); /// - /// Add a Webbook to call after the response has been generated. + /// Add a Webhook to call after the response has been generated. /// /// The Webhook Url /// The method to use. [optional] diff --git a/src/WireMock.Net/Server/RespondWithAProvider.cs b/src/WireMock.Net/Server/RespondWithAProvider.cs index 59837f8b..ca39634c 100644 --- a/src/WireMock.Net/Server/RespondWithAProvider.cs +++ b/src/WireMock.Net/Server/RespondWithAProvider.cs @@ -1,209 +1,212 @@ -// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License. -// For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root. -using System; +// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License. +// For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root. +using System; using System.Collections.Generic; using JetBrains.Annotations; -using WireMock.Matchers.Request; -using WireMock.Models; -using WireMock.ResponseProviders; -using WireMock.Settings; +using WireMock.Matchers.Request; +using WireMock.Models; +using WireMock.ResponseProviders; +using WireMock.Settings; using WireMock.Types; using WireMock.Util; +using WireMock.Validation; + +namespace WireMock.Server +{ + /// + /// The respond with a provider. + /// + internal class RespondWithAProvider : IRespondWithAProvider + { + private int _priority; + private string _title; + private string _path; + private string _executionConditionState; + private string _nextState; + private string _scenario; + private int _timesInSameState = 1; + private readonly RegistrationCallback _registrationCallback; + private readonly IRequestMatcher _requestMatcher; + private readonly IWireMockServerSettings _settings; + private readonly bool _saveToFile; + + public Guid Guid { get; private set; } = Guid.NewGuid(); + + public IWebhook[] Webhooks { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The registration callback. + /// The request matcher. + /// The WireMockServerSettings. + /// Optional boolean to indicate if this mapping should be saved as static mapping file. + public RespondWithAProvider(RegistrationCallback registrationCallback, IRequestMatcher requestMatcher, IWireMockServerSettings settings, bool saveToFile = false) + { + _registrationCallback = registrationCallback; + _requestMatcher = requestMatcher; + _settings = settings; + _saveToFile = saveToFile; + } + + /// + /// The respond with. + /// + /// The provider. + public void RespondWith(IResponseProvider provider) + { + _registrationCallback(new Mapping(Guid, _title, _path, _settings, _requestMatcher, provider, _priority, _scenario, _executionConditionState, _nextState, _timesInSameState, Webhooks), _saveToFile); + } + + /// + public IRespondWithAProvider WithGuid(string guid) + { + return WithGuid(Guid.Parse(guid)); + } + + /// + public IRespondWithAProvider WithGuid(Guid guid) + { + Guid = guid; + + return this; + } + + /// + public IRespondWithAProvider WithTitle(string title) + { + _title = title; + + return this; + } + + /// + public IRespondWithAProvider WithPath(string path) + { + _path = path; + + return this; + } + + /// + public IRespondWithAProvider AtPriority(int priority) + { + _priority = priority; + + return this; + } + + /// + public IRespondWithAProvider InScenario(string scenario) + { + _scenario = scenario; + + return this; + } + + /// + public IRespondWithAProvider InScenario(int scenario) + { + return InScenario(scenario.ToString()); + } + + /// + public IRespondWithAProvider WhenStateIs(string state) + { + if (string.IsNullOrEmpty(_scenario)) + { + throw new NotSupportedException("Unable to set state condition when no scenario is defined."); + } + + _executionConditionState = state; + + return this; + } + + /// + public IRespondWithAProvider WhenStateIs(int state) + { + return WhenStateIs(state.ToString()); + } + + /// + public IRespondWithAProvider WillSetStateTo(string state, int? times = 1) + { + if (string.IsNullOrEmpty(_scenario)) + { + throw new NotSupportedException("Unable to set next state when no scenario is defined."); + } + + _nextState = state; + _timesInSameState = times ?? 1; + + return this; + } + + /// + public IRespondWithAProvider WillSetStateTo(int state, int? times = 1) + { + return WillSetStateTo(state.ToString(), times); + } + + /// + public IRespondWithAProvider WithWebhook(params IWebhook[] webhooks) + { + Check.HasNoNulls(webhooks, nameof(webhooks)); + + Webhooks = webhooks; + + return this; + } + + /// + public IRespondWithAProvider WithWebhook( + [NotNull] string url, + [CanBeNull] string method = "post", + [CanBeNull] IDictionary> headers = null, + [CanBeNull] string body = null, + bool useTransformer = true, + TransformerType transformerType = TransformerType.Handlebars) + { + Webhooks = new[] { InitWebhook(url, method, headers, useTransformer, transformerType) }; -namespace WireMock.Server -{ - /// - /// The respond with a provider. - /// - internal class RespondWithAProvider : IRespondWithAProvider - { - private int _priority; - private string _title; - private string _path; - private string _executionConditionState; - private string _nextState; - private string _scenario; - private int _timesInSameState = 1; - private readonly RegistrationCallback _registrationCallback; - private readonly IRequestMatcher _requestMatcher; - private readonly IWireMockServerSettings _settings; - private readonly bool _saveToFile; - - public Guid Guid { get; private set; } = Guid.NewGuid(); - - public IWebhook Webhook { get; private set; } - - /// - /// Initializes a new instance of the class. - /// - /// The registration callback. - /// The request matcher. - /// The WireMockServerSettings. - /// Optional boolean to indicate if this mapping should be saved as static mapping file. - public RespondWithAProvider(RegistrationCallback registrationCallback, IRequestMatcher requestMatcher, IWireMockServerSettings settings, bool saveToFile = false) - { - _registrationCallback = registrationCallback; - _requestMatcher = requestMatcher; - _settings = settings; - _saveToFile = saveToFile; - } - - /// - /// The respond with. - /// - /// The provider. - public void RespondWith(IResponseProvider provider) - { - _registrationCallback(new Mapping(Guid, _title, _path, _settings, _requestMatcher, provider, _priority, _scenario, _executionConditionState, _nextState, _timesInSameState, Webhook), _saveToFile); - } - - /// - public IRespondWithAProvider WithGuid(string guid) - { - return WithGuid(Guid.Parse(guid)); - } - - /// - public IRespondWithAProvider WithGuid(Guid guid) - { - Guid = guid; - - return this; - } - - /// - public IRespondWithAProvider WithTitle(string title) - { - _title = title; - - return this; - } - - /// - public IRespondWithAProvider WithPath(string path) - { - _path = path; - - return this; - } - - /// - public IRespondWithAProvider AtPriority(int priority) - { - _priority = priority; - - return this; - } - - /// - public IRespondWithAProvider InScenario(string scenario) - { - _scenario = scenario; - - return this; - } - - /// - public IRespondWithAProvider InScenario(int scenario) - { - return InScenario(scenario.ToString()); - } - - /// - public IRespondWithAProvider WhenStateIs(string state) - { - if (string.IsNullOrEmpty(_scenario)) - { - throw new NotSupportedException("Unable to set state condition when no scenario is defined."); - } - - _executionConditionState = state; - - return this; - } - - /// - public IRespondWithAProvider WhenStateIs(int state) - { - return WhenStateIs(state.ToString()); - } - - /// - public IRespondWithAProvider WillSetStateTo(string state, int? times = 1) - { - if (string.IsNullOrEmpty(_scenario)) - { - throw new NotSupportedException("Unable to set next state when no scenario is defined."); - } - - _nextState = state; - _timesInSameState = times ?? 1; - - return this; - } - - /// - public IRespondWithAProvider WillSetStateTo(int state, int? times = 1) - { - return WillSetStateTo(state.ToString(), times); - } - - /// - public IRespondWithAProvider WithWebhook(IWebhook webhook) - { - Webhook = webhook; - - return this; - } - - /// - public IRespondWithAProvider WithWebhook( - [NotNull] string url, - [CanBeNull] string method = "post", - [CanBeNull] IDictionary> headers = null, - [CanBeNull] string body = null, - bool useTransformer = true, - TransformerType transformerType = TransformerType.Handlebars) - { - Webhook = InitWebhook(url, method, headers, useTransformer, transformerType); - if (body != null) { - Webhook.Request.BodyData = new BodyData + Webhooks[0].Request.BodyData = new BodyData { BodyAsString = body, DetectedBodyType = BodyType.String, DetectedBodyTypeFromContentType = BodyType.String }; - } - - return this; + } + + return this; } - /// - public IRespondWithAProvider WithWebhook( - [NotNull] string url, - [CanBeNull] string method = "post", - [CanBeNull] IDictionary> headers = null, - [CanBeNull] object body = null, - bool useTransformer = true, - TransformerType transformerType = TransformerType.Handlebars) - { - Webhook = InitWebhook(url, method, headers, useTransformer, transformerType); - + /// + public IRespondWithAProvider WithWebhook( + [NotNull] string url, + [CanBeNull] string method = "post", + [CanBeNull] IDictionary> headers = null, + [CanBeNull] object body = null, + bool useTransformer = true, + TransformerType transformerType = TransformerType.Handlebars) + { + Webhooks = new[] { InitWebhook(url, method, headers, useTransformer, transformerType) }; + if (body != null) { - Webhook.Request.BodyData = new BodyData + Webhooks[0].Request.BodyData = new BodyData { BodyAsJson = body, DetectedBodyType = BodyType.Json, DetectedBodyTypeFromContentType = BodyType.Json }; - } - - return this; - } - + } + + return this; + } + private IWebhook InitWebhook( string url, string method, @@ -222,6 +225,6 @@ namespace WireMock.Server TransformerType = transformerType } }; - } - } + } + } } \ No newline at end of file diff --git a/src/WireMock.Net/Server/WireMockServer.Admin.cs b/src/WireMock.Net/Server/WireMockServer.Admin.cs index 9087a4ed..b6970ad9 100644 --- a/src/WireMock.Net/Server/WireMockServer.Admin.cs +++ b/src/WireMock.Net/Server/WireMockServer.Admin.cs @@ -470,10 +470,15 @@ namespace WireMock.Server respondProvider = respondProvider.WillSetStateTo(mappingModel.SetStateTo); } - if (mappingModel.Webhook?.Request != null) + if (mappingModel.Webhook != null) { respondProvider = respondProvider.WithWebhook(WebhookMapper.Map(mappingModel.Webhook)); } + else if (mappingModel.Webhooks?.Length > 1) + { + var webhooks = mappingModel.Webhooks.Select(WebhookMapper.Map).ToArray(); + respondProvider = respondProvider.WithWebhook(webhooks); + } respondProvider.RespondWith(responseBuilder); diff --git a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs index c839c6f2..de2a4776 100644 --- a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs +++ b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs @@ -24,31 +24,34 @@ namespace WireMock.Net.Tests.Serialization } [Fact] - public void ToMappingModel() + public void ToMappingModel_With_SingleWebHook() { // Assign var request = Request.Create(); var response = Response.Create(); - var webhook = new Webhook + var webhooks = new IWebhook[] { - Request = new WebhookRequest + new Webhook { - Url = "https://test.com", - Headers = new Dictionary> + Request = new WebhookRequest { - { "Single", new WireMockList("x") }, - { "Multi", new WireMockList("a", "b") } - }, - Method = "post", - BodyData = new BodyData - { - BodyAsString = "b", - DetectedBodyType = BodyType.String, - DetectedBodyTypeFromContentType = BodyType.String + Url = "https://test.com", + Headers = new Dictionary> + { + { "Single", new WireMockList("x") }, + { "Multi", new WireMockList("a", "b") } + }, + Method = "post", + BodyData = new BodyData + { + BodyAsString = "b", + DetectedBodyType = BodyType.String, + DetectedBodyTypeFromContentType = BodyType.String + } } } }; - var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 0, null, null, null, null, webhook); + var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 0, null, null, null, null, webhooks); // Act var model = _sut.ToMappingModel(mapping); @@ -61,6 +64,8 @@ namespace WireMock.Net.Tests.Serialization model.Response.UseTransformer.Should().BeNull(); model.Response.Headers.Should().BeNull(); + model.Webhooks.Should().BeNull(); + model.Webhook.Request.Method.Should().Be("post"); model.Webhook.Request.Url.Should().Be("https://test.com"); model.Webhook.Request.Headers.Should().HaveCount(2); @@ -68,6 +73,80 @@ namespace WireMock.Net.Tests.Serialization model.Webhook.Request.BodyAsJson.Should().BeNull(); } + [Fact] + public void ToMappingModel_With_MultipleWebHooks() + { + // Assign + var request = Request.Create(); + var response = Response.Create(); + var webhooks = new IWebhook[] + { + new Webhook + { + Request = new WebhookRequest + { + Url = "https://test1.com", + Headers = new Dictionary> + { + { "One", new WireMockList("x") } + }, + Method = "post", + BodyData = new BodyData + { + BodyAsString = "1", + DetectedBodyType = BodyType.String, + DetectedBodyTypeFromContentType = BodyType.String + } + } + }, + + new Webhook + { + Request = new WebhookRequest + { + Url = "https://test2.com", + Headers = new Dictionary> + { + { "First", new WireMockList("x") }, + { "Second", new WireMockList("a", "b") } + }, + Method = "post", + BodyData = new BodyData + { + BodyAsString = "2", + DetectedBodyType = BodyType.String, + DetectedBodyTypeFromContentType = BodyType.String + } + } + } + }; + var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 0, null, null, null, null, webhooks +); + + // Act + var model = _sut.ToMappingModel(mapping); + + // Assert + model.Should().NotBeNull(); + model.Priority.Should().BeNull(); + + model.Response.BodyAsJsonIndented.Should().BeNull(); + model.Response.UseTransformer.Should().BeNull(); + model.Response.Headers.Should().BeNull(); + + model.Webhook.Should().BeNull(); + + model.Webhooks[0].Request.Method.Should().Be("post"); + model.Webhooks[0].Request.Url.Should().Be("https://test1.com"); + model.Webhooks[0].Request.Headers.Should().HaveCount(1); + model.Webhooks[0].Request.Body.Should().Be("1"); + + model.Webhooks[1].Request.Method.Should().Be("post"); + model.Webhooks[1].Request.Url.Should().Be("https://test2.com"); + model.Webhooks[1].Request.Headers.Should().HaveCount(2); + model.Webhooks[1].Request.Body.Should().Be("2"); + } + [Fact] public void ToMappingModel_WithPriority_ReturnsPriority() { diff --git a/test/WireMock.Net.Tests/WireMockServer.WebhookTests.cs b/test/WireMock.Net.Tests/WireMockServer.WebhookTests.cs index 7e6ae43e..f988a4c4 100644 --- a/test/WireMock.Net.Tests/WireMockServer.WebhookTests.cs +++ b/test/WireMock.Net.Tests/WireMockServer.WebhookTests.cs @@ -16,6 +16,74 @@ namespace WireMock.Net.Tests { public class WireMockServerWebhookTests { + [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 + { + Request = new WebhookRequest + { + Url = serverReceivingTheWebhook1.Urls[0], + Method = "post", + BodyData = new BodyData + { + BodyAsString = "1", + DetectedBodyType = BodyType.String, + DetectedBodyTypeFromContentType = BodyType.String + } + } + }; + + 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); + string content = await response.Content.ReadAsStringAsync(); + + 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() {