mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-18 23:20:11 +02:00
Add support for multiple webhooks (#615)
This commit is contained in:
@@ -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>
|
||||||
@@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
namespace WireMock.Models
|
||||||
using JetBrains.Annotations;
|
|
||||||
using WireMock.Types;
|
|
||||||
|
|
||||||
namespace WireMock.Models
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Webhook
|
/// Webhook
|
||||||
|
|||||||
@@ -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}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user