Files
git.stella-ops.org/tests/StellaOps.Router.Gateway.Tests/LimitInheritanceResolverTests.cs
2025-12-18 00:47:24 +02:00

167 lines
6.4 KiB
C#

using FluentAssertions;
using StellaOps.Router.Gateway.RateLimit;
using Xunit;
namespace StellaOps.Router.Gateway.Tests;
public sealed class LimitInheritanceResolverTests
{
[Fact]
public void ResolveEnvironmentTarget_UsesEnvironmentDefaultsWhenNoMicroserviceOverride()
{
var config = new RateLimitConfig
{
ActivationThresholdPer5Min = 0,
ForEnvironment = new EnvironmentLimitsConfig
{
ValkeyConnection = "localhost:6379",
ValkeyBucket = "bucket",
Rules = [new RateLimitRule { PerSeconds = 60, MaxRequests = 600 }],
}
}.Validate();
var resolver = new LimitInheritanceResolver(config);
var target = resolver.ResolveEnvironmentTarget("scanner", "/api/scans");
target.Enabled.Should().BeTrue();
target.Kind.Should().Be(RateLimitTargetKind.EnvironmentDefault);
target.RouteName.Should().BeNull();
target.TargetKey.Should().Be("scanner");
target.Rules.Should().ContainSingle();
target.Rules[0].PerSeconds.Should().Be(60);
target.Rules[0].MaxRequests.Should().Be(600);
}
[Fact]
public void ResolveEnvironmentTarget_UsesMicroserviceOverrideWhenPresent()
{
var config = new RateLimitConfig
{
ActivationThresholdPer5Min = 0,
ForEnvironment = new EnvironmentLimitsConfig
{
ValkeyConnection = "localhost:6379",
ValkeyBucket = "bucket",
Rules = [new RateLimitRule { PerSeconds = 60, MaxRequests = 600 }],
Microservices = new Dictionary<string, MicroserviceLimitsConfig>(StringComparer.OrdinalIgnoreCase)
{
["scanner"] = new MicroserviceLimitsConfig
{
Rules = [new RateLimitRule { PerSeconds = 10, MaxRequests = 1 }],
}
}
}
}.Validate();
var resolver = new LimitInheritanceResolver(config);
var target = resolver.ResolveEnvironmentTarget("scanner", "/api/scans");
target.Enabled.Should().BeTrue();
target.Kind.Should().Be(RateLimitTargetKind.Microservice);
target.RouteName.Should().BeNull();
target.TargetKey.Should().Be("scanner");
target.Rules.Should().ContainSingle();
target.Rules[0].PerSeconds.Should().Be(10);
target.Rules[0].MaxRequests.Should().Be(1);
}
[Fact]
public void ResolveEnvironmentTarget_DisablesWhenNoRulesAtAnyLevel()
{
var config = new RateLimitConfig
{
ActivationThresholdPer5Min = 0,
ForEnvironment = new EnvironmentLimitsConfig
{
ValkeyConnection = "localhost:6379",
ValkeyBucket = "bucket",
}
}.Validate();
var resolver = new LimitInheritanceResolver(config);
var target = resolver.ResolveEnvironmentTarget("scanner", "/api/scans");
target.Enabled.Should().BeFalse();
}
[Fact]
public void ResolveEnvironmentTarget_UsesRouteOverrideWhenPresent()
{
var config = new RateLimitConfig
{
ActivationThresholdPer5Min = 0,
ForEnvironment = new EnvironmentLimitsConfig
{
ValkeyConnection = "localhost:6379",
ValkeyBucket = "bucket",
Rules = [new RateLimitRule { PerSeconds = 60, MaxRequests = 600 }],
Microservices = new Dictionary<string, MicroserviceLimitsConfig>(StringComparer.OrdinalIgnoreCase)
{
["scanner"] = new MicroserviceLimitsConfig
{
Rules = [new RateLimitRule { PerSeconds = 60, MaxRequests = 600 }],
Routes = new Dictionary<string, RouteLimitsConfig>(StringComparer.OrdinalIgnoreCase)
{
["scan_submit"] = new RouteLimitsConfig
{
Pattern = "/api/scans",
MatchType = RouteMatchType.Exact,
Rules = [new RateLimitRule { PerSeconds = 300, MaxRequests = 1 }]
}
}
}
}
}
}.Validate();
var resolver = new LimitInheritanceResolver(config);
var target = resolver.ResolveEnvironmentTarget("scanner", "/api/scans");
target.Enabled.Should().BeTrue();
target.Kind.Should().Be(RateLimitTargetKind.Route);
target.RouteName.Should().Be("scan_submit");
target.TargetKey.Should().Be("scanner:scan_submit");
target.Rules.Should().ContainSingle();
target.Rules[0].PerSeconds.Should().Be(300);
target.Rules[0].MaxRequests.Should().Be(1);
}
[Fact]
public void ResolveEnvironmentTarget_DoesNotTreatRouteAsOverrideWhenItHasNoRules()
{
var config = new RateLimitConfig
{
ActivationThresholdPer5Min = 0,
ForEnvironment = new EnvironmentLimitsConfig
{
ValkeyConnection = "localhost:6379",
ValkeyBucket = "bucket",
Rules = [new RateLimitRule { PerSeconds = 60, MaxRequests = 600 }],
Microservices = new Dictionary<string, MicroserviceLimitsConfig>(StringComparer.OrdinalIgnoreCase)
{
["scanner"] = new MicroserviceLimitsConfig
{
Rules = [new RateLimitRule { PerSeconds = 60, MaxRequests = 600 }],
Routes = new Dictionary<string, RouteLimitsConfig>(StringComparer.OrdinalIgnoreCase)
{
["named_only"] = new RouteLimitsConfig
{
Pattern = "/api/scans",
MatchType = RouteMatchType.Exact
}
}
}
}
}
}.Validate();
var resolver = new LimitInheritanceResolver(config);
var target = resolver.ResolveEnvironmentTarget("scanner", "/api/scans");
target.Enabled.Should().BeTrue();
target.Kind.Should().Be(RateLimitTargetKind.Microservice);
target.RouteName.Should().BeNull();
target.TargetKey.Should().Be("scanner");
}
}