Files
git.stella-ops.org/tests/StellaOps.Router.Gateway.Tests/ConnectionManagerTests.cs
master 91f3610b9d Refactor and enhance tests for call graph extractors and connection management
- Updated JavaScriptCallGraphExtractorTests to improve naming conventions and test cases for Azure Functions, CLI commands, and socket handling.
- Modified NodeCallGraphExtractorTests to correctly assert exceptions for null inputs.
- Enhanced WitnessModalComponent tests in Angular to use Jasmine spies and improved assertions for path visualization and signature verification.
- Added ConnectionState property for tracking connection establishment time in Router.Common.
- Implemented validation for HelloPayload in ConnectionManager to ensure required fields are present.
- Introduced RabbitMqContainerFixture method for restarting RabbitMQ container during tests.
- Added integration tests for RabbitMq to verify connection recovery after broker restarts.
- Created new BinaryCallGraphExtractorTests, GoCallGraphExtractorTests, and PythonCallGraphExtractorTests for comprehensive coverage of binary, Go, and Python call graph extraction functionalities.
- Developed ConnectionManagerTests to validate connection handling, including rejection of invalid hello messages and proper cleanup on client disconnects.
2025-12-19 18:49:36 +02:00

227 lines
7.0 KiB
C#

using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using StellaOps.Router.Common.Enums;
using StellaOps.Router.Common.Models;
using StellaOps.Router.Gateway.Services;
using StellaOps.Router.Gateway.State;
using StellaOps.Router.Transport.InMemory;
using Xunit;
namespace StellaOps.Router.Gateway.Tests;
public sealed class ConnectionManagerTests
{
[Fact]
public async Task StartAsync_WhenHelloInvalid_RejectsAndClosesChannel()
{
var (manager, server, registry, routingState) = Create();
var client = CreateClient(registry, server);
try
{
await manager.StartAsync(CancellationToken.None);
var invalid = new InstanceDescriptor
{
InstanceId = "inv-1",
ServiceName = "",
Version = "1.0.0",
Region = "eu1"
};
await client.ConnectAsync(
invalid,
endpoints:
[
new EndpointDescriptor
{
ServiceName = "inventory",
Version = "1.0.0",
Method = "GET",
Path = "/items"
}
],
CancellationToken.None);
await EventuallyAsync(
() => registry.Count == 0,
timeout: TimeSpan.FromSeconds(5));
routingState.GetAllConnections().Should().BeEmpty();
}
finally
{
client.Dispose();
await manager.StopAsync(CancellationToken.None);
server.Dispose();
registry.Dispose();
}
}
[Fact]
public async Task WhenClientDisconnects_RemovesFromRoutingState()
{
var (manager, server, registry, routingState) = Create();
var client = CreateClient(registry, server);
try
{
await manager.StartAsync(CancellationToken.None);
await client.ConnectAsync(
CreateInstance("inventory", "1.0.0", "inv-1"),
endpoints:
[
new EndpointDescriptor
{
ServiceName = "inventory",
Version = "1.0.0",
Method = "GET",
Path = "/items"
}
],
CancellationToken.None);
await EventuallyAsync(
() => routingState.GetAllConnections().Count == 1,
timeout: TimeSpan.FromSeconds(5));
client.Dispose();
await EventuallyAsync(
() => routingState.GetAllConnections().Count == 0,
timeout: TimeSpan.FromSeconds(5));
}
finally
{
client.Dispose();
await manager.StopAsync(CancellationToken.None);
server.Dispose();
registry.Dispose();
}
}
[Fact]
public async Task WhenMultipleClientsConnect_TracksAndCleansIndependently()
{
var (manager, server, registry, routingState) = Create();
var client1 = CreateClient(registry, server);
var client2 = CreateClient(registry, server);
try
{
await manager.StartAsync(CancellationToken.None);
var endpoints =
new[]
{
new EndpointDescriptor
{
ServiceName = "inventory",
Version = "1.0.0",
Method = "GET",
Path = "/items"
}
};
await client1.ConnectAsync(
CreateInstance("inventory", "1.0.0", "inv-1"),
endpoints,
CancellationToken.None);
await client2.ConnectAsync(
CreateInstance("inventory", "1.0.0", "inv-2"),
endpoints,
CancellationToken.None);
await EventuallyAsync(
() => routingState.GetConnectionsFor("inventory", "1.0.0", "GET", "/items").Count == 2,
timeout: TimeSpan.FromSeconds(5));
var before = routingState.GetConnectionsFor("inventory", "1.0.0", "GET", "/items")
.Select(c => c.Instance.InstanceId)
.ToHashSet(StringComparer.Ordinal);
before.Should().BeEquivalentTo(new[] { "inv-1", "inv-2" });
client1.Dispose();
await EventuallyAsync(
() => routingState.GetConnectionsFor("inventory", "1.0.0", "GET", "/items").Count == 1,
timeout: TimeSpan.FromSeconds(5));
var after = routingState.GetConnectionsFor("inventory", "1.0.0", "GET", "/items")
.Single()
.Instance.InstanceId;
after.Should().Be("inv-2");
}
finally
{
client1.Dispose();
client2.Dispose();
await manager.StopAsync(CancellationToken.None);
server.Dispose();
registry.Dispose();
}
}
private static (ConnectionManager Manager, InMemoryTransportServer Server, InMemoryConnectionRegistry Registry, InMemoryRoutingState RoutingState) Create()
{
var registry = new InMemoryConnectionRegistry();
var server = new InMemoryTransportServer(
registry,
Options.Create(new InMemoryTransportOptions()),
NullLogger<InMemoryTransportServer>.Instance);
var routingState = new InMemoryRoutingState();
var manager = new ConnectionManager(
server,
registry,
routingState,
NullLogger<ConnectionManager>.Instance);
return (manager, server, registry, routingState);
}
private static InMemoryTransportClient CreateClient(InMemoryConnectionRegistry registry, InMemoryTransportServer server)
{
return new InMemoryTransportClient(
registry,
Options.Create(new InMemoryTransportOptions()),
NullLogger<InMemoryTransportClient>.Instance,
server);
}
private static InstanceDescriptor CreateInstance(string serviceName, string version, string instanceId)
{
return new InstanceDescriptor
{
InstanceId = instanceId,
ServiceName = serviceName,
Version = version,
Region = "eu1"
};
}
private static async Task EventuallyAsync(Func<bool> predicate, TimeSpan timeout, TimeSpan? pollInterval = null)
{
pollInterval ??= TimeSpan.FromMilliseconds(25);
var deadline = DateTime.UtcNow + timeout;
while (DateTime.UtcNow < deadline)
{
if (predicate())
{
return;
}
await Task.Delay(pollInterval.Value);
}
predicate().Should().BeTrue("condition should become true within {0}", timeout);
}
}