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
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using NATS.Server.Monitoring;
|
||||
|
||||
namespace NATS.Server.Tests.Internal;
|
||||
|
||||
public class InternalDsPeriodicSamplerParityTests
|
||||
{
|
||||
[Fact]
|
||||
[SlopwatchSuppress("SW004", "Test must observe a real 1-second CPU sampling timer tick; wall-clock elapsed time is the observable under test")]
|
||||
public async Task VarzHandler_uses_periodic_background_cpu_sampler()
|
||||
{
|
||||
var options = new NatsOptions { Host = "127.0.0.1", Port = 0 };
|
||||
var server = new NatsServer(options, NullLoggerFactory.Instance);
|
||||
using var cts = new CancellationTokenSource();
|
||||
_ = server.StartAsync(cts.Token);
|
||||
await server.WaitForReadyAsync();
|
||||
|
||||
try
|
||||
{
|
||||
using var handler = new VarzHandler(server, options, NullLoggerFactory.Instance);
|
||||
var field = typeof(VarzHandler).GetField("_lastCpuSampleTime", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
field.ShouldNotBeNull();
|
||||
|
||||
var before = (DateTime)field!.GetValue(handler)!;
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(1200));
|
||||
var after = (DateTime)field.GetValue(handler)!;
|
||||
|
||||
after.ShouldBeGreaterThan(before);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await cts.CancelAsync();
|
||||
server.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user