Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions DevProxy.Integration.Tests/BehaviorPluginsIntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,46 @@ public async Task GenericRandomError_Rate100_OverridesOriginWithConfiguredError(
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
}

[Fact]
public async Task GenericRandomError_Rate99_SometimesPassesThrough()
{
await using var origin = await FakeOrigin.StartAsync();
var urls = KestrelProxyHarness.BuildUrlsToWatch(origin.Host);

// rate:99 ⇒ ~1% of requests pass through. Previously rate:99 behaved like rate:100.
var config = PluginConfig.FromJson($$"""
{
"rate": 99,
"errors": [
{
"request": { "url": "http://{{origin.Host}}/*" },
"responses": [ { "statusCode": 503 } ]
}
]
}
""");
var plugin = new GenericRandomErrorPlugin(
SharedHttpClient,
NullLogger<GenericRandomErrorPlugin>.Instance,
urls,
ProxyConfig,
config);

await using var proxy = await KestrelProxyHarness.StartAsync(
origin.Host, [plugin]);
using var client = proxy.CreateHttpClient();

// Probability of 2000 consecutive failures at 99% is ~2e-9.
var passedThrough = false;
for (var i = 0; i < 2000 && !passedThrough; i++)
{
using var response = await client.GetAsync(new Uri($"http://{origin.Host}/get"));
passedThrough = response.StatusCode == HttpStatusCode.OK;
}

Assert.True(passedThrough);
}

[Fact]
public async Task GenericRandomError_DynamicRetryAfterOnNon429_IsResolved()
{
Expand Down
2 changes: 1 addition & 1 deletion DevProxy.Plugins/Behavior/GenericRandomErrorPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public override Task BeforeRequestAsync(ProxyRequestArgs e, CancellationToken ca
}

// uses config to determine if a request should be failed
private GenericRandomErrorFailMode ShouldFail() => _random.Next(1, 100) <= Configuration.Rate ? GenericRandomErrorFailMode.Random : GenericRandomErrorFailMode.PassThru;
private GenericRandomErrorFailMode ShouldFail() => _random.Next(0, 100) < Configuration.Rate ? GenericRandomErrorFailMode.Random : GenericRandomErrorFailMode.PassThru;

private void FailResponse(ProxyRequestArgs e)
{
Expand Down
2 changes: 1 addition & 1 deletion DevProxy.Plugins/Behavior/GraphRandomErrorPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ public override Task BeforeRequestAsync(ProxyRequestArgs e, CancellationToken ca
}

// uses config to determine if a request should be failed
private GraphRandomErrorFailMode ShouldFail() => _random.Next(1, 100) <= Configuration.Rate ? GraphRandomErrorFailMode.Random : GraphRandomErrorFailMode.PassThru;
private GraphRandomErrorFailMode ShouldFail() => _random.Next(0, 100) < Configuration.Rate ? GraphRandomErrorFailMode.Random : GraphRandomErrorFailMode.PassThru;

private void FailResponse(ProxyRequestArgs e)
{
Expand Down
Loading