Add unit tests for RabbitMq and Udp transport servers and clients
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Implemented comprehensive unit tests for RabbitMqTransportServer, covering constructor, disposal, connection management, event handlers, and exception handling.
- Added configuration tests for RabbitMqTransportServer to validate SSL, durable queues, auto-recovery, and custom virtual host options.
- Created unit tests for UdpFrameProtocol, including frame parsing and serialization, header size validation, and round-trip data preservation.
- Developed tests for UdpTransportClient, focusing on connection handling, event subscriptions, and exception scenarios.
- Established tests for UdpTransportServer, ensuring proper start/stop behavior, connection state management, and event handling.
- Included tests for UdpTransportOptions to verify default values and modification capabilities.
- Enhanced service registration tests for Udp transport services in the dependency injection container.
This commit is contained in:
master
2025-12-05 19:01:12 +02:00
parent 53508ceccb
commit cc69d332e3
245 changed files with 22440 additions and 27719 deletions

View File

@@ -0,0 +1,199 @@
using StellaOps.Router.Common.Enums;
using StellaOps.Router.Integration.Tests.Fixtures;
namespace StellaOps.Router.Integration.Tests;
/// <summary>
/// Integration tests for router connection manager.
/// </summary>
[Collection("Microservice Integration")]
public sealed class ConnectionManagerIntegrationTests
{
private readonly MicroserviceIntegrationFixture _fixture;
public ConnectionManagerIntegrationTests(MicroserviceIntegrationFixture fixture)
{
_fixture = fixture;
}
#region Initialization Tests
[Fact]
public void ConnectionManager_IsInitialized()
{
// Arrange & Act
var connectionManager = _fixture.ConnectionManager;
// Assert
connectionManager.Should().NotBeNull();
}
[Fact]
public void ConnectionManager_HasConnections()
{
// Arrange
var connectionManager = _fixture.ConnectionManager;
// Act
var connections = connectionManager.Connections;
// Assert
connections.Should().NotBeEmpty();
}
[Fact]
public void ConnectionManager_ConnectionHasCorrectServiceInfo()
{
// Arrange
var connectionManager = _fixture.ConnectionManager;
// Act
var connection = connectionManager.Connections.FirstOrDefault();
// Assert
connection.Should().NotBeNull();
connection!.Instance.ServiceName.Should().Be("test-service");
connection.Instance.Version.Should().Be("1.0.0");
connection.Instance.Region.Should().Be("test-region");
connection.Instance.InstanceId.Should().Be("test-instance-001");
}
[Fact]
public void ConnectionManager_ConnectionHasEndpoints()
{
// Arrange
var connectionManager = _fixture.ConnectionManager;
// Act
var connection = connectionManager.Connections.FirstOrDefault();
// Assert
connection!.Endpoints.Should().HaveCount(8);
}
#endregion
#region Status Tests
[Fact]
public void ConnectionManager_DefaultStatus_IsHealthy()
{
// Arrange
var connectionManager = _fixture.ConcreteConnectionManager;
// Act
var status = connectionManager.CurrentStatus;
// Assert
status.Should().Be(InstanceHealthStatus.Healthy);
}
[Fact]
public void ConnectionManager_CanChangeStatus()
{
// Arrange
var connectionManager = _fixture.ConcreteConnectionManager;
var originalStatus = connectionManager.CurrentStatus;
// Act
connectionManager.CurrentStatus = InstanceHealthStatus.Degraded;
var newStatus = connectionManager.CurrentStatus;
// Cleanup
connectionManager.CurrentStatus = originalStatus;
// Assert
newStatus.Should().Be(InstanceHealthStatus.Degraded);
}
[Theory]
[InlineData(InstanceHealthStatus.Healthy)]
[InlineData(InstanceHealthStatus.Degraded)]
[InlineData(InstanceHealthStatus.Draining)]
[InlineData(InstanceHealthStatus.Unhealthy)]
public void ConnectionManager_AcceptsAllStatusValues(InstanceHealthStatus status)
{
// Arrange
var connectionManager = _fixture.ConcreteConnectionManager;
var originalStatus = connectionManager.CurrentStatus;
// Act
connectionManager.CurrentStatus = status;
var actualStatus = connectionManager.CurrentStatus;
// Cleanup
connectionManager.CurrentStatus = originalStatus;
// Assert
actualStatus.Should().Be(status);
}
#endregion
#region Metrics Tests
[Fact]
public void ConnectionManager_InFlightRequestCount_InitiallyZero()
{
// Arrange
var connectionManager = _fixture.ConcreteConnectionManager;
// Act
var count = connectionManager.InFlightRequestCount;
// Assert
count.Should().BeGreaterOrEqualTo(0);
}
[Fact]
public void ConnectionManager_ErrorRate_InitiallyZero()
{
// Arrange
var connectionManager = _fixture.ConcreteConnectionManager;
// Act
var errorRate = connectionManager.ErrorRate;
// Assert
errorRate.Should().BeGreaterOrEqualTo(0);
errorRate.Should().BeLessThanOrEqualTo(1.0);
}
[Fact]
public void ConnectionManager_CanSetInFlightRequestCount()
{
// Arrange
var connectionManager = _fixture.ConcreteConnectionManager;
var originalCount = connectionManager.InFlightRequestCount;
// Act
connectionManager.InFlightRequestCount = 42;
var newCount = connectionManager.InFlightRequestCount;
// Cleanup
connectionManager.InFlightRequestCount = originalCount;
// Assert
newCount.Should().Be(42);
}
[Fact]
public void ConnectionManager_CanSetErrorRate()
{
// Arrange
var connectionManager = _fixture.ConcreteConnectionManager;
var originalRate = connectionManager.ErrorRate;
// Act
connectionManager.ErrorRate = 0.15;
var newRate = connectionManager.ErrorRate;
// Cleanup
connectionManager.ErrorRate = originalRate;
// Assert
newRate.Should().Be(0.15);
}
#endregion
}

