using w4c_workflows.Services.Security;
using w4c_workflows.Services.Nodes;
using Xunit;
namespace w4c_workflows.Tests;
///
/// Tests for the run-scoped outbound-request budget and response-size cap.
///
public class NodeRequestBudgetTests
{
[Fact]
public void Reserves_until_the_cap_then_denies()
{
var policy = EgressTestData.Quota(o => o.MaxRequestsPerRun = 2);
var state = new Dictionary();
Assert.True(policy.TryReserveRequest(state, out var first));
Assert.Equal(1, first);
Assert.True(policy.TryReserveRequest(state, out var second));
Assert.Equal(2, second);
Assert.False(policy.TryReserveRequest(state, out var third));
Assert.Equal(3, third);
}
[Fact]
public void Zero_cap_means_unlimited_and_does_not_touch_state()
{
var policy = EgressTestData.Quota(o => o.MaxRequestsPerRun = 0);
var state = new Dictionary();
for (var i = 0; i < 1_000; i++)
Assert.True(policy.TryReserveRequest(state, out _));
Assert.Empty(state);
}
[Fact]
public void Separate_runs_have_separate_budgets()
{
var policy = EgressTestData.Quota(o => o.MaxRequestsPerRun = 1);
Assert.True(policy.TryReserveRequest(new Dictionary(), out _));
Assert.True(policy.TryReserveRequest(new Dictionary(), out _));
}
[Fact]
public void Counter_is_stored_under_the_documented_state_key()
{
var policy = EgressTestData.Quota(o => o.MaxRequestsPerRun = 5);
var state = new Dictionary();
policy.TryReserveRequest(state, out _);
Assert.True(state.ContainsKey(NodeRequestBudget.RequestCounterKey));
}
[Fact]
public void Response_limit_is_inclusive()
{
var capped = EgressTestData.Quota(o => o.MaxResponseBytes = 10);
Assert.True(capped.IsResponseWithinLimit(0));
Assert.True(capped.IsResponseWithinLimit(10));
Assert.False(capped.IsResponseWithinLimit(11));
}
[Fact]
public void Zero_response_limit_is_unlimited()
{
var unlimited = EgressTestData.Quota(o => o.MaxResponseBytes = 0);
Assert.True(unlimited.IsResponseWithinLimit(long.MaxValue));
}
}