Add support for multiple webhooks (#615)

This commit is contained in:
Stef Heyenrath
2021-05-19 13:58:48 +02:00
committed by GitHub
parent 93ab4e1853
commit b04000bfdd
12 changed files with 403 additions and 235 deletions

View File

@@ -16,4 +16,6 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Raml/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Raml/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=randomizer/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=randomizer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Stef/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Stef/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Webhook/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Webhooks/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary> </wpf:ResourceDictionary>

View File

@@ -57,5 +57,10 @@ namespace WireMock.Admin.Mappings
/// The Webhook. /// The Webhook.
/// </summary> /// </summary>
public WebhookModel Webhook { get; set; } public WebhookModel Webhook { get; set; }
/// <summary>
/// The Webhooks.
/// </summary>
public WebhookModel[] Webhooks { get; set; }
} }
} }

View File

@@ -95,9 +95,9 @@ namespace WireMock
bool LogMapping { get; } bool LogMapping { get; }
/// <summary> /// <summary>
/// The Webhook. /// The Webhooks.
/// </summary> /// </summary>
IWebhook Webhook { get; } IWebhook[] Webhooks { get; }
/// <summary> /// <summary>
/// ProvideResponseAsync /// ProvideResponseAsync

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Admin.Mappings;
using WireMock.Matchers.Request; using WireMock.Matchers.Request;
using WireMock.Models; using WireMock.Models;
using WireMock.ResponseProviders; using WireMock.ResponseProviders;
@@ -56,8 +55,8 @@ namespace WireMock
/// <inheritdoc cref="IMapping.LogMapping" /> /// <inheritdoc cref="IMapping.LogMapping" />
public bool LogMapping => !(Provider is DynamicResponseProvider || Provider is DynamicAsyncResponseProvider); public bool LogMapping => !(Provider is DynamicResponseProvider || Provider is DynamicAsyncResponseProvider);
/// <inheritdoc cref="IMapping.Webhook" /> /// <inheritdoc cref="IMapping.Webhooks" />
public IWebhook Webhook { get; } public IWebhook[] Webhooks { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Mapping"/> class. /// Initializes a new instance of the <see cref="Mapping"/> class.
@@ -73,7 +72,7 @@ namespace WireMock
/// <param name="executionConditionState">State in which the current mapping can occur. [Optional]</param> /// <param name="executionConditionState">State in which the current mapping can occur. [Optional]</param>
/// <param name="nextState">The next state which will occur after the current mapping execution. [Optional]</param> /// <param name="nextState">The next state which will occur after the current mapping execution. [Optional]</param>
/// <param name="stateTimes">Only when the current state is executed this number, the next state which will occur. [Optional]</param> /// <param name="stateTimes">Only when the current state is executed this number, the next state which will occur. [Optional]</param>
/// <param name="webhook">The Webhook. [Optional]</param> /// <param name="webhooks">The Webhooks. [Optional]</param>
public Mapping( public Mapping(
Guid guid, Guid guid,
[CanBeNull] string title, [CanBeNull] string title,
@@ -86,7 +85,7 @@ namespace WireMock
[CanBeNull] string executionConditionState, [CanBeNull] string executionConditionState,
[CanBeNull] string nextState, [CanBeNull] string nextState,
[CanBeNull] int? stateTimes, [CanBeNull] int? stateTimes,
[CanBeNull] IWebhook webhook) [CanBeNull] IWebhook[] webhooks)
{ {
Guid = guid; Guid = guid;
Title = title; Title = title;
@@ -99,7 +98,7 @@ namespace WireMock
ExecutionConditionState = executionConditionState; ExecutionConditionState = executionConditionState;
NextState = nextState; NextState = nextState;
StateTimes = stateTimes; StateTimes = stateTimes;
Webhook = webhook; Webhooks = webhooks;
} }
/// <inheritdoc cref="IMapping.ProvideResponseAsync" /> /// <inheritdoc cref="IMapping.ProvideResponseAsync" />

View File

@@ -1,8 +1,4 @@
using System.Collections.Generic; namespace WireMock.Models
using JetBrains.Annotations;
using WireMock.Types;
namespace WireMock.Models
{ {
/// <summary> /// <summary>
/// Webhook /// Webhook

View File

@@ -156,9 +156,9 @@ namespace WireMock.Owin
UpdateScenarioState(targetMapping); 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) catch (Exception ex)
@@ -191,18 +191,21 @@ namespace WireMock.Owin
await CompletedTask; 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()); for (int index = 0; index < mapping.Webhooks.Length; index++)
var webhookSender = new WebhookSender(mapping.Settings); {
var httpClientForWebhook = HttpClientBuilder.Build(mapping.Settings.WebhookSettings ?? new WebhookSettings());
var webhookSender = new WebhookSender(mapping.Settings);
try try
{ {
await webhookSender.SendAsync(httpClientForWebhook, mapping.Webhook.Request, request, response).ConfigureAwait(false); await webhookSender.SendAsync(httpClientForWebhook, mapping.Webhooks[index].Request, request, response).ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
{ {
_options.Logger.Error($"Sending message to Webhook Mapping '{mapping.Guid}' failed. Exception: {ex}"); _options.Logger.Error($"Sending message to Webhook [{index}] from Mapping '{mapping.Guid}' failed. Exception: {ex}");
}
} }
} }

View File

@@ -84,10 +84,18 @@ namespace WireMock.Serialization
Response = new ResponseModel Response = new ResponseModel
{ {
Delay = (int?)response.Delay?.TotalMilliseconds 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) if (bodyMatcher?.Matchers != null)
{ {
mappingModel.Request.Body = new BodyModel(); mappingModel.Request.Body = new BodyModel();

View File

@@ -103,14 +103,14 @@ namespace WireMock.Server
IRespondWithAProvider WillSetStateTo(int state, int? times = 1); IRespondWithAProvider WillSetStateTo(int state, int? times = 1);
/// <summary> /// <summary>
/// Add a Webbook to call after the response has been generated. /// Add (multiple) Webhook(s) to call after the response has been generated.
/// </summary> /// </summary>
/// <param name="webhook">The Webhook</param> /// <param name="webhooks">The Webhooks</param>
/// <returns>The <see cref="IRespondWithAProvider"/>.</returns> /// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
IRespondWithAProvider WithWebhook(IWebhook webhook); IRespondWithAProvider WithWebhook(params IWebhook[] webhooks);
/// <summary> /// <summary>
/// Add a Webbook to call after the response has been generated. /// Add a Webhook to call after the response has been generated.
/// </summary> /// </summary>
/// <param name="url">The Webhook Url</param> /// <param name="url">The Webhook Url</param>
/// <param name="method">The method to use. [optional]</param> /// <param name="method">The method to use. [optional]</param>
@@ -129,7 +129,7 @@ namespace WireMock.Server
); );
/// <summary> /// <summary>
/// Add a Webbook to call after the response has been generated. /// Add a Webhook to call after the response has been generated.
/// </summary> /// </summary>
/// <param name="url">The Webhook Url</param> /// <param name="url">The Webhook Url</param>
/// <param name="method">The method to use. [optional]</param> /// <param name="method">The method to use. [optional]</param>

View File

@@ -1,209 +1,212 @@
// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License. // 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. // For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Matchers.Request; using WireMock.Matchers.Request;
using WireMock.Models; using WireMock.Models;
using WireMock.ResponseProviders; using WireMock.ResponseProviders;
using WireMock.Settings; using WireMock.Settings;
using WireMock.Types; using WireMock.Types;
using WireMock.Util; using WireMock.Util;
using WireMock.Validation;
namespace WireMock.Server
{
/// <summary>
/// The respond with a provider.
/// </summary>
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; }
/// <summary>
/// Initializes a new instance of the <see cref="RespondWithAProvider"/> class.
/// </summary>
/// <param name="registrationCallback">The registration callback.</param>
/// <param name="requestMatcher">The request matcher.</param>
/// <param name="settings">The WireMockServerSettings.</param>
/// <param name="saveToFile">Optional boolean to indicate if this mapping should be saved as static mapping file.</param>
public RespondWithAProvider(RegistrationCallback registrationCallback, IRequestMatcher requestMatcher, IWireMockServerSettings settings, bool saveToFile = false)
{
_registrationCallback = registrationCallback;
_requestMatcher = requestMatcher;
_settings = settings;
_saveToFile = saveToFile;
}
/// <summary>
/// The respond with.
/// </summary>
/// <param name="provider">The provider.</param>
public void RespondWith(IResponseProvider provider)
{
_registrationCallback(new Mapping(Guid, _title, _path, _settings, _requestMatcher, provider, _priority, _scenario, _executionConditionState, _nextState, _timesInSameState, Webhooks), _saveToFile);
}
/// <see cref="IRespondWithAProvider.WithGuid(string)"/>
public IRespondWithAProvider WithGuid(string guid)
{
return WithGuid(Guid.Parse(guid));
}
/// <see cref="IRespondWithAProvider.WithGuid(Guid)"/>
public IRespondWithAProvider WithGuid(Guid guid)
{
Guid = guid;
return this;
}
/// <see cref="IRespondWithAProvider.WithTitle"/>
public IRespondWithAProvider WithTitle(string title)
{
_title = title;
return this;
}
/// <see cref="IRespondWithAProvider.WithPath"/>
public IRespondWithAProvider WithPath(string path)
{
_path = path;
return this;
}
/// <see cref="IRespondWithAProvider.AtPriority"/>
public IRespondWithAProvider AtPriority(int priority)
{
_priority = priority;
return this;
}
/// <see cref="IRespondWithAProvider.InScenario(string)"/>
public IRespondWithAProvider InScenario(string scenario)
{
_scenario = scenario;
return this;
}
/// <see cref="IRespondWithAProvider.InScenario(int)"/>
public IRespondWithAProvider InScenario(int scenario)
{
return InScenario(scenario.ToString());
}
/// <see cref="IRespondWithAProvider.WhenStateIs(string)"/>
public IRespondWithAProvider WhenStateIs(string state)
{
if (string.IsNullOrEmpty(_scenario))
{
throw new NotSupportedException("Unable to set state condition when no scenario is defined.");
}
_executionConditionState = state;
return this;
}
/// <see cref="IRespondWithAProvider.WhenStateIs(int)"/>
public IRespondWithAProvider WhenStateIs(int state)
{
return WhenStateIs(state.ToString());
}
/// <see cref="IRespondWithAProvider.WillSetStateTo(string, int?)"/>
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;
}
/// <see cref="IRespondWithAProvider.WillSetStateTo(int, int?)"/>
public IRespondWithAProvider WillSetStateTo(int state, int? times = 1)
{
return WillSetStateTo(state.ToString(), times);
}
/// <see cref="IRespondWithAProvider.WithWebhook(IWebhook[])"/>
public IRespondWithAProvider WithWebhook(params IWebhook[] webhooks)
{
Check.HasNoNulls(webhooks, nameof(webhooks));
Webhooks = webhooks;
return this;
}
/// <see cref="IRespondWithAProvider.WithWebhook(string, string, IDictionary{string, WireMockList{string}}, string, bool, TransformerType)"/>
public IRespondWithAProvider WithWebhook(
[NotNull] string url,
[CanBeNull] string method = "post",
[CanBeNull] IDictionary<string, WireMockList<string>> headers = null,
[CanBeNull] string body = null,
bool useTransformer = true,
TransformerType transformerType = TransformerType.Handlebars)
{
Webhooks = new[] { InitWebhook(url, method, headers, useTransformer, transformerType) };
namespace WireMock.Server
{
/// <summary>
/// The respond with a provider.
/// </summary>
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; }
/// <summary>
/// Initializes a new instance of the <see cref="RespondWithAProvider"/> class.
/// </summary>
/// <param name="registrationCallback">The registration callback.</param>
/// <param name="requestMatcher">The request matcher.</param>
/// <param name="settings">The WireMockServerSettings.</param>
/// <param name="saveToFile">Optional boolean to indicate if this mapping should be saved as static mapping file.</param>
public RespondWithAProvider(RegistrationCallback registrationCallback, IRequestMatcher requestMatcher, IWireMockServerSettings settings, bool saveToFile = false)
{
_registrationCallback = registrationCallback;
_requestMatcher = requestMatcher;
_settings = settings;
_saveToFile = saveToFile;
}
/// <summary>
/// The respond with.
/// </summary>
/// <param name="provider">The provider.</param>
public void RespondWith(IResponseProvider provider)
{
_registrationCallback(new Mapping(Guid, _title, _path, _settings, _requestMatcher, provider, _priority, _scenario, _executionConditionState, _nextState, _timesInSameState, Webhook), _saveToFile);
}
/// <see cref="IRespondWithAProvider.WithGuid(string)"/>
public IRespondWithAProvider WithGuid(string guid)
{
return WithGuid(Guid.Parse(guid));
}
/// <see cref="IRespondWithAProvider.WithGuid(Guid)"/>
public IRespondWithAProvider WithGuid(Guid guid)
{
Guid = guid;
return this;
}
/// <see cref="IRespondWithAProvider.WithTitle"/>
public IRespondWithAProvider WithTitle(string title)
{
_title = title;
return this;
}
/// <see cref="IRespondWithAProvider.WithPath"/>
public IRespondWithAProvider WithPath(string path)
{
_path = path;
return this;
}
/// <see cref="IRespondWithAProvider.AtPriority"/>
public IRespondWithAProvider AtPriority(int priority)
{
_priority = priority;
return this;
}
/// <see cref="IRespondWithAProvider.InScenario(string)"/>
public IRespondWithAProvider InScenario(string scenario)
{
_scenario = scenario;
return this;
}
/// <see cref="IRespondWithAProvider.InScenario(int)"/>
public IRespondWithAProvider InScenario(int scenario)
{
return InScenario(scenario.ToString());
}
/// <see cref="IRespondWithAProvider.WhenStateIs(string)"/>
public IRespondWithAProvider WhenStateIs(string state)
{
if (string.IsNullOrEmpty(_scenario))
{
throw new NotSupportedException("Unable to set state condition when no scenario is defined.");
}
_executionConditionState = state;
return this;
}
/// <see cref="IRespondWithAProvider.WhenStateIs(int)"/>
public IRespondWithAProvider WhenStateIs(int state)
{
return WhenStateIs(state.ToString());
}
/// <see cref="IRespondWithAProvider.WillSetStateTo(string, int?)"/>
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;
}
/// <see cref="IRespondWithAProvider.WillSetStateTo(int, int?)"/>
public IRespondWithAProvider WillSetStateTo(int state, int? times = 1)
{
return WillSetStateTo(state.ToString(), times);
}
/// <see cref="IRespondWithAProvider.WithWebhook(IWebhook)"/>
public IRespondWithAProvider WithWebhook(IWebhook webhook)
{
Webhook = webhook;
return this;
}
/// <see cref="IRespondWithAProvider.WithWebhook(string,string, IDictionary{string, WireMockList{string}}, string, bool, TransformerType)"/>
public IRespondWithAProvider WithWebhook(
[NotNull] string url,
[CanBeNull] string method = "post",
[CanBeNull] IDictionary<string, WireMockList<string>> headers = null,
[CanBeNull] string body = null,
bool useTransformer = true,
TransformerType transformerType = TransformerType.Handlebars)
{
Webhook = InitWebhook(url, method, headers, useTransformer, transformerType);
if (body != null) if (body != null)
{ {
Webhook.Request.BodyData = new BodyData Webhooks[0].Request.BodyData = new BodyData
{ {
BodyAsString = body, BodyAsString = body,
DetectedBodyType = BodyType.String, DetectedBodyType = BodyType.String,
DetectedBodyTypeFromContentType = BodyType.String DetectedBodyTypeFromContentType = BodyType.String
}; };
} }
return this; return this;
} }
/// <see cref="IRespondWithAProvider.WithWebhook(string, string, IDictionary{string, WireMockList{string}}, object, bool, TransformerType)"/> /// <see cref="IRespondWithAProvider.WithWebhook(string, string, IDictionary{string, WireMockList{string}}, object, bool, TransformerType)"/>
public IRespondWithAProvider WithWebhook( public IRespondWithAProvider WithWebhook(
[NotNull] string url, [NotNull] string url,
[CanBeNull] string method = "post", [CanBeNull] string method = "post",
[CanBeNull] IDictionary<string, WireMockList<string>> headers = null, [CanBeNull] IDictionary<string, WireMockList<string>> headers = null,
[CanBeNull] object body = null, [CanBeNull] object body = null,
bool useTransformer = true, bool useTransformer = true,
TransformerType transformerType = TransformerType.Handlebars) TransformerType transformerType = TransformerType.Handlebars)
{ {
Webhook = InitWebhook(url, method, headers, useTransformer, transformerType); Webhooks = new[] { InitWebhook(url, method, headers, useTransformer, transformerType) };
if (body != null) if (body != null)
{ {
Webhook.Request.BodyData = new BodyData Webhooks[0].Request.BodyData = new BodyData
{ {
BodyAsJson = body, BodyAsJson = body,
DetectedBodyType = BodyType.Json, DetectedBodyType = BodyType.Json,
DetectedBodyTypeFromContentType = BodyType.Json DetectedBodyTypeFromContentType = BodyType.Json
}; };
} }
return this; return this;
} }
private IWebhook InitWebhook( private IWebhook InitWebhook(
string url, string url,
string method, string method,
@@ -222,6 +225,6 @@ namespace WireMock.Server
TransformerType = transformerType TransformerType = transformerType
} }
}; };
} }
} }
} }