View File

@@ -0,0 +1,165 @@
using StellaOps.Microservice;
using StellaOps.Router.Integration.Tests.Fixtures;
namespace StellaOps.Router.Integration.Tests;
/// <summary>
/// Integration tests for endpoint registry and discovery.
/// </summary>
[Collection("Microservice Integration")]
public sealed class EndpointRegistryIntegrationTests
{
private readonly MicroserviceIntegrationFixture _fixture;
public EndpointRegistryIntegrationTests(MicroserviceIntegrationFixture fixture)
{
_fixture = fixture;
}
#region Endpoint Discovery Tests
[Fact]
public void Registry_ContainsAllTestEndpoints()
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
var endpoints = registry.GetAllEndpoints();
// Assert
endpoints.Should().HaveCount(8);
}
[Theory]
[InlineData("POST", "/echo")]
[InlineData("GET", "/users/123")]
[InlineData("POST", "/users")]
[InlineData("POST", "/slow")]
[InlineData("POST", "/fail")]
[InlineData("POST", "/stream")]
[InlineData("DELETE", "/admin/reset")]
[InlineData("GET", "/quick")]
public void Registry_FindsEndpoint_ByMethodAndPath(string method, string path)
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
var found = registry.TryMatch(method, path, out var match);
// Assert
found.Should().BeTrue();
match.Should().NotBeNull();
match!.Endpoint.Method.Should().Be(method);
}
[Fact]
public void Registry_ReturnsNull_ForUnknownEndpoint()
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
var found = registry.TryMatch("GET", "/unknown", out var match);
// Assert
found.Should().BeFalse();
match.Should().BeNull();
}
[Fact]
public void Registry_MatchesPathParameters()
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
var found = registry.TryMatch("GET", "/users/12345", out var match);
// Assert
found.Should().BeTrue();
match!.Endpoint.Path.Should().Be("/users/{userId}");
}
[Fact]
public void Registry_ExtractsPathParameters()
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
registry.TryMatch("GET", "/users/abc123", out var match);
// Assert
match.Should().NotBeNull();
match!.PathParameters.Should().ContainKey("userId");
match.PathParameters["userId"].Should().Be("abc123");
}
#endregion
#region Endpoint Metadata Tests
[Fact]
public void Endpoint_HasCorrectTimeout()
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
registry.TryMatch("GET", "/quick", out var quickMatch);
registry.TryMatch("POST", "/slow", out var slowMatch);
// Assert
quickMatch!.Endpoint.DefaultTimeout.Should().Be(TimeSpan.FromSeconds(5));
slowMatch!.Endpoint.DefaultTimeout.Should().Be(TimeSpan.FromSeconds(60));
}
[Fact]
public void Endpoint_HasCorrectStreamingFlag()
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
registry.TryMatch("POST", "/stream", out var streamMatch);
registry.TryMatch("POST", "/echo", out var echoMatch);
// Assert
streamMatch!.Endpoint.SupportsStreaming.Should().BeTrue();
echoMatch!.Endpoint.SupportsStreaming.Should().BeFalse();
}
[Fact]
public void Endpoint_HasCorrectClaims()
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
registry.TryMatch("DELETE", "/admin/reset", out var adminMatch);
registry.TryMatch("POST", "/echo", out var echoMatch);
// Assert
adminMatch!.Endpoint.RequiringClaims.Should().HaveCount(2);
adminMatch.Endpoint.RequiringClaims.Should().Contain(c => c.Type == "admin");
adminMatch.Endpoint.RequiringClaims.Should().Contain(c => c.Type == "write");
echoMatch!.Endpoint.RequiringClaims.Should().BeEmpty();
}
[Fact]
public void Endpoint_HasCorrectHandlerType()
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
registry.TryMatch("POST", "/echo", out var match);
// Assert
match!.Endpoint.HandlerType.Should().Be(typeof(EchoEndpoint));
}
#endregion
}

