Refactor code structure and optimize performance across multiple modules

This commit is contained in:
StellaOps Bot
2025-12-26 20:03:22 +02:00
parent c786faae84
commit b4fc66feb6
3353 changed files with 88254 additions and 1590657 deletions

View File

@@ -12,6 +12,8 @@ using StellaOps.Router.Transport.InMemory;
using StellaOps.Router.Transport.Tls;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Router.Transport.Tcp.Tests;
/// <summary>
@@ -40,21 +42,24 @@ public sealed class ConnectionFailureTests : IDisposable
#region Connection Failure Scenarios
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Options_MaxReconnectAttempts_DefaultIsTen()
{
var options = new TcpTransportOptions();
options.MaxReconnectAttempts.Should().Be(10);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Options_MaxReconnectBackoff_DefaultIsOneMinute()
{
var options = new TcpTransportOptions();
options.MaxReconnectBackoff.Should().Be(TimeSpan.FromMinutes(1));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Options_ReconnectSettings_CanBeCustomized()
{
var options = new TcpTransportOptions
@@ -71,7 +76,8 @@ public sealed class ConnectionFailureTests : IDisposable
#region Exponential Backoff Calculation
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData(1, 200)] // 2^1 * 100 = 200ms
[InlineData(2, 400)] // 2^2 * 100 = 400ms
[InlineData(3, 800)] // 2^3 * 100 = 800ms
@@ -84,7 +90,8 @@ public sealed class ConnectionFailureTests : IDisposable
calculated.Should().Be(expectedMs);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Backoff_CappedAtMaximum_WhenExceedsLimit()
{
var maxBackoff = TimeSpan.FromMinutes(1);
@@ -96,7 +103,8 @@ public sealed class ConnectionFailureTests : IDisposable
capped.Should().Be(maxBackoff.TotalMilliseconds);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Backoff_Sequence_IsMonotonicallyIncreasing()
{
var maxBackoff = TimeSpan.FromMinutes(1);
@@ -118,7 +126,8 @@ public sealed class ConnectionFailureTests : IDisposable
#region Connection Refused Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Connect_ServerNotListening_ThrowsException()
{
// Arrange - Stop the listener so connection will be refused
@@ -148,7 +157,8 @@ public sealed class ConnectionFailureTests : IDisposable
await client.DisposeAsync();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Connect_InvalidHost_ThrowsException()
{
var options = new TcpTransportOptions
@@ -179,7 +189,8 @@ public sealed class ConnectionFailureTests : IDisposable
#region Connection Drop Detection
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ServerDropsConnection_ReadReturnsNull()
{
// This test verifies the frame protocol handles connection drops
@@ -205,7 +216,8 @@ public sealed class ConnectionFailureTests : IDisposable
#region Reconnection State Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ReconnectAttempts_ResetOnSuccessfulConnection()
{
// This is a behavioral expectation from the implementation:
@@ -224,7 +236,8 @@ public sealed class ConnectionFailureTests : IDisposable
options.MaxReconnectAttempts.Should().Be(3);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ReconnectionLoop_RespectsMaxAttempts()
{
// Arrange
@@ -244,7 +257,8 @@ public sealed class ConnectionFailureTests : IDisposable
#region Frame Protocol Connection Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task FrameProtocol_ReadFromClosedStream_ReturnsNull()
{
// Arrange
@@ -257,7 +271,8 @@ public sealed class ConnectionFailureTests : IDisposable
frame.Should().BeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task FrameProtocol_PartialRead_HandlesGracefully()
{
// Arrange - Create a stream with incomplete frame header
@@ -276,7 +291,8 @@ public sealed class ConnectionFailureTests : IDisposable
#region Timeout Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Connect_Timeout_RespectsTimeoutSetting()
{
var options = new TcpTransportOptions
@@ -319,7 +335,8 @@ public sealed class ConnectionFailureTests : IDisposable
#region Disposal During Reconnection
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Dispose_DuringPendingConnect_CancelsGracefully()
{
var options = new TcpTransportOptions
@@ -360,7 +377,8 @@ public sealed class ConnectionFailureTests : IDisposable
#region Socket Error Classification
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SocketException_ConnectionRefused_IsRecoverable()
{
var ex = new SocketException((int)SocketError.ConnectionRefused);
@@ -369,7 +387,8 @@ public sealed class ConnectionFailureTests : IDisposable
ex.SocketErrorCode.Should().Be(SocketError.ConnectionRefused);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SocketException_ConnectionReset_IsRecoverable()
{
var ex = new SocketException((int)SocketError.ConnectionReset);
@@ -378,7 +397,8 @@ public sealed class ConnectionFailureTests : IDisposable
ex.SocketErrorCode.Should().Be(SocketError.ConnectionReset);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SocketException_NetworkUnreachable_IsRecoverable()
{
var ex = new SocketException((int)SocketError.NetworkUnreachable);
@@ -387,7 +407,8 @@ public sealed class ConnectionFailureTests : IDisposable
ex.SocketErrorCode.Should().Be(SocketError.NetworkUnreachable);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SocketException_TimedOut_IsRecoverable()
{
var ex = new SocketException((int)SocketError.TimedOut);
@@ -400,7 +421,8 @@ public sealed class ConnectionFailureTests : IDisposable
#region Multiple Reconnection Cycles
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void BackoffSequence_MultipleFullCycles_Deterministic()
{
// Verify that backoff calculation is deterministic across cycles
@@ -429,7 +451,8 @@ public sealed class ConnectionFailureTests : IDisposable
#region Connection State Tracking
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Client_InitialState_NotConnected()
{
var options = new TcpTransportOptions
@@ -457,21 +480,24 @@ public sealed class TlsConnectionFailureTests
{
#region TLS-Specific Options
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void TlsOptions_MaxReconnectAttempts_DefaultIsTen()
{
var options = new TlsTransportOptions();
options.MaxReconnectAttempts.Should().Be(10);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void TlsOptions_MaxReconnectBackoff_DefaultIsOneMinute()
{
var options = new TlsTransportOptions();
options.MaxReconnectBackoff.Should().Be(TimeSpan.FromMinutes(1));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void TlsOptions_ReconnectAndSsl_CanBeCombined()
{
var options = new TlsTransportOptions
@@ -492,7 +518,8 @@ public sealed class TlsConnectionFailureTests
#region TLS Connection Failures
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task TlsConnect_InvalidCertificate_ShouldFail()
{
// TLS connections with invalid certificates should fail
@@ -511,7 +538,8 @@ public sealed class TlsConnectionFailureTests
options.Should().NotBeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void TlsBackoff_SameFormulaAsTcp()
{
// TLS uses the same exponential backoff formula
@@ -531,7 +559,8 @@ public sealed class TlsConnectionFailureTests
/// </summary>
public sealed class InMemoryConnectionFailureTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void InMemoryChannel_NoReconnection_NotApplicable()
{
// InMemory transport doesn't have network connections
@@ -553,7 +582,8 @@ public sealed class InMemoryConnectionFailureTests
canWrite.Should().BeFalse();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task InMemoryChannel_CompletedWithError_PropagatesError()
{
using var channel = new InMemoryChannel("error-complete");

View File

@@ -3,6 +3,8 @@ using System.Text;
using StellaOps.Router.Common.Enums;
using StellaOps.Router.Common.Models;
using StellaOps.TestKit;
namespace StellaOps.Router.Transport.Tcp.Tests;
/// <summary>
@@ -13,7 +15,8 @@ public sealed class FrameFuzzTests
{
#region Truncated Frame Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_EmptyStream_ReturnsNull()
{
// Arrange
@@ -26,7 +29,8 @@ public sealed class FrameFuzzTests
result.Should().BeNull();
}
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
@@ -41,7 +45,8 @@ public sealed class FrameFuzzTests
.WithMessage("*Incomplete length prefix*");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_LengthPrefixOnly_ThrowsException()
{
// Arrange - Valid length prefix but no payload
@@ -57,7 +62,8 @@ public sealed class FrameFuzzTests
.WithMessage("*Incomplete payload*");
}
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData(50, 10)]
[InlineData(100, 25)]
[InlineData(1000, 100)]
@@ -81,7 +87,8 @@ public sealed class FrameFuzzTests
#region Invalid Length Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_NegativeLength_ThrowsException()
{
// Arrange - Negative length (high bit set in signed int)
@@ -96,7 +103,8 @@ public sealed class FrameFuzzTests
await action.Should().ThrowAsync<InvalidOperationException>();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_ZeroLength_ThrowsException()
{
// Arrange
@@ -112,7 +120,8 @@ public sealed class FrameFuzzTests
.WithMessage("*Invalid payload length*");
}
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData(1)]
[InlineData(5)]
[InlineData(16)]
@@ -132,7 +141,8 @@ public sealed class FrameFuzzTests
.WithMessage("*Invalid payload length*");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_OversizedLength_ThrowsException()
{
// Arrange - Frame larger than max allowed
@@ -156,7 +166,8 @@ public sealed class FrameFuzzTests
#region Invalid Frame Type Tests
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData(255)]
[InlineData(100)]
[InlineData(50)]
@@ -187,7 +198,8 @@ public sealed class FrameFuzzTests
#region Corrupted Correlation ID Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_AllZeroCorrelationId_ReadSuccessfully()
{
// Arrange
@@ -210,7 +222,8 @@ public sealed class FrameFuzzTests
result!.CorrelationId.Should().Be("00000000000000000000000000000000");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_NonGuidCorrelationBytes_ReadAsHex()
{
// Arrange - Non-standard bytes that aren't a valid GUID
@@ -238,7 +251,8 @@ public sealed class FrameFuzzTests
#region Random Data Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_RandomBytes_HandledGracefully()
{
// Arrange
@@ -260,7 +274,8 @@ public sealed class FrameFuzzTests
}
}
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData(10)]
[InlineData(50)]
[InlineData(100)]
@@ -294,7 +309,8 @@ public sealed class FrameFuzzTests
#region Boundary Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_ExactMinimumValidFrame_ParsesSuccessfully()
{
// Arrange - Minimum valid frame: type (1) + correlation (16) + 0 payload = 17 bytes
@@ -317,7 +333,8 @@ public sealed class FrameFuzzTests
result.Payload.Length.Should().Be(0);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_MaxIntLength_RejectedByMaxFrameSize()
{
// Arrange - Length = Int32.MaxValue
@@ -333,7 +350,8 @@ public sealed class FrameFuzzTests
.WithMessage("*exceeds maximum*");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_ExactMaxFrameSize_Accepted()
{
// Arrange
@@ -358,7 +376,8 @@ public sealed class FrameFuzzTests
result.Should().NotBeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_OneBytOverMaxFrameSize_Rejected()
{
// Arrange
@@ -386,7 +405,8 @@ public sealed class FrameFuzzTests
#region Multiple Frames Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_GarbageBetweenFrames_CorruptsSubsequent()
{
// Arrange - Valid frame, then garbage, then valid frame
@@ -424,7 +444,8 @@ public sealed class FrameFuzzTests
await action.Should().ThrowAsync<InvalidOperationException>();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_MultipleValidFrames_AllParsed()
{
// Arrange
@@ -463,7 +484,8 @@ public sealed class FrameFuzzTests
#region Payload Content Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_AllByteValues_InPayload_Preserved()
{
// Arrange - All possible byte values (0-255)
@@ -487,7 +509,8 @@ public sealed class FrameFuzzTests
result!.Payload.ToArray().Should().BeEquivalentTo(allBytes);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Fuzz_NullBytes_InPayload_Preserved()
{
// Arrange - Payload with null bytes

View File

@@ -25,6 +25,7 @@
<ProjectReference Include="..\..\StellaOps.Router.Transport.Tls\StellaOps.Router.Transport.Tls.csproj" />
<ProjectReference Include="..\..\StellaOps.Router.Transport.InMemory\StellaOps.Router.Transport.InMemory.csproj" />
<ProjectReference Include="..\..\StellaOps.Router.Common\StellaOps.Router.Common.csproj" />
<ProjectReference Include="../../StellaOps.TestKit/StellaOps.TestKit.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />

View File

@@ -3,6 +3,8 @@ using StellaOps.Router.Common.Enums;
using StellaOps.Router.Common.Frames;
using StellaOps.Router.Common.Models;
using StellaOps.TestKit;
namespace StellaOps.Router.Transport.Tcp.Tests;
/// <summary>
@@ -13,7 +15,8 @@ public sealed class TcpTransportComplianceTests
{
#region Protocol Roundtrip Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ProtocolRoundtrip_RequestFrame_AllFieldsPreserved()
{
// Arrange
@@ -57,7 +60,8 @@ public sealed class TcpTransportComplianceTests
restored.SupportsStreaming.Should().Be(request.SupportsStreaming);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ProtocolRoundtrip_ResponseFrame_AllFieldsPreserved()
{
// Arrange
@@ -93,7 +97,8 @@ public sealed class TcpTransportComplianceTests
restored.HasMoreChunks.Should().Be(response.HasMoreChunks);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ProtocolRoundtrip_BinaryPayload_PreservesAllBytes()
{
// Arrange
@@ -118,7 +123,8 @@ public sealed class TcpTransportComplianceTests
readFrame!.Payload.ToArray().Should().BeEquivalentTo(binaryPayload);
}
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(100)]
@@ -157,7 +163,8 @@ public sealed class TcpTransportComplianceTests
#region Frame Type Discrimination Tests
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData(FrameType.Request)]
[InlineData(FrameType.Response)]
[InlineData(FrameType.Hello)]
@@ -188,7 +195,8 @@ public sealed class TcpTransportComplianceTests
#region Message Ordering Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Ordering_MultipleFrames_FifoPreserved()
{
// Arrange
@@ -226,7 +234,8 @@ public sealed class TcpTransportComplianceTests
}
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Ordering_MixedFrameTypes_OrderPreserved()
{
// Arrange
@@ -266,7 +275,8 @@ public sealed class TcpTransportComplianceTests
#region Framing Integrity Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task FramingIntegrity_CorrelationIdPreserved()
{
// Arrange
@@ -300,7 +310,8 @@ public sealed class TcpTransportComplianceTests
}
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task FramingIntegrity_LargeFrame_TransfersCompletely()
{
// Arrange - 1MB frame
@@ -328,7 +339,8 @@ public sealed class TcpTransportComplianceTests
#region Connection Behavior Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ConnectionBehavior_PendingRequestTracker_TracksCorrectly()
{
// Arrange
@@ -354,7 +366,8 @@ public sealed class TcpTransportComplianceTests
tracker.Count.Should().Be(0);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ConnectionBehavior_RequestTimeout_CancelsCleanly()
{
// Arrange
@@ -370,7 +383,8 @@ public sealed class TcpTransportComplianceTests
tracker.Count.Should().Be(0);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ConnectionBehavior_CancelAll_ClearsAllPending()
{
// Arrange
@@ -389,7 +403,8 @@ public sealed class TcpTransportComplianceTests
tasks.Should().AllSatisfy(t => t.IsCanceled.Should().BeTrue());
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ConnectionBehavior_FailRequest_PropagatesToAwaiter()
{
// Arrange
@@ -410,7 +425,8 @@ public sealed class TcpTransportComplianceTests
#region Determinism Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Determinism_SameInput_SameOutput()
{
// Run same test multiple times - should always produce same results
@@ -445,7 +461,8 @@ public sealed class TcpTransportComplianceTests
}
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Determinism_ByteSequence_Consistent()
{
// Arrange - Write same frame twice
@@ -471,7 +488,8 @@ public sealed class TcpTransportComplianceTests
#region Error Handling Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ErrorHandling_OversizedFrame_Rejected()
{
// Arrange
@@ -495,7 +513,8 @@ public sealed class TcpTransportComplianceTests
.WithMessage("*exceeds maximum*");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ErrorHandling_EmptyStream_ReturnsNull()
{
// Arrange
@@ -508,7 +527,8 @@ public sealed class TcpTransportComplianceTests
result.Should().BeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ErrorHandling_CancellationDuringWrite_Throws()
{
// Arrange

View File

@@ -7,13 +7,16 @@ using StellaOps.Router.Common.Models;
using StellaOps.Router.Transport.Tcp;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Router.Transport.Tcp.Tests;
#region TcpTransportOptions Tests
public class TcpTransportOptionsTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void DefaultOptions_HaveCorrectValues()
{
// Act
@@ -30,7 +33,8 @@ public class TcpTransportOptionsTests
options.MaxFrameSize.Should().Be(16 * 1024 * 1024);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Host_CanBeSet()
{
// Act
@@ -40,7 +44,8 @@ public class TcpTransportOptionsTests
options.Host.Should().Be("192.168.1.100");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Port_CanBeSet()
{
// Act
@@ -50,7 +55,8 @@ public class TcpTransportOptionsTests
options.Port.Should().Be(9999);
}
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData(1024)]
[InlineData(128 * 1024)]
[InlineData(1024 * 1024)]
@@ -63,7 +69,8 @@ public class TcpTransportOptionsTests
options.ReceiveBufferSize.Should().Be(bufferSize);
}
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData(1024)]
[InlineData(128 * 1024)]
[InlineData(1024 * 1024)]
@@ -76,7 +83,8 @@ public class TcpTransportOptionsTests
options.SendBufferSize.Should().Be(bufferSize);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void MaxReconnectAttempts_CanBeSetToZero()
{
// Act
@@ -93,7 +101,8 @@ public class TcpTransportOptionsTests
public class FrameProtocolTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task WriteAndReadFrame_RoundTrip()
{
// Arrange
@@ -119,7 +128,8 @@ public class FrameProtocolTests
readFrame.Payload.ToArray().Should().Equal(originalFrame.Payload.ToArray());
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task WriteAndReadFrame_EmptyPayload()
{
// Arrange
@@ -142,7 +152,8 @@ public class FrameProtocolTests
readFrame.Payload.ToArray().Should().BeEmpty();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ReadFrame_ReturnsNullOnEmptyStream()
{
// Arrange
@@ -155,7 +166,8 @@ public class FrameProtocolTests
result.Should().BeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ReadFrame_ThrowsOnOversizedFrame()
{
// Arrange
@@ -176,7 +188,8 @@ public class FrameProtocolTests
.WithMessage("*exceeds maximum*");
}
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData(FrameType.Request)]
[InlineData(FrameType.Response)]
[InlineData(FrameType.Cancel)]
@@ -203,7 +216,8 @@ public class FrameProtocolTests
readFrame!.Type.Should().Be(frameType);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task WriteFrame_WithNullCorrelationId_GeneratesNewGuid()
{
// Arrange
@@ -226,7 +240,8 @@ public class FrameProtocolTests
Guid.TryParse(readFrame.CorrelationId, out _).Should().BeTrue();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task WriteFrame_BigEndianLength_CorrectByteOrder()
{
// Arrange
@@ -252,7 +267,8 @@ public class FrameProtocolTests
actualLength.Should().Be(expectedLength);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ReadFrame_IncompleteLengthPrefix_ThrowsException()
{
// Arrange - Only 2 bytes instead of 4 for length prefix
@@ -264,7 +280,8 @@ public class FrameProtocolTests
.WithMessage("*Incomplete length prefix*");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ReadFrame_InvalidPayloadLength_TooSmall_ThrowsException()
{
// Arrange - Length of 5 is too small (header is 17 bytes minimum)
@@ -280,7 +297,8 @@ public class FrameProtocolTests
.WithMessage("*Invalid payload length*");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ReadFrame_IncompletePayload_ThrowsException()
{
// Arrange - Claim to have 100 bytes but only provide 10
@@ -297,7 +315,8 @@ public class FrameProtocolTests
.WithMessage("*Incomplete payload*");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ReadFrame_WithLargePayload_ReadsCorrectly()
{
// Arrange
@@ -322,7 +341,8 @@ public class FrameProtocolTests
readFrame!.Payload.ToArray().Should().Equal(largePayload);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task WriteFrame_CancellationRequested_ThrowsOperationCanceled()
{
// Arrange
@@ -348,7 +368,8 @@ public class FrameProtocolTests
public class PendingRequestTrackerTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task TrackRequest_CompletesWithResponse()
{
// Arrange
@@ -371,7 +392,8 @@ public class PendingRequestTrackerTests
response.Type.Should().Be(expectedResponse.Type);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task TrackRequest_CancelsOnTokenCancellation()
{
// Arrange
@@ -388,7 +410,8 @@ public class PendingRequestTrackerTests
await action.Should().ThrowAsync<TaskCanceledException>();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Count_ReturnsCorrectValue()
{
// Arrange
@@ -401,7 +424,8 @@ public class PendingRequestTrackerTests
tracker.Count.Should().Be(2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CancelAll_CancelsAllPendingRequests()
{
// Arrange
@@ -417,7 +441,8 @@ public class PendingRequestTrackerTests
task2.IsCanceled.Should().BeTrue();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void FailRequest_SetsException()
{
// Arrange
@@ -433,7 +458,8 @@ public class PendingRequestTrackerTests
task.Exception?.InnerException.Should().BeOfType<InvalidOperationException>();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CancelRequest_CancelsSpecificRequest()
{
// Arrange
@@ -452,7 +478,8 @@ public class PendingRequestTrackerTests
task2.IsCompleted.Should().BeFalse();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CompleteRequest_WithUnknownId_DoesNotThrow()
{
// Arrange
@@ -467,7 +494,8 @@ public class PendingRequestTrackerTests
action.Should().NotThrow();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CancelRequest_WithUnknownId_DoesNotThrow()
{
// Arrange
@@ -481,7 +509,8 @@ public class PendingRequestTrackerTests
action.Should().NotThrow();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void FailRequest_WithUnknownId_DoesNotThrow()
{
// Arrange
@@ -495,7 +524,8 @@ public class PendingRequestTrackerTests
action.Should().NotThrow();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Dispose_CancelsAllPendingRequests()
{
// Arrange
@@ -509,7 +539,8 @@ public class PendingRequestTrackerTests
(task.IsCanceled || task.IsFaulted).Should().BeTrue();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Dispose_CanBeCalledMultipleTimes()
{
// Arrange
@@ -527,7 +558,8 @@ public class PendingRequestTrackerTests
action.Should().NotThrow();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CompleteRequest_DecreasesCount()
{
// Arrange
@@ -553,7 +585,8 @@ public class PendingRequestTrackerTests
public class TcpTransportServerTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StartAsync_StartsListening()
{
// Arrange
@@ -568,7 +601,8 @@ public class TcpTransportServerTests
await server.StopAsync(CancellationToken.None);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StopAsync_CanBeCalledWithoutStart()
{
// Arrange
@@ -582,7 +616,8 @@ public class TcpTransportServerTests
await action.Should().NotThrowAsync();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ConnectionCount_InitiallyZero()
{
// Arrange
@@ -593,7 +628,8 @@ public class TcpTransportServerTests
server.ConnectionCount.Should().Be(0);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DisposeAsync_CanBeCalledMultipleTimes()
{
// Arrange
@@ -612,7 +648,8 @@ public class TcpTransportServerTests
await action.Should().NotThrowAsync();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StartAsync_TwiceDoesNotThrow()
{
// Arrange
@@ -643,7 +680,8 @@ public class TcpTransportClientTests
NullLogger<TcpTransportClient>.Instance);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Constructor_InitializesCorrectly()
{
// Act
@@ -653,7 +691,8 @@ public class TcpTransportClientTests
client.Should().NotBeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ConnectAsync_WithoutHost_ThrowsInvalidOperationException()
{
// Arrange
@@ -675,7 +714,8 @@ public class TcpTransportClientTests
.WithMessage("*Host is not configured*");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ConnectAsync_WithEmptyHost_ThrowsInvalidOperationException()
{
// Arrange
@@ -697,7 +737,8 @@ public class TcpTransportClientTests
.WithMessage("*Host is not configured*");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DisposeAsync_CanBeCalledMultipleTimes()
{
// Arrange
@@ -715,7 +756,8 @@ public class TcpTransportClientTests
await action.Should().NotThrowAsync();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DisconnectAsync_WithoutConnect_DoesNotThrow()
{
// Arrange
@@ -728,7 +770,8 @@ public class TcpTransportClientTests
await action.Should().NotThrowAsync();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CancelAllInflight_WithNoInflight_DoesNotThrow()
{
// Arrange