View File

@@ -470,10 +470,15 @@ namespace WireMock.Server
respondProvider = respondProvider.WillSetStateTo(mappingModel.SetStateTo); respondProvider = respondProvider.WillSetStateTo(mappingModel.SetStateTo);
} }
if (mappingModel.Webhook?.Request != null) if (mappingModel.Webhook != null)
{ {
respondProvider = respondProvider.WithWebhook(WebhookMapper.Map(mappingModel.Webhook)); 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); respondProvider.RespondWith(responseBuilder);

View File

@@ -24,31 +24,34 @@ namespace WireMock.Net.Tests.Serialization
} }
[Fact] [Fact]
public void ToMappingModel() public void ToMappingModel_With_SingleWebHook()
{ {
// Assign // Assign
var request = Request.Create(); var request = Request.Create();
var response = Response.Create(); var response = Response.Create();
var webhook = new Webhook var webhooks = new IWebhook[]
{ {
Request = new WebhookRequest new Webhook
{ {
Url = "https://test.com", Request = new WebhookRequest
Headers = new Dictionary<string, WireMockList<string>>
{ {
{ "Single", new WireMockList<string>("x") }, Url = "https://test.com",
{ "Multi", new WireMockList<string>("a", "b") } Headers = new Dictionary<string, WireMockList<string>>
}, {
Method = "post", { "Single", new WireMockList<string>("x") },
BodyData = new BodyData { "Multi", new WireMockList<string>("a", "b") }
{ },
BodyAsString = "b", Method = "post",
DetectedBodyType = BodyType.String, BodyData = new BodyData
DetectedBodyTypeFromContentType = BodyType.String {
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 // Act
var model = _sut.ToMappingModel(mapping); var model = _sut.ToMappingModel(mapping);
@@ -61,6 +64,8 @@ namespace WireMock.Net.Tests.Serialization
model.Response.UseTransformer.Should().BeNull(); model.Response.UseTransformer.Should().BeNull();
model.Response.Headers.Should().BeNull(); model.Response.Headers.Should().BeNull();
model.Webhooks.Should().BeNull();
model.Webhook.Request.Method.Should().Be("post"); model.Webhook.Request.Method.Should().Be("post");
model.Webhook.Request.Url.Should().Be("https://test.com"); model.Webhook.Request.Url.Should().Be("https://test.com");
model.Webhook.Request.Headers.Should().HaveCount(2); model.Webhook.Request.Headers.Should().HaveCount(2);
@@ -68,6 +73,80 @@ namespace WireMock.Net.Tests.Serialization
model.Webhook.Request.BodyAsJson.Should().BeNull(); 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<string, WireMockList<string>>
{
{ "One", new WireMockList<string>("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<string, WireMockList<string>>
{
{ "First", new WireMockList<string>("x") },
{ "Second", new WireMockList<string>("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] [Fact]
public void ToMappingModel_WithPriority_ReturnsPriority() public void ToMappingModel_WithPriority_ReturnsPriority()
{ {

View File

@@ -16,6 +16,74 @@ namespace WireMock.Net.Tests
{ {
public class WireMockServerWebhookTests 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] [Fact]
public async Task WireMockServer_WithWebhook_Should_Send_Message_To_Webhook() public async Task WireMockServer_WithWebhook_Should_Send_Message_To_Webhook()
{ {