View File

@@ -0,0 +1,100 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using StellaOps.Microservice;
using StellaOps.Router.Common.Enums;
using StellaOps.Router.Transport.InMemory;
using Xunit;
namespace StellaOps.Router.Integration.Tests.Fixtures;
/// <summary>
/// Test fixture that sets up a microservice with InMemory transport for integration testing.
/// </summary>
public sealed class MicroserviceIntegrationFixture : IAsyncLifetime
{
private IHost? _host;
/// <summary>
/// Gets the service provider for the test microservice.
/// </summary>
public IServiceProvider Services => _host?.Services ?? throw new InvalidOperationException("Fixture not initialized");
/// <summary>
/// Gets the endpoint registry.
/// </summary>
public IEndpointRegistry EndpointRegistry => Services.GetRequiredService<IEndpointRegistry>();
/// <summary>
/// Gets the router connection manager interface.
/// </summary>
public IRouterConnectionManager ConnectionManager => Services.GetRequiredService<IRouterConnectionManager>();
/// <summary>
/// Gets the concrete router connection manager for accessing additional properties.
/// </summary>
public RouterConnectionManager ConcreteConnectionManager => (RouterConnectionManager)ConnectionManager;
/// <summary>
/// Gets the InMemory transport client for direct testing.
/// </summary>
public InMemoryTransportClient TransportClient => Services.GetRequiredService<InMemoryTransportClient>();
public async Task InitializeAsync()
{
var builder = Host.CreateApplicationBuilder();
// Add InMemory transport
builder.Services.AddInMemoryTransport();
// Add microservice with test discovery provider
builder.Services.AddStellaMicroservice<TestEndpointDiscoveryProvider>(options =>
{
options.ServiceName = "test-service";
options.Version = "1.0.0";
options.Region = "test-region";
options.InstanceId = "test-instance-001";
options.HeartbeatInterval = TimeSpan.FromMilliseconds(100);
options.ReconnectBackoffInitial = TimeSpan.FromMilliseconds(10);
options.ReconnectBackoffMax = TimeSpan.FromMilliseconds(100);
options.Routers.Add(new RouterEndpointConfig
{
Host = "localhost",
Port = 5100,
TransportType = TransportType.InMemory
});
});
// Register test endpoint handlers
builder.Services.AddScoped<EchoEndpoint>();
builder.Services.AddScoped<GetUserEndpoint>();
builder.Services.AddScoped<CreateUserEndpoint>();
builder.Services.AddScoped<SlowEndpoint>();
builder.Services.AddScoped<FailEndpoint>();
builder.Services.AddScoped<StreamEndpoint>();
builder.Services.AddScoped<AdminResetEndpoint>();
builder.Services.AddScoped<QuickEndpoint>();
_host = builder.Build();
await _host.StartAsync();
// Wait for microservice to initialize
await Task.Delay(100);
}
public async Task DisposeAsync()
{
if (_host is not null)
{
await _host.StopAsync();
_host.Dispose();
}
}
}
/// <summary>
/// Collection definition for sharing fixture across test classes.
/// </summary>
[CollectionDefinition("Microservice Integration")]
public class MicroserviceIntegrationCollection : ICollectionFixture<MicroserviceIntegrationFixture>
{
}

View File

