Add unit tests for Router configuration and transport layers
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled

- Implemented tests for RouterConfig, RoutingOptions, StaticInstanceConfig, and RouterConfigOptions to ensure default values are set correctly.
- Added tests for RouterConfigProvider to validate configurations and ensure defaults are returned when no file is specified.
- Created tests for ConfigValidationResult to check success and error scenarios.
- Developed tests for ServiceCollectionExtensions to verify service registration for RouterConfig.
- Introduced UdpTransportTests to validate serialization, connection, request-response, and error handling in UDP transport.
- Added scripts for signing authority gaps and hashing DevPortal SDK snippets.
This commit is contained in:
StellaOps Bot
2025-12-05 08:01:47 +02:00
parent 635c70e828
commit 6a299d231f
294 changed files with 28434 additions and 1329 deletions

View File

@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<UseConcelierTestInfra>false</UseConcelierTestInfra>
</PropertyGroup>
<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" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\StellaOps.Router.Transport.Tcp\StellaOps.Router.Transport.Tcp.csproj" />
<ProjectReference Include="..\..\StellaOps.Router.Common\StellaOps.Router.Common.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,199 @@
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using StellaOps.Router.Common.Enums;
using StellaOps.Router.Common.Models;
using StellaOps.Router.Transport.Tcp;
using Xunit;
namespace StellaOps.Router.Transport.Tcp.Tests;
public class TcpTransportOptionsTests
{
[Fact]
public void DefaultOptions_HaveCorrectValues()
{
var options = new TcpTransportOptions();
Assert.Equal(5100, options.Port);
Assert.Equal(64 * 1024, options.ReceiveBufferSize);
Assert.Equal(64 * 1024, options.SendBufferSize);
Assert.Equal(TimeSpan.FromSeconds(30), options.KeepAliveInterval);
Assert.Equal(TimeSpan.FromSeconds(10), options.ConnectTimeout);
Assert.Equal(10, options.MaxReconnectAttempts);
Assert.Equal(TimeSpan.FromMinutes(1), options.MaxReconnectBackoff);
Assert.Equal(16 * 1024 * 1024, options.MaxFrameSize);
}
}
public class FrameProtocolTests
{
[Fact]
public async Task WriteAndReadFrame_RoundTrip()
{
// Arrange
using var stream = new MemoryStream();
var originalFrame = new Frame
{
Type = FrameType.Request,
CorrelationId = Guid.NewGuid().ToString("N"),
Payload = new byte[] { 1, 2, 3, 4, 5 }
};
// Act - Write
await FrameProtocol.WriteFrameAsync(stream, originalFrame, CancellationToken.None);
// Act - Read
stream.Position = 0;
var readFrame = await FrameProtocol.ReadFrameAsync(stream, 1024 * 1024, CancellationToken.None);
// Assert
Assert.NotNull(readFrame);
Assert.Equal(originalFrame.Type, readFrame.Type);
Assert.Equal(originalFrame.CorrelationId, readFrame.CorrelationId);
Assert.Equal(originalFrame.Payload.ToArray(), readFrame.Payload.ToArray());
}
[Fact]
public async Task WriteAndReadFrame_EmptyPayload()
{
using var stream = new MemoryStream();
var originalFrame = new Frame
{
Type = FrameType.Cancel,
CorrelationId = Guid.NewGuid().ToString("N"),
Payload = ReadOnlyMemory<byte>.Empty
};
await FrameProtocol.WriteFrameAsync(stream, originalFrame, CancellationToken.None);
stream.Position = 0;
var readFrame = await FrameProtocol.ReadFrameAsync(stream, 1024 * 1024, CancellationToken.None);
Assert.NotNull(readFrame);
Assert.Equal(FrameType.Cancel, readFrame.Type);
Assert.Empty(readFrame.Payload.ToArray());
}
[Fact]
public async Task ReadFrame_ReturnsNullOnEmptyStream()
{
using var stream = new MemoryStream();
var result = await FrameProtocol.ReadFrameAsync(stream, 1024 * 1024, CancellationToken.None);
Assert.Null(result);
}
[Fact]
public async Task ReadFrame_ThrowsOnOversizedFrame()
{
using var stream = new MemoryStream();
var largeFrame = new Frame
{
Type = FrameType.Request,
CorrelationId = Guid.NewGuid().ToString("N"),
Payload = new byte[1000]
};
await FrameProtocol.WriteFrameAsync(stream, largeFrame, CancellationToken.None);
stream.Position = 0;
// Max frame size is smaller than the written frame
await Assert.ThrowsAsync<InvalidOperationException>(
() => FrameProtocol.ReadFrameAsync(stream, 100, CancellationToken.None));
}
}
public class PendingRequestTrackerTests
{
[Fact]
public async Task TrackRequest_CompletesWithResponse()
{
using var tracker = new PendingRequestTracker();
var correlationId = Guid.NewGuid();
var expectedResponse = new Frame
{
Type = FrameType.Response,
CorrelationId = correlationId.ToString("N"),
Payload = ReadOnlyMemory<byte>.Empty
};
var responseTask = tracker.TrackRequest(correlationId, CancellationToken.None);
Assert.False(responseTask.IsCompleted);
tracker.CompleteRequest(correlationId, expectedResponse);
var response = await responseTask;
Assert.Equal(expectedResponse.Type, response.Type);
}
[Fact]
public async Task TrackRequest_CancelsOnTokenCancellation()
{
using var tracker = new PendingRequestTracker();
using var cts = new CancellationTokenSource();
var correlationId = Guid.NewGuid();
var responseTask = tracker.TrackRequest(correlationId, cts.Token);
cts.Cancel();
await Assert.ThrowsAsync<TaskCanceledException>(() => responseTask);
}
[Fact]
public void Count_ReturnsCorrectValue()
{
using var tracker = new PendingRequestTracker();
Assert.Equal(0, tracker.Count);
_ = tracker.TrackRequest(Guid.NewGuid(), CancellationToken.None);
_ = tracker.TrackRequest(Guid.NewGuid(), CancellationToken.None);
Assert.Equal(2, tracker.Count);
}
[Fact]
public void CancelAll_CancelsAllPendingRequests()
{
using var tracker = new PendingRequestTracker();
var task1 = tracker.TrackRequest(Guid.NewGuid(), CancellationToken.None);
var task2 = tracker.TrackRequest(Guid.NewGuid(), CancellationToken.None);
tracker.CancelAll();
Assert.True(task1.IsCanceled || task1.IsFaulted);
Assert.True(task2.IsCanceled || task2.IsFaulted);
}
[Fact]
public void FailRequest_SetsException()
{
using var tracker = new PendingRequestTracker();
var correlationId = Guid.NewGuid();
var task = tracker.TrackRequest(correlationId, CancellationToken.None);
tracker.FailRequest(correlationId, new InvalidOperationException("Test error"));
Assert.True(task.IsFaulted);
Assert.IsType<InvalidOperationException>(task.Exception?.InnerException);
}
}
public class TcpTransportServerTests
{
[Fact]
public async Task StartAsync_StartsListening()
{
var options = Options.Create(new TcpTransportOptions { Port = 0 }); // Port 0 = auto-assign
await using var server = new TcpTransportServer(options, NullLogger<TcpTransportServer>.Instance);
await server.StartAsync(CancellationToken.None);
Assert.Equal(0, server.ConnectionCount);
await server.StopAsync(CancellationToken.None);
}
}