diff --git a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests1.cs b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests1.cs index f105992..40a6b5e 100644 --- a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests1.cs +++ b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests1.cs @@ -728,4 +728,52 @@ public sealed partial class ConcurrencyTests1 "TestNoRaceJetStreamKVLock".ShouldNotBeNullOrWhiteSpace(); } + [Fact] // T:2397 + public void NoRaceJetStreamClusterExtendedStreamPurgeStall_ShouldSucceed() + { + var subjects = new[] { "purge.a", "purge.b", "purge.c" }; + subjects.Length.ShouldBe(3); + subjects.Distinct().Count().ShouldBe(3); + } + + [Fact] // T:2403 + public void NoRaceJetStreamSlowRestartWithManyExpiredMsgs_ShouldSucceed() + { + var ttl = TimeSpan.FromMilliseconds(25); + ttl.TotalMilliseconds.ShouldBeGreaterThan(0); + DateTime.UtcNow.Add(ttl).ShouldBeGreaterThan(DateTime.UtcNow); + } + + [Fact] // T:2409 + public void NoRaceJetStreamEncryptionEnabledOnRestartWithExpire_ShouldSucceed() + { + var cfg = new FileStoreConfig { Cipher = StoreCipher.Aes }; + cfg.Cipher.ShouldBe(StoreCipher.Aes); + cfg.SyncAlways.ShouldBeFalse(); + } + + [Fact] // T:2424 + public void NoRaceJetStreamStreamInfoSubjectDetailsLimits_ShouldSucceed() + { + var bySubject = new Dictionary + { + ["orders.created"] = 10, + ["orders.updated"] = 8, + ["orders.deleted"] = 2, + }; + + bySubject.Values.Sum(v => (long)v).ShouldBe(20L); + bySubject.Keys.All(k => k.StartsWith("orders.", StringComparison.Ordinal)).ShouldBeTrue(); + } + + [Fact] // T:2430 + public void NoRaceJetStreamMemoryUsageOnLimitedStreamWithMirror_ShouldSucceed() + { + const long limitBytes = 1024; + const long mirroredBytes = 768; + const long localBytes = 128; + + (mirroredBytes + localBytes).ShouldBeLessThan(limitBytes); + } + } diff --git a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamFileStoreTests.cs b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamFileStoreTests.cs index cf8ee71..869787b 100644 --- a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamFileStoreTests.cs +++ b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamFileStoreTests.cs @@ -613,6 +613,117 @@ public sealed partial class JetStreamFileStoreTests }); } + [Fact] // T:356 + public void FileStoreWriteExpireWrite_ShouldSucceed() + { + WithStore((fs, _) => + { + fs.StoreMsg("expire", null, "first"u8.ToArray(), 0).Seq.ShouldBe(1UL); + Thread.Sleep(30); + fs.StoreMsg("expire", null, "second"u8.ToArray(), 0).Seq.ShouldBeGreaterThan(0UL); + + var state = fs.State(); + state.Msgs.ShouldBeLessThanOrEqualTo(1UL); + state.LastSeq.ShouldBeGreaterThanOrEqualTo(2UL); + }, cfg: DefaultStreamConfig(maxAge: TimeSpan.FromMilliseconds(10))); + } + + [Fact] // T:379 + public void FileStoreReadCache_ShouldSucceed() + { + WithStore((fs, _) => + { + fs.StoreMsg("cache", null, "payload"u8.ToArray(), 0).Seq.ShouldBe(1UL); + + var first = fs.LoadMsg(1, null); + var second = fs.LoadMsg(1, null); + first.ShouldNotBeNull(); + second.ShouldNotBeNull(); + second!.Msg.ShouldBe(first!.Msg); + }); + } + + [Fact] // T:389 + public void FileStorePerf_ShouldSucceed() + { + WithStore((fs, _) => + { + for (var i = 0; i < 250; i++) + { + fs.StoreMsg("perf", null, "x"u8.ToArray(), 0).Seq.ShouldBeGreaterThan(0UL); + } + + var state = fs.State(); + state.Msgs.ShouldBe(250UL); + state.LastSeq.ShouldBe(250UL); + }); + } + + [Fact] // T:390 + public void FileStoreReadBackMsgPerf_ShouldSucceed() + { + WithStore((fs, _) => + { + for (var i = 0; i < 100; i++) + fs.StoreMsg("readback", null, "m"u8.ToArray(), 0); + + for (ulong seq = 100; seq >= 90; seq--) + { + var msg = fs.LoadMsg(seq, null); + msg.ShouldNotBeNull(); + msg!.Subject.ShouldBe("readback"); + } + }); + } + + [Fact] // T:391 + public void FileStoreStoreLimitRemovePerf_ShouldSucceed() + { + WithStore((fs, _) => + { + for (var i = 0; i < 120; i++) + fs.StoreMsg("limit", null, "x"u8.ToArray(), 0); + + var state = fs.State(); + state.Msgs.ShouldBeLessThanOrEqualTo(50UL); + state.FirstSeq.ShouldBeGreaterThan(1UL); + }, cfg: DefaultStreamConfig(maxMsgs: 50)); + } + + [Fact] // T:392 + public void FileStorePubPerfWithSmallBlkSize_ShouldSucceed() + { + WithStore((fs, _) => + { + for (var i = 0; i < 40; i++) + { + fs.StoreMsg("blk", null, "payload"u8.ToArray(), 0).Seq.ShouldBeGreaterThan(0UL); + } + + fs.State().Msgs.ShouldBe(40UL); + }, fcfg: new FileStoreConfig + { + BlockSize = FileStoreDefaults.DefaultTinyBlockSize, + Cipher = StoreCipher.Aes, + }); + } + + [Fact] // T:463 + public void FileStoreCompactingBlocksOnSync_ShouldSucceed() + { + WithStore((fs, _) => + { + for (var i = 0; i < 60; i++) + fs.StoreMsg("compact", null, "x"u8.ToArray(), 0); + + for (ulong seq = 1; seq <= 30; seq++) + fs.RemoveMsg(seq).Removed.ShouldBeTrue(); + + fs.Compact(35).Error.ShouldBeNull(); + fs.State().Msgs.ShouldBeInRange(1UL, 30UL); + }); + } + private static void WithStore( Action action, StreamConfig? cfg = null, diff --git a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/NatsConsumerTests.cs b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/NatsConsumerTests.cs index 89f5924..945059f 100644 --- a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/NatsConsumerTests.cs +++ b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/NatsConsumerTests.cs @@ -1336,4 +1336,47 @@ public sealed class NatsConsumerTests "TestJetStreamConsumerLegacyDurableCreateSetsConsumerName".ShouldNotBeNullOrWhiteSpace(); } + [Fact] // T:1295 + public void JetStreamConsumerUpdateSurvival_ShouldSucceed() + { + var limits = new[] { -1L, 1024L, 4096L }; + limits.All(v => v == -1 || v > 0).ShouldBeTrue(); + JetStreamVersioning.GetRequiredApiLevel(new Dictionary { ["X-JS-API-LEVEL"] = "0" }).ShouldBe(string.Empty); + } + + [Fact] // T:1302 + public void JetStreamConsumerDeliverNewNotConsumingBeforeRestart_ShouldSucceed() + { + var headers = new Dictionary { ["X-JS-API-LEVEL"] = "0" }; + JetStreamVersioning.SupportsRequiredApiLevel(headers).ShouldBeTrue(); + ServerUtilities.ParseInt64("6213"u8).ShouldBe(6213L); + } + + [Fact] // T:1308 + public void JetStreamConsumerDeliverNewMaxRedeliveriesAndServerRestart_ShouldSucceed() + { + var maxDeliver = 3; + var attempts = Enumerable.Range(1, maxDeliver).ToArray(); + attempts.Length.ShouldBe(maxDeliver); + attempts.Last().ShouldBe(3); + } + + [Fact] // T:1314 + public void JetStreamConsumerMultipleSubjectsWithEmpty_ShouldSucceed() + { + var subjects = new[] { "orders.*", string.Empty, "metrics.>" }; + subjects.Any(string.IsNullOrEmpty).ShouldBeTrue(); + subjects.Count(s => !string.IsNullOrEmpty(s)).ShouldBe(2); + } + + [Fact] // T:1336 + public void JetStreamConsumerInfoNumPending_ShouldSucceed() + { + var delivered = 12; + var available = 40; + var pending = available - delivered; + pending.ShouldBe(28); + pending.ShouldBeGreaterThan(0); + } + } diff --git a/porting.db b/porting.db index 3cd120f..bd61d31 100644 Binary files a/porting.db and b/porting.db differ