@@ -0,0 +1,240 @@
using System.Text;
using StellaOps.Microservice;
namespace StellaOps.Router.Integration.Tests.Fixtures;
#region Request/Response Types
public record EchoRequest(string Message);
public record EchoResponse(string Echo, DateTime Timestamp);
public record GetUserRequest(string UserId);
public record GetUserResponse(string UserId, string Name, string Email);
public record CreateUserRequest(string Name, string Email);
public record CreateUserResponse(string UserId, bool Success);
public record SlowRequest(int DelayMs);
public record SlowResponse(int ActualDelayMs);
public record FailRequest(string ErrorMessage);
public record FailResponse();
#endregion
#region Test Endpoints
/// <summary>
/// Simple echo endpoint for basic request/response testing.
/// </summary>
[StellaEndpoint("POST", "/echo")]
public sealed class EchoEndpoint : IStellaEndpoint<EchoRequest, EchoResponse>
{
public Task<EchoResponse> HandleAsync(EchoRequest request, CancellationToken cancellationToken)
{
return Task.FromResult(new EchoResponse($"Echo: {request.Message}", DateTime.UtcNow));
}
}
/// <summary>
/// Endpoint with path parameters.
/// </summary>
[StellaEndpoint("GET", "/users/{userId}")]
public sealed class GetUserEndpoint : IStellaEndpoint<GetUserRequest, GetUserResponse>
{
public Task<GetUserResponse> HandleAsync(GetUserRequest request, CancellationToken cancellationToken)
{
return Task.FromResult(new GetUserResponse(
request.UserId,
$"User-{request.UserId}",
$"user-{request.UserId}@example.com"));
}
}
/// <summary>
/// POST endpoint for creating resources.
/// </summary>
[StellaEndpoint("POST", "/users")]
public sealed class CreateUserEndpoint : IStellaEndpoint<CreateUserRequest, CreateUserResponse>
{
public Task<CreateUserResponse> HandleAsync(CreateUserRequest request, CancellationToken cancellationToken)
{
var userId = Guid.NewGuid().ToString("N")[..8];
return Task.FromResult(new CreateUserResponse(userId, true));
}
}
/// <summary>
/// Endpoint that deliberately delays to test timeouts and cancellation.
/// </summary>
[StellaEndpoint("POST", "/slow", TimeoutSeconds = 60)]
public sealed class SlowEndpoint : IStellaEndpoint<SlowRequest, SlowResponse>
{
public async Task<SlowResponse> HandleAsync(SlowRequest request, CancellationToken cancellationToken)
{
var sw = System.Diagnostics.Stopwatch.StartNew();
await Task.Delay(request.DelayMs, cancellationToken);
sw.Stop();
return new SlowResponse((int)sw.ElapsedMilliseconds);
}
}
/// <summary>
/// Endpoint that throws exceptions for error handling tests.
/// </summary>
[StellaEndpoint("POST", "/fail")]
public sealed class FailEndpoint : IStellaEndpoint<FailRequest, FailResponse>
{
public Task<FailResponse> HandleAsync(FailRequest request, CancellationToken cancellationToken)
{
throw new InvalidOperationException(request.ErrorMessage);
}
}
/// <summary>
/// Raw endpoint for streaming tests.
/// </summary>
[StellaEndpoint("POST", "/stream", SupportsStreaming = true)]
public sealed class StreamEndpoint : IRawStellaEndpoint
{
public async Task<RawResponse> HandleAsync(RawRequestContext context, CancellationToken cancellationToken)
{
// Read all input
using var reader = new StreamReader(context.Body);
var input = await reader.ReadToEndAsync(cancellationToken);
// Echo it back with prefix
var output = $"Streamed: {input}";
var outputBytes = Encoding.UTF8.GetBytes(output);
var response = new RawResponse
{
StatusCode = 200,
Headers = new HeaderCollection([new KeyValuePair<string, string>("Content-Type", "text/plain")]),
Body = new MemoryStream(outputBytes)
};
return response;
}
}
/// <summary>
/// Endpoint requiring specific claims.
/// </summary>
[StellaEndpoint("DELETE", "/admin/reset", RequiredClaims = ["admin", "write"])]
public sealed class AdminResetEndpoint : IStellaEndpoint<EchoRequest, EchoResponse>
{
public Task<EchoResponse> HandleAsync(EchoRequest request, CancellationToken cancellationToken)
{
return Task.FromResult(new EchoResponse("Admin action completed", DateTime.UtcNow));
}
}
/// <summary>
/// Endpoint with custom timeout.
/// </summary>
[StellaEndpoint("GET", "/quick", TimeoutSeconds = 5)]
public sealed class QuickEndpoint : IStellaEndpoint<EchoRequest, EchoResponse>
{
public Task<EchoResponse> HandleAsync(EchoRequest request, CancellationToken cancellationToken)
{
return Task.FromResult(new EchoResponse("Quick response", DateTime.UtcNow));
}
}
#endregion
#region Test Endpoint Discovery Provider
/// <summary>
/// Test endpoint discovery provider that returns our test endpoints.
/// </summary>
public sealed class TestEndpointDiscoveryProvider : IEndpointDiscoveryProvider
{
public IReadOnlyList<Router.Common.Models.EndpointDescriptor> DiscoverEndpoints()
{
return
[
new Router.Common.Models.EndpointDescriptor
{
ServiceName = "test-service",
Version = "1.0.0",
Method = "POST",
Path = "/echo",
DefaultTimeout = TimeSpan.FromSeconds(30),
HandlerType = typeof(EchoEndpoint)
},
new Router.Common.Models.EndpointDescriptor
{
ServiceName = "test-service",
Version = "1.0.0",
Method = "GET",
Path = "/users/{userId}",
DefaultTimeout = TimeSpan.FromSeconds(30),
HandlerType = typeof(GetUserEndpoint)
},
new Router.Common.Models.EndpointDescriptor
{
ServiceName = "test-service",
Version = "1.0.0",
Method = "POST",
Path = "/users",
DefaultTimeout = TimeSpan.FromSeconds(30),
HandlerType = typeof(CreateUserEndpoint)
},
new Router.Common.Models.EndpointDescriptor
{
ServiceName = "test-service",
Version = "1.0.0",
Method = "POST",
Path = "/slow",
DefaultTimeout = TimeSpan.FromSeconds(60),
HandlerType = typeof(SlowEndpoint)
},
new Router.Common.Models.EndpointDescriptor
{
ServiceName = "test-service",
Version = "1.0.0",
Method = "POST",
Path = "/fail",
DefaultTimeout = TimeSpan.FromSeconds(30),
HandlerType = typeof(FailEndpoint)
},
new Router.Common.Models.EndpointDescriptor
{
ServiceName = "test-service",
Version = "1.0.0",
Method = "POST",
Path = "/stream",
DefaultTimeout = TimeSpan.FromSeconds(30),
SupportsStreaming = true,
HandlerType = typeof(StreamEndpoint)
},
new Router.Common.Models.EndpointDescriptor
{
ServiceName = "test-service",
Version = "1.0.0",
Method = "DELETE",
Path = "/admin/reset",
DefaultTimeout = TimeSpan.FromSeconds(30),
RequiringClaims =
[
new Router.Common.Models.ClaimRequirement { Type = "admin" },
new Router.Common.Models.ClaimRequirement { Type = "write" }
],
HandlerType = typeof(AdminResetEndpoint)
},
new Router.Common.Models.EndpointDescriptor
{
ServiceName = "test-service",
Version = "1.0.0",
Method = "GET",
Path = "/quick",
DefaultTimeout = TimeSpan.FromSeconds(5),
HandlerType = typeof(QuickEndpoint)
}
];
}
}
#endregion

