Files
natsdotnet/tests/NATS.Server.Tests/Internal/InternalDsParityBatch2Tests.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

92 lines
2.7 KiB
C#

using System.Text;
using NATS.Server.Internal.Avl;
using NATS.Server.Internal.Gsl;
using NATS.Server.Internal.SubjectTree;
using NATS.Server.Internal.SysMem;
using NATS.Server.Internal.TimeHashWheel;
namespace NATS.Server.Tests.Internal;
public class InternalDsParityBatch2Tests
{
[Fact]
public void SubjectTreeHelper_IntersectGSL_matches_interested_subjects_once()
{
var tree = new SubjectTree<int>();
tree.Insert("foo.bar"u8.ToArray(), 1);
tree.Insert("foo.baz"u8.ToArray(), 2);
tree.Insert("other.subject"u8.ToArray(), 3);
var sublist = new GenericSubjectList<int>();
sublist.Insert("foo.*", 1);
sublist.Insert("foo.bar", 2); // overlap should not duplicate callback for same subject
var seen = new HashSet<string>(StringComparer.Ordinal);
SubjectTreeHelper.IntersectGSL(tree, sublist, (subject, _) =>
{
seen.Add(Encoding.UTF8.GetString(subject));
});
seen.Count.ShouldBe(2);
seen.ShouldContain("foo.bar");
seen.ShouldContain("foo.baz");
}
[Fact]
public void SubjectTree_Dump_outputs_node_and_leaf_structure()
{
var tree = new SubjectTree<int>();
tree.Insert("foo.bar"u8.ToArray(), 1);
tree.Insert("foo.baz"u8.ToArray(), 2);
using var sw = new StringWriter();
tree.Dump(sw);
var dump = sw.ToString();
dump.ShouldContain("NODE");
dump.ShouldContain("LEAF");
dump.ShouldContain("Prefix:");
}
[Fact]
public void SequenceSet_Encode_supports_destination_buffer_reuse()
{
var set = new SequenceSet();
set.Insert(1);
set.Insert(65);
set.Insert(1024);
var buffer = new byte[set.EncodeLength() + 32];
var written = set.Encode(buffer);
written.ShouldBe(set.EncodeLength());
var (decoded, bytesRead) = SequenceSet.Decode(buffer.AsSpan(0, written));
bytesRead.ShouldBe(written);
decoded.Exists(1).ShouldBeTrue();
decoded.Exists(65).ShouldBeTrue();
decoded.Exists(1024).ShouldBeTrue();
}
[Fact]
public void HashWheelEntry_struct_exposes_sequence_and_expiration()
{
var entry = new HashWheel.HashWheelEntry(42, 99);
entry.Sequence.ShouldBe((ulong)42);
entry.Expires.ShouldBe(99);
}
[Fact]
public void SystemMemory_returns_positive_memory_value()
{
SystemMemory.Memory().ShouldBeGreaterThan(0);
}
[Fact]
public void SimpleSubjectList_works_with_empty_marker_values()
{
var list = new SimpleSubjectList();
list.Insert("foo.bar", new SimpleSublistValue());
list.HasInterest("foo.bar").ShouldBeTrue();
}
}