diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs
index f054487b..c3acc208 100644
--- a/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs
+++ b/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs
@@ -83,6 +83,16 @@ namespace WireMock.Admin.Mappings
///
public int? Delay { get; set; }
+ ///
+ /// Gets or sets the minimum random delay in milliseconds.
+ ///
+ public int? MinimumRandomDelay { get; set; }
+
+ ///
+ /// Gets or sets the maximum random delay in milliseconds.
+ ///
+ public int? MaximumRandomDelay { get; set; }
+
///
/// Gets or sets the Proxy URL.
///
diff --git a/src/WireMock.Net/ResponseBuilders/IDelayResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/IDelayResponseBuilder.cs
index fe0d3b1c..3682f90e 100644
--- a/src/WireMock.Net/ResponseBuilders/IDelayResponseBuilder.cs
+++ b/src/WireMock.Net/ResponseBuilders/IDelayResponseBuilder.cs
@@ -20,5 +20,13 @@ namespace WireMock.ResponseBuilders
/// The milliseconds to delay.
/// The .
IResponseBuilder WithDelay(int milliseconds);
+
+ ///
+ /// Introduce random delay
+ ///
+ /// Minimum milliseconds to delay
+ /// Maximum milliseconds to delay
+ /// The .
+ IResponseBuilder WithRandomDelay(int minimumMilliseconds = 0, int maximumMilliseconds = 60_000);
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/ResponseBuilders/Response.cs b/src/WireMock.Net/ResponseBuilders/Response.cs
index 33f90bc4..9fe97fac 100644
--- a/src/WireMock.Net/ResponseBuilders/Response.cs
+++ b/src/WireMock.Net/ResponseBuilders/Response.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Proxy;
@@ -24,10 +25,40 @@ namespace WireMock.ResponseBuilders
///
public partial class Response : IResponseBuilder
{
+ private static readonly ThreadLocal Random = new ThreadLocal(() => new Random(DateTime.UtcNow.Millisecond));
+
+ private TimeSpan? _delay;
+
+ ///
+ /// The minimum random delay in milliseconds.
+ ///
+ public int? MinimumDelayMilliseconds { get; private set; }
+
+ ///
+ /// The maximum random delay in milliseconds.
+ ///
+ public int? MaximumDelayMilliseconds { get; private set; }
+
///
/// The delay
///
- 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;
+ }
+ }
///
/// Gets a value indicating whether [use transformer].
@@ -334,6 +365,18 @@ namespace WireMock.ResponseBuilders
return WithDelay(TimeSpan.FromMilliseconds(milliseconds));
}
+ ///
+ 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;
+ }
+
///
public async Task<(ResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(RequestMessage requestMessage, IWireMockServerSettings settings)
{
diff --git a/src/WireMock.Net/Serialization/MappingConverter.cs b/src/WireMock.Net/Serialization/MappingConverter.cs
index 229d4ad4..d74fe17d 100644
--- a/src/WireMock.Net/Serialization/MappingConverter.cs
+++ b/src/WireMock.Net/Serialization/MappingConverter.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
using WireMock.Admin.Mappings;
using WireMock.Matchers.Request;
@@ -6,7 +7,6 @@ using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Settings;
using WireMock.Types;
-using WireMock.Validation;
namespace WireMock.Serialization
{
@@ -16,9 +16,7 @@ namespace WireMock.Serialization
public MappingConverter(MatcherMapper mapper)
{
- Check.NotNull(mapper, nameof(mapper));
-
- _mapper = mapper;
+ _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
}
public MappingModel ToMappingModel(IMapping mapping)
@@ -81,12 +79,19 @@ namespace WireMock.Serialization
Matchers = _mapper.Map(pm.Matchers)
}).ToList() : null
},
- Response = new ResponseModel
- {
- Delay = (int?)response.Delay?.TotalMilliseconds
- }
+ Response = new ResponseModel()
};
+ 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)
{
mappingModel.Webhook = WebhookMapper.Map(mapping.Webhooks[0]);
diff --git a/src/WireMock.Net/Server/WireMockServer.Admin.cs b/src/WireMock.Net/Server/WireMockServer.Admin.cs
index eda99b6b..0c6034ec 100644
--- a/src/WireMock.Net/Server/WireMockServer.Admin.cs
+++ b/src/WireMock.Net/Server/WireMockServer.Admin.cs
@@ -782,6 +782,10 @@ namespace WireMock.Server
{
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)
{
diff --git a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs
index de2a4776..c820a41a 100644
--- a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs
+++ b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using FluentAssertions;
using WireMock.Models;
@@ -163,5 +163,61 @@ namespace WireMock.Net.Tests.Serialization
model.Priority.Should().Be(42);
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);
+ }
}
}
\ No newline at end of file
diff --git a/test/WireMock.Net.Tests/WireMockServerTests.cs b/test/WireMock.Net.Tests/WireMockServerTests.cs
index 5cb939b8..be1123f3 100644
--- a/test/WireMock.Net.Tests/WireMockServerTests.cs
+++ b/test/WireMock.Net.Tests/WireMockServerTests.cs
@@ -115,6 +115,38 @@ namespace WireMock.Net.Tests
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 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]
public async Task WireMockServer_Should_delay_responses()
{