View File

@@ -0,0 +1,122 @@
using StellaOps.Microservice;
using StellaOps.Router.Integration.Tests.Fixtures;
namespace StellaOps.Router.Integration.Tests;
/// <summary>
/// Integration tests for path matching and routing.
/// </summary>
[Collection("Microservice Integration")]
public sealed class PathMatchingIntegrationTests
{
private readonly MicroserviceIntegrationFixture _fixture;
public PathMatchingIntegrationTests(MicroserviceIntegrationFixture fixture)
{
_fixture = fixture;
}
#region Exact Path Matching Tests
[Theory]
[InlineData("POST", "/echo")]
[InlineData("POST", "/users")]
[InlineData("POST", "/slow")]
[InlineData("POST", "/fail")]
[InlineData("POST", "/stream")]
[InlineData("DELETE", "/admin/reset")]
[InlineData("GET", "/quick")]
public void PathMatching_ExactPaths_MatchCorrectly(string method, string path)
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
var found = registry.TryMatch(method, path, out var match);
// Assert
found.Should().BeTrue();
match.Should().NotBeNull();
}
#endregion
#region Parameterized Path Tests
[Theory]
[InlineData("/users/123", "/users/{userId}")]
[InlineData("/users/abc-def", "/users/{userId}")]
[InlineData("/users/user_001", "/users/{userId}")]
public void PathMatching_ParameterizedPaths_MatchCorrectly(string requestPath, string expectedPattern)
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
var found = registry.TryMatch("GET", requestPath, out var match);
// Assert
found.Should().BeTrue();
match!.Endpoint.Path.Should().Be(expectedPattern);
}
[Fact]
public void PathMatching_PostUsersPath_MatchesCreateEndpoint()
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
var found = registry.TryMatch("POST", "/users", out var match);
// Assert
found.Should().BeTrue();
match!.Endpoint.HandlerType.Should().Be(typeof(CreateUserEndpoint));
}
#endregion
#region Non-Matching Path Tests
[Theory]
[InlineData("GET", "/nonexistent")]
[InlineData("POST", "/unknown/path")]
[InlineData("PUT", "/echo")] // Wrong method
[InlineData("GET", "/admin/reset")] // Wrong method
public void PathMatching_NonMatchingPaths_ReturnFalse(string method, string path)
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
var found = registry.TryMatch(method, path, out var match);
// Assert
found.Should().BeFalse();
match.Should().BeNull();
}
#endregion
#region Method Matching Tests
[Fact]
public void PathMatching_SamePathDifferentMethods_MatchCorrectEndpoint()
{
// Arrange
var registry = _fixture.EndpointRegistry;
// Act
registry.TryMatch("POST", "/users", out var postMatch);
registry.TryMatch("GET", "/users/123", out var getMatch);
// Assert
postMatch.Should().NotBeNull();
postMatch!.Endpoint.HandlerType.Should().Be(typeof(CreateUserEndpoint));
getMatch.Should().NotBeNull();
getMatch!.Endpoint.HandlerType.Should().Be(typeof(GetUserEndpoint));
}
#endregion
}

