Refactor code structure and optimize performance across multiple modules
This commit is contained in:
@@ -8,11 +8,13 @@ using StellaOps.Router.Gateway.State;
|
||||
using StellaOps.Router.Transport.InMemory;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Router.Gateway.Tests;
|
||||
|
||||
public sealed class ConnectionManagerTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task StartAsync_WhenHelloInvalid_RejectsAndClosesChannel()
|
||||
{
|
||||
var (manager, server, registry, routingState) = Create();
|
||||
@@ -59,7 +61,8 @@ public sealed class ConnectionManagerTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task WhenClientDisconnects_RemovesFromRoutingState()
|
||||
{
|
||||
var (manager, server, registry, routingState) = Create();
|
||||
@@ -102,7 +105,8 @@ public sealed class ConnectionManagerTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task WhenMultipleClientsConnect_TracksAndCleansIndependently()
|
||||
{
|
||||
var (manager, server, registry, routingState) = Create();
|
||||
|
||||
@@ -6,11 +6,13 @@ using StellaOps.Router.Gateway.Configuration;
|
||||
using StellaOps.Router.Gateway.Routing;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Router.Gateway.Tests;
|
||||
|
||||
public sealed class DefaultRoutingPluginTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ChooseInstanceAsync_WhenNoCandidates_ReturnsNull()
|
||||
{
|
||||
var plugin = CreatePlugin(gatewayRegion: "eu1");
|
||||
@@ -38,7 +40,8 @@ public sealed class DefaultRoutingPluginTests
|
||||
decision.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ChooseInstanceAsync_WhenRequestedVersionDoesNotMatch_ReturnsNull()
|
||||
{
|
||||
var plugin = CreatePlugin(
|
||||
@@ -63,7 +66,8 @@ public sealed class DefaultRoutingPluginTests
|
||||
decision.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ChooseInstanceAsync_PrefersHealthyOverDegraded()
|
||||
{
|
||||
var plugin = CreatePlugin(
|
||||
@@ -93,7 +97,8 @@ public sealed class DefaultRoutingPluginTests
|
||||
decision!.Connection.ConnectionId.Should().Be("inv-healthy");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ChooseInstanceAsync_PrefersLocalRegionOverRemote()
|
||||
{
|
||||
var plugin = CreatePlugin(
|
||||
@@ -120,7 +125,8 @@ public sealed class DefaultRoutingPluginTests
|
||||
decision!.Connection.ConnectionId.Should().Be("inv-eu1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ChooseInstanceAsync_WhenNoLocal_UsesNeighborRegion()
|
||||
{
|
||||
var plugin = CreatePlugin(
|
||||
@@ -148,7 +154,8 @@ public sealed class DefaultRoutingPluginTests
|
||||
decision!.Connection.ConnectionId.Should().Be("inv-eu2");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ChooseInstanceAsync_WhenTied_UsesRoundRobin()
|
||||
{
|
||||
var plugin = CreatePlugin(
|
||||
|
||||
@@ -4,11 +4,13 @@ using StellaOps.Router.Common.Models;
|
||||
using StellaOps.Router.Gateway.State;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Router.Gateway.Tests;
|
||||
|
||||
public sealed class InMemoryRoutingStateTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ResolveEndpoint_WhenExactMatch_ReturnsEndpointDescriptor()
|
||||
{
|
||||
var routingState = new InMemoryRoutingState();
|
||||
@@ -33,7 +35,8 @@ public sealed class InMemoryRoutingStateTests
|
||||
resolved.Path.Should().Be("/items");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ResolveEndpoint_WhenTemplateMatch_ReturnsEndpointDescriptor()
|
||||
{
|
||||
var routingState = new InMemoryRoutingState();
|
||||
@@ -55,7 +58,8 @@ public sealed class InMemoryRoutingStateTests
|
||||
resolved!.Path.Should().Be("/items/{sku}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void RemoveConnection_RemovesEndpointsFromIndex()
|
||||
{
|
||||
var routingState = new InMemoryRoutingState();
|
||||
@@ -78,7 +82,8 @@ public sealed class InMemoryRoutingStateTests
|
||||
routingState.GetAllConnections().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void GetConnectionsFor_FiltersByServiceAndVersion()
|
||||
{
|
||||
var routingState = new InMemoryRoutingState();
|
||||
|
||||
@@ -2,11 +2,13 @@ using FluentAssertions;
|
||||
using StellaOps.Router.Gateway.RateLimit;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Router.Gateway.Tests;
|
||||
|
||||
public sealed class InMemoryValkeyRateLimitStoreTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task IncrementAndCheckAsync_UsesSmallestWindowAsRepresentativeWhenAllowed()
|
||||
{
|
||||
var store = new InMemoryValkeyRateLimitStore();
|
||||
@@ -25,7 +27,8 @@ public sealed class InMemoryValkeyRateLimitStoreTests
|
||||
result.RetryAfterSeconds.Should().Be(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task IncrementAndCheckAsync_DeniesWhenLimitExceeded()
|
||||
{
|
||||
var store = new InMemoryValkeyRateLimitStore();
|
||||
|
||||
@@ -2,11 +2,13 @@ using FluentAssertions;
|
||||
using StellaOps.Router.Gateway.RateLimit;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Router.Gateway.Tests;
|
||||
|
||||
public sealed class InstanceRateLimiterTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void TryAcquire_ReportsMostConstrainedRuleWhenAllowed()
|
||||
{
|
||||
var limiter = new InstanceRateLimiter(
|
||||
@@ -24,7 +26,8 @@ public sealed class InstanceRateLimiterTests
|
||||
decision.CurrentCount.Should().Be(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void TryAcquire_DeniesWhenAnyRuleIsExceeded()
|
||||
{
|
||||
var limiter = new InstanceRateLimiter(
|
||||
|
||||
@@ -2,11 +2,13 @@ using FluentAssertions;
|
||||
using StellaOps.Router.Gateway.RateLimit;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Router.Gateway.Tests;
|
||||
|
||||
public sealed class LimitInheritanceResolverTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ResolveEnvironmentTarget_UsesEnvironmentDefaultsWhenNoMicroserviceOverride()
|
||||
{
|
||||
var config = new RateLimitConfig
|
||||
@@ -32,7 +34,8 @@ public sealed class LimitInheritanceResolverTests
|
||||
target.Rules[0].MaxRequests.Should().Be(600);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ResolveEnvironmentTarget_UsesMicroserviceOverrideWhenPresent()
|
||||
{
|
||||
var config = new RateLimitConfig
|
||||
@@ -65,7 +68,8 @@ public sealed class LimitInheritanceResolverTests
|
||||
target.Rules[0].MaxRequests.Should().Be(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ResolveEnvironmentTarget_DisablesWhenNoRulesAtAnyLevel()
|
||||
{
|
||||
var config = new RateLimitConfig
|
||||
@@ -84,7 +88,8 @@ public sealed class LimitInheritanceResolverTests
|
||||
target.Enabled.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ResolveEnvironmentTarget_UsesRouteOverrideWhenPresent()
|
||||
{
|
||||
var config = new RateLimitConfig
|
||||
@@ -126,7 +131,8 @@ public sealed class LimitInheritanceResolverTests
|
||||
target.Rules[0].MaxRequests.Should().Be(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ResolveEnvironmentTarget_DoesNotTreatRouteAsOverrideWhenItHasNoRules()
|
||||
{
|
||||
var config = new RateLimitConfig
|
||||
|
||||
@@ -19,7 +19,8 @@ namespace StellaOps.Router.Gateway.Tests;
|
||||
|
||||
public sealed class MiddlewareErrorScenarioTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task EndpointResolutionMiddleware_WhenNoEndpoint_Returns404StructuredError()
|
||||
{
|
||||
var context = CreateContext(method: "GET", path: "/missing");
|
||||
@@ -45,7 +46,8 @@ public sealed class MiddlewareErrorScenarioTests
|
||||
body.GetProperty("traceId").GetString().Should().Be("trace-1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task RoutingDecisionMiddleware_WhenNoInstances_Returns503StructuredError()
|
||||
{
|
||||
var context = CreateContext(method: "GET", path: "/items");
|
||||
@@ -84,7 +86,8 @@ public sealed class MiddlewareErrorScenarioTests
|
||||
body.GetProperty("version").GetString().Should().Be("1.0.0");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task AuthorizationMiddleware_WhenMissingClaim_Returns403StructuredError()
|
||||
{
|
||||
var context = CreateContext(method: "GET", path: "/items");
|
||||
@@ -128,7 +131,8 @@ public sealed class MiddlewareErrorScenarioTests
|
||||
body.GetProperty("details").GetProperty("requiredClaimValue").GetString().Should().Be("admin");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task GlobalErrorHandlerMiddleware_WhenUnhandledException_Returns500StructuredError()
|
||||
{
|
||||
var context = CreateContext(method: "GET", path: "/boom");
|
||||
@@ -173,6 +177,7 @@ public sealed class MiddlewareErrorScenarioTests
|
||||
{
|
||||
context.Response.Body.Position = 0;
|
||||
using var doc = JsonDocument.Parse(context.Response.Body);
|
||||
using StellaOps.TestKit;
|
||||
return doc.RootElement.Clone();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@ using Microsoft.Extensions.Configuration;
|
||||
using StellaOps.Router.Gateway.RateLimit;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Router.Gateway.Tests;
|
||||
|
||||
public sealed class RateLimitConfigTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Load_BindsRoutesAndRules()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
@@ -41,7 +43,8 @@ public sealed class RateLimitConfigTests
|
||||
route.Rules[0].MaxRequests.Should().Be(50);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Load_ThrowsForInvalidRegexRoute()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
|
||||
@@ -11,7 +11,8 @@ namespace StellaOps.Router.Gateway.Tests;
|
||||
|
||||
public sealed class RateLimitMiddlewareTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task InvokeAsync_EnforcesEnvironmentLimit_WithRetryAfterAndJsonBody()
|
||||
{
|
||||
var config = new RateLimitConfig
|
||||
@@ -86,6 +87,7 @@ public sealed class RateLimitMiddlewareTests
|
||||
var body = await new StreamReader(context.Response.Body, Encoding.UTF8).ReadToEndAsync();
|
||||
using var json = JsonDocument.Parse(body);
|
||||
|
||||
using StellaOps.TestKit;
|
||||
json.RootElement.GetProperty("error").GetString().Should().Be("rate_limit_exceeded");
|
||||
json.RootElement.GetProperty("scope").GetString().Should().Be("environment");
|
||||
json.RootElement.GetProperty("limit").GetInt64().Should().Be(1);
|
||||
|
||||
@@ -2,11 +2,13 @@ using FluentAssertions;
|
||||
using StellaOps.Router.Gateway.RateLimit;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Router.Gateway.Tests;
|
||||
|
||||
public sealed class RateLimitRouteMatcherTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void TryMatch_ExactBeatsPrefixAndRegex()
|
||||
{
|
||||
var microservice = new MicroserviceLimitsConfig
|
||||
@@ -43,7 +45,8 @@ public sealed class RateLimitRouteMatcherTests
|
||||
match!.Value.Name.Should().Be("exact");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void TryMatch_LongestPrefixWins()
|
||||
{
|
||||
var microservice = new MicroserviceLimitsConfig
|
||||
|
||||
@@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging.Abstractions;
|
||||
using StellaOps.Router.Gateway.RateLimit;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Router.Gateway.Tests;
|
||||
|
||||
public sealed class RateLimitServiceTests
|
||||
@@ -26,7 +27,8 @@ public sealed class RateLimitServiceTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task CheckLimitAsync_DoesNotInvokeEnvironmentLimiterUntilActivationGateTriggers()
|
||||
{
|
||||
var config = new RateLimitConfig
|
||||
@@ -58,7 +60,8 @@ public sealed class RateLimitServiceTests
|
||||
store.Calls.Should().Be(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task CheckLimitAsync_EnforcesPerRouteEnvironmentRules()
|
||||
{
|
||||
var config = new RateLimitConfig
|
||||
|
||||
@@ -9,7 +9,8 @@ namespace StellaOps.Router.Gateway.Tests;
|
||||
|
||||
public sealed class RouterNodeConfigValidationTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void RouterNodeConfig_WhenRegionMissing_ThrowsOptionsValidationException()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
@@ -22,7 +23,8 @@ public sealed class RouterNodeConfigValidationTests
|
||||
act.Should().Throw<OptionsValidationException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void RouterNodeConfig_WhenRegionProvided_GeneratesNodeIdIfMissing()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
@@ -31,6 +33,7 @@ public sealed class RouterNodeConfigValidationTests
|
||||
|
||||
using var provider = services.BuildServiceProvider();
|
||||
|
||||
using StellaOps.TestKit;
|
||||
var config = provider.GetRequiredService<IOptions<RouterNodeConfig>>().Value;
|
||||
|
||||
config.Region.Should().Be("test");
|
||||
|
||||
Reference in New Issue
Block a user