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)); } }