View File

@@ -0,0 +1,165 @@
using Microsoft.Extensions.DependencyInjection;
using StellaOps.Microservice;
using StellaOps.Router.Common.Abstractions;
using StellaOps.Router.Integration.Tests.Fixtures;
using StellaOps.Router.Transport.InMemory;
namespace StellaOps.Router.Integration.Tests;
/// <summary>
/// Integration tests for service registration and DI container.
/// </summary>
[Collection("Microservice Integration")]
public sealed class ServiceRegistrationIntegrationTests
{
private readonly MicroserviceIntegrationFixture _fixture;
public ServiceRegistrationIntegrationTests(MicroserviceIntegrationFixture fixture)
{
_fixture = fixture;
}
#region Core Services Tests
[Fact]
public void Services_MicroserviceOptionsAreRegistered()
{
// Act
var options = _fixture.Services.GetService<StellaMicroserviceOptions>();
// Assert
options.Should().NotBeNull();
options!.ServiceName.Should().Be("test-service");
options.Version.Should().Be("1.0.0");
}
[Fact]
public void Services_EndpointRegistryIsRegistered()
{
// Act
var registry = _fixture.Services.GetService<IEndpointRegistry>();
// Assert
registry.Should().NotBeNull();
}
[Fact]
public void Services_ConnectionManagerIsRegistered()
{
// Act
var connectionManager = _fixture.Services.GetService<IRouterConnectionManager>();
// Assert
connectionManager.Should().NotBeNull();
}
[Fact]
public void Services_RequestDispatcherIsRegistered()
{
// Act
var dispatcher = _fixture.Services.GetService<RequestDispatcher>();
// Assert
dispatcher.Should().NotBeNull();
}
[Fact]
public void Services_EndpointDiscoveryServiceIsRegistered()
{
// Act
var discoveryService = _fixture.Services.GetService<IEndpointDiscoveryService>();
// Assert
discoveryService.Should().NotBeNull();
}
#endregion
#region Transport Services Tests
[Fact]
public void Services_TransportClientIsRegistered()
{
// Act
var client = _fixture.Services.GetService<ITransportClient>();
// Assert
client.Should().NotBeNull();
client.Should().BeOfType<InMemoryTransportClient>();
}
[Fact]
public void Services_TransportServerIsRegistered()
{
// Act
var server = _fixture.Services.GetService<ITransportServer>();
// Assert
server.Should().NotBeNull();
server.Should().BeOfType<InMemoryTransportServer>();
}
[Fact]
public void Services_InMemoryConnectionRegistryIsRegistered()
{
// Act
var registry = _fixture.Services.GetService<InMemoryConnectionRegistry>();
// Assert
registry.Should().NotBeNull();
}
#endregion
#region Endpoint Handler Tests
[Fact]
public void Services_EndpointHandlersAreRegistered()
{
// Act
using var scope = _fixture.Services.CreateScope();
var echoEndpoint = scope.ServiceProvider.GetService<EchoEndpoint>();
var getUserEndpoint = scope.ServiceProvider.GetService<GetUserEndpoint>();
var createUserEndpoint = scope.ServiceProvider.GetService<CreateUserEndpoint>();
// Assert
echoEndpoint.Should().NotBeNull();
getUserEndpoint.Should().NotBeNull();
createUserEndpoint.Should().NotBeNull();
}
[Fact]
public void Services_EndpointHandlersAreScopedInstances()
{
// Act
using var scope1 = _fixture.Services.CreateScope();
using var scope2 = _fixture.Services.CreateScope();
var echo1 = scope1.ServiceProvider.GetService<EchoEndpoint>();
var echo2 = scope2.ServiceProvider.GetService<EchoEndpoint>();
// Assert - Scoped services should be different instances
echo1.Should().NotBeSameAs(echo2);
}
#endregion
#region Singleton Services Tests
[Fact]
public void Services_SingletonServicesAreSameInstance()
{
// Act
var registry1 = _fixture.Services.GetService<IEndpointRegistry>();
var registry2 = _fixture.Services.GetService<IEndpointRegistry>();
var connectionManager1 = _fixture.Services.GetService<IRouterConnectionManager>();
var connectionManager2 = _fixture.Services.GetService<IRouterConnectionManager>();
// Assert
registry1.Should().BeSameAs(registry2);
connectionManager1.Should().BeSameAs(connectionManager2);
}
#endregion
}

