75 lines
2.5 KiB
C#
75 lines
2.5 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Shared;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Shared.Contracts;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Shared.Tests;
|
|
|
|
[Trait("Category", "Unit")]
|
|
public sealed class FramingTests
|
|
{
|
|
[Fact]
|
|
public async Task FrameWriter_FrameReader_round_trip_preserves_kind_and_body()
|
|
{
|
|
using var ms = new MemoryStream();
|
|
|
|
using (var writer = new FrameWriter(ms, leaveOpen: true))
|
|
{
|
|
await writer.WriteAsync(MessageKind.Hello,
|
|
new Hello { PeerName = "p", SharedSecret = "s" }, TestContext.Current.CancellationToken);
|
|
await writer.WriteAsync(MessageKind.Heartbeat,
|
|
new Heartbeat { SequenceNumber = 7, UtcUnixMs = 42 }, TestContext.Current.CancellationToken);
|
|
}
|
|
|
|
ms.Position = 0;
|
|
using var reader = new FrameReader(ms, leaveOpen: true);
|
|
|
|
var f1 = (await reader.ReadFrameAsync(TestContext.Current.CancellationToken))!.Value;
|
|
f1.Kind.ShouldBe(MessageKind.Hello);
|
|
FrameReader.Deserialize<Hello>(f1.Body).PeerName.ShouldBe("p");
|
|
|
|
var f2 = (await reader.ReadFrameAsync(TestContext.Current.CancellationToken))!.Value;
|
|
f2.Kind.ShouldBe(MessageKind.Heartbeat);
|
|
FrameReader.Deserialize<Heartbeat>(f2.Body).SequenceNumber.ShouldBe(7L);
|
|
|
|
var eof = await reader.ReadFrameAsync(TestContext.Current.CancellationToken);
|
|
eof.ShouldBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task FrameReader_rejects_frames_larger_than_the_cap()
|
|
{
|
|
using var ms = new MemoryStream();
|
|
var evilLen = Framing.MaxFrameBodyBytes + 1;
|
|
ms.Write(new byte[]
|
|
{
|
|
(byte)((evilLen >> 24) & 0xFF),
|
|
(byte)((evilLen >> 16) & 0xFF),
|
|
(byte)((evilLen >> 8) & 0xFF),
|
|
(byte)( evilLen & 0xFF),
|
|
}, 0, 4);
|
|
ms.WriteByte((byte)MessageKind.Hello);
|
|
ms.Position = 0;
|
|
|
|
using var reader = new FrameReader(ms, leaveOpen: true);
|
|
await Should.ThrowAsync<InvalidDataException>(() =>
|
|
reader.ReadFrameAsync(TestContext.Current.CancellationToken).AsTask());
|
|
}
|
|
|
|
private static class TestContext
|
|
{
|
|
public static TestContextHelper Current { get; } = new();
|
|
}
|
|
|
|
private sealed class TestContextHelper
|
|
{
|
|
public CancellationToken CancellationToken => CancellationToken.None;
|
|
}
|
|
}
|
|
|
|
file static class TaskExtensions
|
|
{
|
|
public static Task AsTask<T>(this ValueTask<T> vt) => vt.AsTask();
|
|
public static Task AsTask<T>(this Task<T> t) => t;
|
|
}
|