Files
git.stella-ops.org/src/__Libraries/__Tests/StellaOps.Router.Common.Tests/FrameConverterTests.cs

580 lines
15 KiB
C#

using System.Text;
using StellaOps.Router.Common.Enums;
using StellaOps.Router.Common.Frames;
using StellaOps.Router.Common.Models;
using StellaOps.TestKit;
namespace StellaOps.Router.Common.Tests;
/// <summary>
/// Unit tests for <see cref="FrameConverter"/>.
/// </summary>
public sealed class FrameConverterTests
{
#region ToFrame (RequestFrame) Tests
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToFrame_RequestFrame_ReturnsFrameWithRequestType()
{
// Arrange
var request = CreateTestRequestFrame();
// Act
var frame = FrameConverter.ToFrame(request);
// Assert
frame.Type.Should().Be(FrameType.Request);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToFrame_RequestFrame_SetsCorrelationIdFromRequest()
{
// Arrange
var request = CreateTestRequestFrame(correlationId: "test-correlation-123");
// Act
var frame = FrameConverter.ToFrame(request);
// Assert
frame.CorrelationId.Should().Be("test-correlation-123");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToFrame_RequestFrame_UsesRequestIdWhenCorrelationIdIsNull()
{
// Arrange
var request = new RequestFrame
{
RequestId = "request-id-456",
CorrelationId = null,
Method = "GET",
Path = "/test"
};
// Act
var frame = FrameConverter.ToFrame(request);
// Assert
frame.CorrelationId.Should().Be("request-id-456");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToFrame_RequestFrame_SerializesPayload()
{
// Arrange
var request = CreateTestRequestFrame();
// Act
var frame = FrameConverter.ToFrame(request);
// Assert
frame.Payload.Length.Should().BeGreaterThan(0);
}
#endregion
#region ToRequestFrame Tests
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToRequestFrame_ValidRequestFrame_ReturnsRequestFrame()
{
// Arrange
var originalRequest = CreateTestRequestFrame();
var frame = FrameConverter.ToFrame(originalRequest);
// Act
var result = FrameConverter.ToRequestFrame(frame);
// Assert
result.Should().NotBeNull();
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToRequestFrame_WrongFrameType_ReturnsNull()
{
// Arrange
var frame = new Frame
{
Type = FrameType.Response,
CorrelationId = "test",
Payload = Array.Empty<byte>()
};
// Act
var result = FrameConverter.ToRequestFrame(frame);
// Assert
result.Should().BeNull();
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToRequestFrame_InvalidJson_ReturnsNull()
{
// Arrange
var frame = new Frame
{
Type = FrameType.Request,
CorrelationId = "test",
Payload = Encoding.UTF8.GetBytes("invalid json {{{")
};
// Act
var result = FrameConverter.ToRequestFrame(frame);
// Assert
result.Should().BeNull();
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToRequestFrame_RoundTrip_PreservesRequestId()
{
// Arrange
var originalRequest = CreateTestRequestFrame(requestId: "unique-request-id");
var frame = FrameConverter.ToFrame(originalRequest);
// Act
var result = FrameConverter.ToRequestFrame(frame);
// Assert
result!.RequestId.Should().Be("unique-request-id");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToRequestFrame_RoundTrip_PreservesMethod()
{
// Arrange
var originalRequest = CreateTestRequestFrame(method: "DELETE");
var frame = FrameConverter.ToFrame(originalRequest);
// Act
var result = FrameConverter.ToRequestFrame(frame);
// Assert
result!.Method.Should().Be("DELETE");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToRequestFrame_RoundTrip_PreservesPath()
{
// Arrange
var originalRequest = CreateTestRequestFrame(path: "/api/users/123");
var frame = FrameConverter.ToFrame(originalRequest);
// Act
var result = FrameConverter.ToRequestFrame(frame);
// Assert
result!.Path.Should().Be("/api/users/123");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToRequestFrame_RoundTrip_PreservesHeaders()
{
// Arrange
var headers = new Dictionary<string, string>
{
["Content-Type"] = "application/json",
["X-Custom-Header"] = "custom-value"
};
var originalRequest = new RequestFrame
{
RequestId = "test-id",
Method = "POST",
Path = "/test",
Headers = headers
};
var frame = FrameConverter.ToFrame(originalRequest);
// Act
var result = FrameConverter.ToRequestFrame(frame);
// Assert
result!.Headers.Should().ContainKey("Content-Type");
result.Headers["Content-Type"].Should().Be("application/json");
result.Headers["X-Custom-Header"].Should().Be("custom-value");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToRequestFrame_RoundTrip_PreservesPayload()
{
// Arrange
var payloadBytes = Encoding.UTF8.GetBytes("{\"key\":\"value\"}");
var originalRequest = new RequestFrame
{
RequestId = "test-id",
Method = "POST",
Path = "/test",
Payload = payloadBytes
};
var frame = FrameConverter.ToFrame(originalRequest);
// Act
var result = FrameConverter.ToRequestFrame(frame);
// Assert
result!.Payload.ToArray().Should().BeEquivalentTo(payloadBytes);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToRequestFrame_RoundTrip_PreservesTimeoutSeconds()
{
// Arrange
var originalRequest = new RequestFrame
{
RequestId = "test-id",
Method = "GET",
Path = "/test",
TimeoutSeconds = 60
};
var frame = FrameConverter.ToFrame(originalRequest);
// Act
var result = FrameConverter.ToRequestFrame(frame);
// Assert
result!.TimeoutSeconds.Should().Be(60);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToRequestFrame_RoundTrip_PreservesSupportsStreaming()
{
// Arrange
var originalRequest = new RequestFrame
{
RequestId = "test-id",
Method = "GET",
Path = "/test",
SupportsStreaming = true
};
var frame = FrameConverter.ToFrame(originalRequest);
// Act
var result = FrameConverter.ToRequestFrame(frame);
// Assert
result!.SupportsStreaming.Should().BeTrue();
}
#endregion
#region ToFrame (ResponseFrame) Tests
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToFrame_ResponseFrame_ReturnsFrameWithResponseType()
{
// Arrange
var response = CreateTestResponseFrame();
// Act
var frame = FrameConverter.ToFrame(response);
// Assert
frame.Type.Should().Be(FrameType.Response);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToFrame_ResponseFrame_SetsCorrelationIdToRequestId()
{
// Arrange
var response = CreateTestResponseFrame(requestId: "req-123");
// Act
var frame = FrameConverter.ToFrame(response);
// Assert
frame.CorrelationId.Should().Be("req-123");
}
#endregion
#region ToResponseFrame Tests
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToResponseFrame_ValidResponseFrame_ReturnsResponseFrame()
{
// Arrange
var originalResponse = CreateTestResponseFrame();
var frame = FrameConverter.ToFrame(originalResponse);
// Act
var result = FrameConverter.ToResponseFrame(frame);
// Assert
result.Should().NotBeNull();
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToResponseFrame_WrongFrameType_ReturnsNull()
{
// Arrange
var frame = new Frame
{
Type = FrameType.Request,
CorrelationId = "test",
Payload = Array.Empty<byte>()
};
// Act
var result = FrameConverter.ToResponseFrame(frame);
// Assert
result.Should().BeNull();
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToResponseFrame_InvalidJson_ReturnsNull()
{
// Arrange
var frame = new Frame
{
Type = FrameType.Response,
CorrelationId = "test",
Payload = Encoding.UTF8.GetBytes("not valid json")
};
// Act
var result = FrameConverter.ToResponseFrame(frame);
// Assert
result.Should().BeNull();
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToResponseFrame_RoundTrip_PreservesRequestId()
{
// Arrange
var originalResponse = CreateTestResponseFrame(requestId: "original-req-id");
var frame = FrameConverter.ToFrame(originalResponse);
// Act
var result = FrameConverter.ToResponseFrame(frame);
// Assert
result!.RequestId.Should().Be("original-req-id");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToResponseFrame_RoundTrip_PreservesStatusCode()
{
// Arrange
var originalResponse = CreateTestResponseFrame(statusCode: 404);
var frame = FrameConverter.ToFrame(originalResponse);
// Act
var result = FrameConverter.ToResponseFrame(frame);
// Assert
result!.StatusCode.Should().Be(404);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToResponseFrame_RoundTrip_PreservesHeaders()
{
// Arrange
var headers = new Dictionary<string, string>
{
["Content-Type"] = "application/json",
["Cache-Control"] = "no-cache"
};
var originalResponse = new ResponseFrame
{
RequestId = "test-id",
StatusCode = 200,
Headers = headers
};
var frame = FrameConverter.ToFrame(originalResponse);
// Act
var result = FrameConverter.ToResponseFrame(frame);
// Assert
result!.Headers["Content-Type"].Should().Be("application/json");
result.Headers["Cache-Control"].Should().Be("no-cache");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToResponseFrame_RoundTrip_PreservesPayload()
{
// Arrange
var payloadBytes = Encoding.UTF8.GetBytes("{\"result\":\"success\"}");
var originalResponse = new ResponseFrame
{
RequestId = "test-id",
StatusCode = 200,
Payload = payloadBytes
};
var frame = FrameConverter.ToFrame(originalResponse);
// Act
var result = FrameConverter.ToResponseFrame(frame);
// Assert
result!.Payload.ToArray().Should().BeEquivalentTo(payloadBytes);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToResponseFrame_RoundTrip_PreservesHasMoreChunks()
{
// Arrange
var originalResponse = new ResponseFrame
{
RequestId = "test-id",
StatusCode = 200,
HasMoreChunks = true
};
var frame = FrameConverter.ToFrame(originalResponse);
// Act
var result = FrameConverter.ToResponseFrame(frame);
// Assert
result!.HasMoreChunks.Should().BeTrue();
}
#endregion
#region Edge Cases
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToRequestFrame_EmptyPayload_ReturnsEmptyPayload()
{
// Arrange
var originalRequest = new RequestFrame
{
RequestId = "test-id",
Method = "GET",
Path = "/test",
Payload = Array.Empty<byte>()
};
var frame = FrameConverter.ToFrame(originalRequest);
// Act
var result = FrameConverter.ToRequestFrame(frame);
// Assert
result!.Payload.IsEmpty.Should().BeTrue();
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToRequestFrame_NullHeaders_ReturnsEmptyHeaders()
{
// Arrange
var originalRequest = new RequestFrame
{
RequestId = "test-id",
Method = "GET",
Path = "/test"
};
var frame = FrameConverter.ToFrame(originalRequest);
// Act
var result = FrameConverter.ToRequestFrame(frame);
// Assert
result!.Headers.Should().NotBeNull();
result.Headers.Should().BeEmpty();
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToResponseFrame_EmptyPayload_ReturnsEmptyPayload()
{
// Arrange
var originalResponse = new ResponseFrame
{
RequestId = "test-id",
StatusCode = 204,
Payload = Array.Empty<byte>()
};
var frame = FrameConverter.ToFrame(originalResponse);
// Act
var result = FrameConverter.ToResponseFrame(frame);
// Assert
result!.Payload.IsEmpty.Should().BeTrue();
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ToFrame_LargePayload_Succeeds()
{
// Arrange
var largePayload = new byte[1024 * 1024]; // 1MB
Random.Shared.NextBytes(largePayload);
var originalRequest = new RequestFrame
{
RequestId = "test-id",
Method = "POST",
Path = "/upload",
Payload = largePayload
};
// Act
var frame = FrameConverter.ToFrame(originalRequest);
var result = FrameConverter.ToRequestFrame(frame);
// Assert
result.Should().NotBeNull();
result!.Payload.ToArray().Should().BeEquivalentTo(largePayload);
}
#endregion
#region Helper Methods
private static RequestFrame CreateTestRequestFrame(
string? requestId = null,
string? correlationId = null,
string method = "GET",
string path = "/test")
{
return new RequestFrame
{
RequestId = requestId ?? Guid.NewGuid().ToString("N"),
CorrelationId = correlationId,
Method = method,
Path = path
};
}
private static ResponseFrame CreateTestResponseFrame(
string? requestId = null,
int statusCode = 200)
{
return new ResponseFrame
{
RequestId = requestId ?? Guid.NewGuid().ToString("N"),
StatusCode = statusCode
};
}
#endregion
}