mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-23 17:28:55 +02:00
Implement Random Delay (#633)
* implement random delays * fixing CodeFactor issue * fix code comments * ... * UT Co-authored-by: Michael Yarichuk <michael.yarichuk@gmail.com>
This commit is contained in:
@@ -83,6 +83,16 @@ namespace WireMock.Admin.Mappings
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int? Delay { get; set; }
|
public int? Delay { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the minimum random delay in milliseconds.
|
||||||
|
/// </summary>
|
||||||
|
public int? MinimumRandomDelay { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the maximum random delay in milliseconds.
|
||||||
|
/// </summary>
|
||||||
|
public int? MaximumRandomDelay { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Proxy URL.
|
/// Gets or sets the Proxy URL.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -20,5 +20,13 @@ namespace WireMock.ResponseBuilders
|
|||||||
/// <param name="milliseconds">The milliseconds to delay.</param>
|
/// <param name="milliseconds">The milliseconds to delay.</param>
|
||||||
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
|
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
|
||||||
IResponseBuilder WithDelay(int milliseconds);
|
IResponseBuilder WithDelay(int milliseconds);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Introduce random delay
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="minimumMilliseconds">Minimum milliseconds to delay</param>
|
||||||
|
/// <param name="maximumMilliseconds">Maximum milliseconds to delay</param>
|
||||||
|
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
|
||||||
|
IResponseBuilder WithRandomDelay(int minimumMilliseconds = 0, int maximumMilliseconds = 60_000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using WireMock.Proxy;
|
using WireMock.Proxy;
|
||||||
@@ -24,10 +25,40 @@ namespace WireMock.ResponseBuilders
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class Response : IResponseBuilder
|
public partial class Response : IResponseBuilder
|
||||||
{
|
{
|
||||||
|
private static readonly ThreadLocal<Random> Random = new ThreadLocal<Random>(() => new Random(DateTime.UtcNow.Millisecond));
|
||||||
|
|
||||||
|
private TimeSpan? _delay;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The minimum random delay in milliseconds.
|
||||||
|
/// </summary>
|
||||||
|
public int? MinimumDelayMilliseconds { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum random delay in milliseconds.
|
||||||
|
/// </summary>
|
||||||
|
public int? MaximumDelayMilliseconds { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The delay
|
/// The delay
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan? Delay { get; private set; }
|
public TimeSpan? Delay
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (MinimumDelayMilliseconds != null && MaximumDelayMilliseconds != null)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromMilliseconds(Random.Value.Next(MinimumDelayMilliseconds.Value, MaximumDelayMilliseconds.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return _delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
_delay = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether [use transformer].
|
/// Gets a value indicating whether [use transformer].
|
||||||
@@ -334,6 +365,18 @@ namespace WireMock.ResponseBuilders
|
|||||||
return WithDelay(TimeSpan.FromMilliseconds(milliseconds));
|
return WithDelay(TimeSpan.FromMilliseconds(milliseconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IDelayResponseBuilder.WithRandomDelay(int, int)"/>
|
||||||
|
public IResponseBuilder WithRandomDelay(int minimumMilliseconds = 0, int maximumMilliseconds = 60_000)
|
||||||
|
{
|
||||||
|
Check.Condition(minimumMilliseconds, min => min >= 0, nameof(minimumMilliseconds));
|
||||||
|
Check.Condition(maximumMilliseconds, max => max > minimumMilliseconds, nameof(maximumMilliseconds));
|
||||||
|
|
||||||
|
MinimumDelayMilliseconds = minimumMilliseconds;
|
||||||
|
MaximumDelayMilliseconds = maximumMilliseconds;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IResponseProvider.ProvideResponseAsync(RequestMessage, IWireMockServerSettings)"/>
|
/// <inheritdoc cref="IResponseProvider.ProvideResponseAsync(RequestMessage, IWireMockServerSettings)"/>
|
||||||
public async Task<(ResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(RequestMessage requestMessage, IWireMockServerSettings settings)
|
public async Task<(ResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(RequestMessage requestMessage, IWireMockServerSettings settings)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
@@ -6,7 +7,6 @@ using WireMock.RequestBuilders;
|
|||||||
using WireMock.ResponseBuilders;
|
using WireMock.ResponseBuilders;
|
||||||
using WireMock.Settings;
|
using WireMock.Settings;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
using WireMock.Validation;
|
|
||||||
|
|
||||||
namespace WireMock.Serialization
|
namespace WireMock.Serialization
|
||||||
{
|
{
|
||||||
@@ -16,9 +16,7 @@ namespace WireMock.Serialization
|
|||||||
|
|
||||||
public MappingConverter(MatcherMapper mapper)
|
public MappingConverter(MatcherMapper mapper)
|
||||||
{
|
{
|
||||||
Check.NotNull(mapper, nameof(mapper));
|
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
|
||||||
|
|
||||||
_mapper = mapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MappingModel ToMappingModel(IMapping mapping)
|
public MappingModel ToMappingModel(IMapping mapping)
|
||||||
@@ -81,12 +79,19 @@ namespace WireMock.Serialization
|
|||||||
Matchers = _mapper.Map(pm.Matchers)
|
Matchers = _mapper.Map(pm.Matchers)
|
||||||
}).ToList() : null
|
}).ToList() : null
|
||||||
},
|
},
|
||||||
Response = new ResponseModel
|
Response = new ResponseModel()
|
||||||
{
|
|
||||||
Delay = (int?)response.Delay?.TotalMilliseconds
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (response.MinimumDelayMilliseconds >= 0 || response.MaximumDelayMilliseconds > 0)
|
||||||
|
{
|
||||||
|
mappingModel.Response.MinimumRandomDelay = response.MinimumDelayMilliseconds;
|
||||||
|
mappingModel.Response.MaximumRandomDelay = response.MaximumDelayMilliseconds;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mappingModel.Response.Delay = (int?)response.Delay?.TotalMilliseconds;
|
||||||
|
}
|
||||||
|
|
||||||
if (mapping.Webhooks?.Length == 1)
|
if (mapping.Webhooks?.Length == 1)
|
||||||
{
|
{
|
||||||
mappingModel.Webhook = WebhookMapper.Map(mapping.Webhooks[0]);
|
mappingModel.Webhook = WebhookMapper.Map(mapping.Webhooks[0]);
|
||||||
|
|||||||
@@ -782,6 +782,10 @@ namespace WireMock.Server
|
|||||||
{
|
{
|
||||||
responseBuilder = responseBuilder.WithDelay(responseModel.Delay.Value);
|
responseBuilder = responseBuilder.WithDelay(responseModel.Delay.Value);
|
||||||
}
|
}
|
||||||
|
else if (responseModel.MinimumRandomDelay >= 0 || responseModel.MaximumRandomDelay > 0)
|
||||||
|
{
|
||||||
|
responseBuilder = responseBuilder.WithRandomDelay(responseModel.MinimumRandomDelay ?? 0, responseModel.MaximumRandomDelay ?? 60_000);
|
||||||
|
}
|
||||||
|
|
||||||
if (responseModel.UseTransformer == true)
|
if (responseModel.UseTransformer == true)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
@@ -163,5 +163,61 @@ namespace WireMock.Net.Tests.Serialization
|
|||||||
model.Priority.Should().Be(42);
|
model.Priority.Should().Be(42);
|
||||||
model.Response.UseTransformer.Should().BeTrue();
|
model.Response.UseTransformer.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToMappingModel_WithDelay_ReturnsCorrectModel()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
int delay = 1000;
|
||||||
|
var request = Request.Create();
|
||||||
|
var response = Response.Create().WithDelay(delay);
|
||||||
|
var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 42, null, null, null, null, null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var model = _sut.ToMappingModel(mapping);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
model.Should().NotBeNull();
|
||||||
|
model.Response.Delay.Should().Be(delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToMappingModel_WithRandomMininumDelay_ReturnsCorrectModel()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
int minimumDelay = 1000;
|
||||||
|
var request = Request.Create();
|
||||||
|
var response = Response.Create().WithRandomDelay(minimumDelay);
|
||||||
|
var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 42, null, null, null, null, null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var model = _sut.ToMappingModel(mapping);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
model.Should().NotBeNull();
|
||||||
|
model.Response.Delay.Should().BeNull();
|
||||||
|
model.Response.MinimumRandomDelay.Should().Be(minimumDelay);
|
||||||
|
model.Response.MaximumRandomDelay.Should().Be(60_000);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToMappingModel_WithRandomDelay_ReturnsCorrectModel()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
int minimumDelay = 1000;
|
||||||
|
int maximumDelay = 2000;
|
||||||
|
var request = Request.Create();
|
||||||
|
var response = Response.Create().WithRandomDelay(minimumDelay, maximumDelay);
|
||||||
|
var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 42, null, null, null, null, null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var model = _sut.ToMappingModel(mapping);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
model.Should().NotBeNull();
|
||||||
|
model.Response.Delay.Should().BeNull();
|
||||||
|
model.Response.MinimumRandomDelay.Should().Be(minimumDelay);
|
||||||
|
model.Response.MaximumRandomDelay.Should().Be(maximumDelay);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,6 +115,38 @@ namespace WireMock.Net.Tests
|
|||||||
server.Stop();
|
server.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task WireMockServer_Should_randomly_delay_responses_for_a_given_route()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = WireMockServer.Start();
|
||||||
|
|
||||||
|
server
|
||||||
|
.Given(Request.Create()
|
||||||
|
.WithPath("/*"))
|
||||||
|
.RespondWith(Response.Create()
|
||||||
|
.WithBody(@"{ msg: ""Hello world!""}")
|
||||||
|
.WithRandomDelay(10, 1000));
|
||||||
|
|
||||||
|
var watch = new Stopwatch();
|
||||||
|
watch.Start();
|
||||||
|
|
||||||
|
var httClient = new HttpClient();
|
||||||
|
async Task<long> ExecuteTimedRequestAsync()
|
||||||
|
{
|
||||||
|
watch.Reset();
|
||||||
|
await httClient.GetStringAsync("http://localhost:" + server.Ports[0] + "/foo");
|
||||||
|
return watch.ElapsedMilliseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await ExecuteTimedRequestAsync();
|
||||||
|
await ExecuteTimedRequestAsync();
|
||||||
|
await ExecuteTimedRequestAsync();
|
||||||
|
|
||||||
|
server.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task WireMockServer_Should_delay_responses()
|
public async Task WireMockServer_Should_delay_responses()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user