Files
natsdotnet/tests/NATS.Server.Tests/Protocol/ProtoWireParityTests.cs
Joseph Doherty c30e67a69d Fix E2E test gaps and add comprehensive E2E + parity test suites
- Fix pull consumer fetch: send original stream subject in HMSG (not inbox)
  so NATS client distinguishes data messages from control messages
- Fix MaxAge expiry: add background timer in StreamManager for periodic pruning
- Fix JetStream wire format: Go-compatible anonymous objects with string enums,
  proper offset-based pagination for stream/consumer list APIs
- Add 42 E2E black-box tests (core messaging, auth, TLS, accounts, JetStream)
- Add ~1000 parity tests across all subsystems (gaps closure)
- Update gap inventory docs to reflect implementation status
2026-03-12 14:09:23 -04:00

88 lines
2.8 KiB
C#

using NATS.Server.Protocol;
namespace NATS.Server.Tests.ProtocolParity;
public class ProtoWireParityTests
{
[Fact]
public void ScanField_reads_tag_and_value_size_for_length_delimited_field()
{
// field=2, type=2, len=3, bytes=abc
byte[] bytes = [0x12, 0x03, (byte)'a', (byte)'b', (byte)'c'];
var (number, wireType, size) = ProtoWire.ScanField(bytes);
number.ShouldBe(2);
wireType.ShouldBe(2);
size.ShouldBe(5);
}
[Fact]
public void ScanTag_rejects_invalid_field_numbers()
{
var zeroFieldEx = Should.Throw<ProtoWireException>(() => ProtoWire.ScanTag([0x00]));
zeroFieldEx.Message.ShouldBe(ProtoWire.ErrProtoInvalidFieldNumber);
var tooLargeTag = ProtoWire.EncodeVarint(((ulong)int.MaxValue + 1UL) << 3);
var tooLargeEx = Should.Throw<ProtoWireException>(() => ProtoWire.ScanTag(tooLargeTag));
tooLargeEx.Message.ShouldBe(ProtoWire.ErrProtoInvalidFieldNumber);
}
[Fact]
public void ScanFieldValue_supports_expected_wire_types()
{
ProtoWire.ScanFieldValue(5, [0, 0, 0, 0]).ShouldBe(4);
ProtoWire.ScanFieldValue(1, [0, 0, 0, 0, 0, 0, 0, 0]).ShouldBe(8);
ProtoWire.ScanFieldValue(0, [0x01]).ShouldBe(1);
}
[Fact]
public void ScanFieldValue_rejects_unsupported_wire_type()
{
var ex = Should.Throw<ProtoWireException>(() => ProtoWire.ScanFieldValue(3, [0x00]));
ex.Message.ShouldBe("unsupported type: 3");
}
[Fact]
public void ScanVarint_reports_insufficient_and_overflow_errors()
{
var insufficient = Should.Throw<ProtoWireException>(() => ProtoWire.ScanVarint([0x80]));
insufficient.Message.ShouldBe(ProtoWire.ErrProtoInsufficient);
byte[] overflow = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x02];
var tooLarge = Should.Throw<ProtoWireException>(() => ProtoWire.ScanVarint(overflow));
tooLarge.Message.ShouldBe(ProtoWire.ErrProtoOverflow);
}
[Fact]
public void ScanBytes_reports_insufficient_when_length_prefix_exceeds_payload()
{
var ex = Should.Throw<ProtoWireException>(() => ProtoWire.ScanBytes([0x04, 0x01, 0x02]));
ex.Message.ShouldBe(ProtoWire.ErrProtoInsufficient);
}
[Fact]
public void EncodeVarint_round_trips_values_via_scan_varint()
{
ulong[] values =
[
0UL,
1UL,
127UL,
128UL,
16_383UL,
16_384UL,
(1UL << 32) - 1,
ulong.MaxValue,
];
foreach (var value in values)
{
var encoded = ProtoWire.EncodeVarint(value);
var (decoded, size) = ProtoWire.ScanVarint(encoded);
decoded.ShouldBe(value);
size.ShouldBe(encoded.Length);
}
}
}