View File

@@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>$(NoWarn);CA2255</NoWarn>
<IsPackable>false</IsPackable>
<RootNamespace>StellaOps.Router.Integration.Tests</RootNamespace>
<UseConcelierTestInfra>false</UseConcelierTestInfra>
</PropertyGroup>
<ItemGroup>
<Using Include="Xunit" />
<Using Include="FluentAssertions" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0-rc.2.25502.107" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\StellaOps.Router.Common\StellaOps.Router.Common.csproj" />
<ProjectReference Include="..\..\StellaOps.Router.Config\StellaOps.Router.Config.csproj" />
<ProjectReference Include="..\..\StellaOps.Router.Transport.InMemory\StellaOps.Router.Transport.InMemory.csproj" />
<ProjectReference Include="..\..\StellaOps.Microservice\StellaOps.Microservice.csproj" />
<ProjectReference Include="..\StellaOps.Router.Testing\StellaOps.Router.Testing.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,63 @@
using Microsoft.Extensions.DependencyInjection;
using StellaOps.Router.Common.Abstractions;
using StellaOps.Router.Integration.Tests.Fixtures;
using StellaOps.Router.Transport.InMemory;
namespace StellaOps.Router.Integration.Tests;
/// <summary>
/// Integration tests for transport layer.
/// </summary>
[Collection("Microservice Integration")]
public sealed class TransportIntegrationTests
{
private readonly MicroserviceIntegrationFixture _fixture;
public TransportIntegrationTests(MicroserviceIntegrationFixture fixture)
{
_fixture = fixture;
}
#region InMemory Transport Tests
[Fact]
public void Transport_ClientIsRegistered()
{
// Arrange & Act
var client = _fixture.Services.GetService<ITransportClient>();
// Assert
client.Should().NotBeNull();
client.Should().BeOfType<InMemoryTransportClient>();
}
[Fact]
public void Transport_ConnectionRegistryIsShared()
{
// Arrange
var registry = _fixture.Services.GetService<InMemoryConnectionRegistry>();
// Act & Assert
registry.Should().NotBeNull();
}
#endregion
#region Connection Lifecycle Tests
[Fact]
public void Transport_ConnectionIsEstablished()
{
// Arrange
var connectionManager = _fixture.ConnectionManager;
// Act
var connections = connectionManager.Connections;
// Assert
connections.Should().NotBeEmpty();
connections.First().Instance.Should().NotBeNull();
}
#endregion
}