diff --git a/DevProxy.Integration.Tests/BehaviorPluginsIntegrationTests.cs b/DevProxy.Integration.Tests/BehaviorPluginsIntegrationTests.cs index aa39cf27..8ff0687b 100644 --- a/DevProxy.Integration.Tests/BehaviorPluginsIntegrationTests.cs +++ b/DevProxy.Integration.Tests/BehaviorPluginsIntegrationTests.cs @@ -146,6 +146,23 @@ public async Task Latency_AddsConfiguredDelayBeforeForwarding() $"Expected >= {minMs - 100}ms of injected latency, saw {stopwatch.ElapsedMilliseconds}ms."); } + [Fact] + public void Latency_DelayRangeIncludesMaxMs() + { + var random = new Random(42); + var seen = new HashSet(); + for (var i = 0; i < 1000; i++) + { + var delay = LatencyPlugin.GetDelay(random, 0, 1); + Assert.InRange(delay, 0, 1); + _ = seen.Add(delay); + } + + Assert.Contains(1, seen); + Assert.Equal(5, LatencyPlugin.GetDelay(random, 5, 5)); + Assert.InRange(LatencyPlugin.GetDelay(random, int.MaxValue - 1, int.MaxValue), int.MaxValue - 1, int.MaxValue); + } + [Fact] public async Task RateLimiting_ThrottlesOnceResourcesAreExhausted() { diff --git a/DevProxy.Plugins/Behavior/LatencyPlugin.cs b/DevProxy.Plugins/Behavior/LatencyPlugin.cs index a47d9464..a892b042 100644 --- a/DevProxy.Plugins/Behavior/LatencyPlugin.cs +++ b/DevProxy.Plugins/Behavior/LatencyPlugin.cs @@ -103,15 +103,19 @@ public override async Task AfterStderrAsync(StdioResponseArgs e, CancellationTok private async Task ApplyDelayAsync(string context, LoggingContext loggingContext, CancellationToken cancellationToken) { - var delay = _random.Next(Configuration.MinMs, Configuration.MaxMs); + var delay = GetDelay(_random, Configuration.MinMs, Configuration.MaxMs); Logger.LogRequest($"Delaying {context} for {delay}ms", MessageType.Chaos, loggingContext); await Task.Delay(delay, cancellationToken); } private async Task ApplyDelayAsync(string context, StdioLoggingContext loggingContext, CancellationToken cancellationToken) { - var delay = _random.Next(Configuration.MinMs, Configuration.MaxMs); + var delay = GetDelay(_random, Configuration.MinMs, Configuration.MaxMs); Logger.LogRequest($"Delaying {context} for {delay}ms", MessageType.Chaos, loggingContext); await Task.Delay(delay, cancellationToken); } + + // maxMs is inclusive; use a 64-bit upper bound to avoid overflow when maxMs is int.MaxValue + internal static int GetDelay(Random random, int minMs, int maxMs) => + (int)random.NextInt64(minMs, (long)maxMs + 1); }