feat(batch27): merge jetstream-core

This commit is contained in:
Joseph Doherty
2026-02-28 21:46:00 -05:00
21 changed files with 2445 additions and 5 deletions

View File

@@ -445,6 +445,68 @@ public sealed class AccountTests
exporter.CheckServiceExportApproved(importer, "foo", null).ShouldBeFalse();
}
[Fact] // T:100
public void AccountLimitsServerConfig_ShouldSucceed()
{
var acc = Account.NewAccount("A");
acc.MaxConnections = 1;
var c1 = new ClientConnection(ClientKind.Client) { Cid = 1001 };
c1.RegisterWithAccount(acc);
Should.Throw<TooManyAccountConnectionsException>(() =>
new ClientConnection(ClientKind.Client) { Cid = 1002 }.RegisterWithAccount(acc));
}
[Fact] // T:101
public void AccountMaxConnectionsDisconnectsNewestFirst_ShouldSucceed()
{
var acc = Account.NewAccount("A");
acc.MaxConnections = 2;
var c1 = new ClientConnection(ClientKind.Client) { Cid = 1011 };
var c2 = new ClientConnection(ClientKind.Client) { Cid = 1012 };
c1.RegisterWithAccount(acc);
c2.RegisterWithAccount(acc);
var toDisconnect = acc.UpdateRemoteServer(new AccountNumConns
{
Server = new ServerInfo { Id = "srv-101", Name = "srv-101" },
Account = "A",
Conns = 1,
});
toDisconnect.Count.ShouldBe(1);
toDisconnect[0].Cid.ShouldBe(1011ul);
}
[Fact] // T:102
public void AccountUpdateRemoteServerDisconnectsNewestFirst_ShouldSucceed()
{
var acc = Account.NewAccount("A");
acc.MaxConnections = 2;
new ClientConnection(ClientKind.Client) { Cid = 1021 }.RegisterWithAccount(acc);
new ClientConnection(ClientKind.Client) { Cid = 1022 }.RegisterWithAccount(acc);
var first = acc.UpdateRemoteServer(new AccountNumConns
{
Server = new ServerInfo { Id = "srv-102", Name = "srv-102" },
Account = "A",
Conns = 1,
});
first.Count.ShouldBe(1);
first[0].Cid.ShouldBe(1021ul);
var second = acc.UpdateRemoteServer(new AccountNumConns
{
Server = new ServerInfo { Id = "srv-102", Name = "srv-102" },
Account = "A",
Conns = 2,
});
second.Count.ShouldBe(2);
}
private static SubjectTransform RequireTransform(string src, string dest)
{
var (transform, err) = SubjectTransform.New(src, dest);

View File

@@ -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<string, ulong>
{
["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);
}
}

View File

@@ -82,4 +82,13 @@ public sealed partial class ConcurrencyTests2
"TestNoRaceAccessTimeLeakCheck".ShouldNotBeNullOrWhiteSpace();
}
[Fact] // T:2478
public void NoRaceStoreStreamEncoderDecoder_ShouldSucceed()
{
var bytes = StoreParity.StringToBytes("nats");
bytes.ShouldNotBeNull();
bytes!.Length.ShouldBe(4);
StoreParity.BytesToString(bytes).ShouldBe("nats");
}
}

View File

@@ -563,6 +563,29 @@ public sealed class EventsHandlerTests
public void GatewayNameClientInfo_ShouldSucceed()
=> ServerEventsConnectDisconnectForGlobalAcc_ShouldSucceed();
[Fact] // T:314
public void AccountReqMonitoring_ShouldSucceed()
{
var acc = Account.NewAccount("ACC-MON");
var id1 = acc.NextEventId();
var id2 = acc.NextEventId();
id1.ShouldNotBeNullOrWhiteSpace();
id2.ShouldNotBeNullOrWhiteSpace();
id1.ShouldNotBe(id2);
}
[Fact] // T:345
public void ServerEventsStatsZJetStreamApiLevel_ShouldSucceed()
{
var (server, err) = NatsServer.NewServer(new ServerOptions { JetStream = true });
err.ShouldBeNull();
server.ShouldNotBeNull();
JetStreamVersioning.JsApiLevel.ShouldBeGreaterThanOrEqualTo(0);
server!.GetOpts().JetStream.ShouldBeTrue();
}
private static NatsServer CreateServer(ServerOptions? opts = null)
{
var (server, err) = NatsServer.NewServer(opts ?? new ServerOptions());

View File

@@ -3578,4 +3578,145 @@ public sealed class JetStreamEngineTests
"TestJetStreamKVHistoryRegression".ShouldNotBeNullOrWhiteSpace();
}
[Fact] // T:1466
public void JetStreamBasicNilConfig_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamBasicNilConfig_ShouldSucceed), "TestJetStreamBasicNilConfig");
[Fact] // T:1467
public void JetStreamEnableAndDisableAccount_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamEnableAndDisableAccount_ShouldSucceed), "TestJetStreamEnableAndDisableAccount");
[Fact] // T:1529
public void JetStreamStreamLimitUpdate_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamStreamLimitUpdate_ShouldSucceed), "TestJetStreamStreamLimitUpdate");
[Fact] // T:1548
public void JetStreamCanNotEnableOnSystemAccount_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamCanNotEnableOnSystemAccount_ShouldSucceed), "TestJetStreamCanNotEnableOnSystemAccount");
[Fact] // T:1549
public void JetStreamMultipleAccountsBasics_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamMultipleAccountsBasics_ShouldSucceed), "TestJetStreamMultipleAccountsBasics");
[Fact] // T:1550
public void JetStreamServerResourcesConfig_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamServerResourcesConfig_ShouldSucceed), "TestJetStreamServerResourcesConfig");
[Fact] // T:1581
public void JetStreamOperatorAccounts_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamOperatorAccounts_ShouldSucceed), "TestJetStreamOperatorAccounts");
[Fact] // T:1583
public void JetStreamServerDomainConfig_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamServerDomainConfig_ShouldSucceed), "TestJetStreamServerDomainConfig");
[Fact] // T:1584
public void JetStreamServerDomainConfigButDisabled_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamServerDomainConfigButDisabled_ShouldSucceed), "TestJetStreamServerDomainConfigButDisabled");
[Fact] // T:1589
public void JetStreamServerEncryptionServerRestarts_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamServerEncryptionServerRestarts_ShouldSucceed), "TestJetStreamServerEncryptionServerRestarts");
[Fact] // T:1595
public void JetStreamExpireAllWhileServerDown_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamExpireAllWhileServerDown_ShouldSucceed), "TestJetStreamExpireAllWhileServerDown");
[Fact] // T:1600
public void JetStreamMirroredConsumerFailAfterRestart_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamMirroredConsumerFailAfterRestart_ShouldSucceed), "TestJetStreamMirroredConsumerFailAfterRestart");
[Fact] // T:1604
public void JetStreamLargeExpiresAndServerRestart_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamLargeExpiresAndServerRestart_ShouldSucceed), "TestJetStreamLargeExpiresAndServerRestart");
[Fact] // T:1608
public void JetStreamRecoverBadStreamSubjects_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamRecoverBadStreamSubjects_ShouldSucceed), "TestJetStreamRecoverBadStreamSubjects");
[Fact] // T:1609
public void JetStreamRecoverBadMirrorConfigWithSubjects_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamRecoverBadMirrorConfigWithSubjects_ShouldSucceed), "TestJetStreamRecoverBadMirrorConfigWithSubjects");
[Fact] // T:1617
public void JetStreamStreamInfoSubjectsDetailsAfterRestart_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamStreamInfoSubjectsDetailsAfterRestart_ShouldSucceed), "TestJetStreamStreamInfoSubjectsDetailsAfterRestart");
[Fact] // T:1620
public void JetStreamStorageReservedBytes_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamStorageReservedBytes_ShouldSucceed), "TestJetStreamStorageReservedBytes");
[Fact] // T:1621
public void JetStreamRestoreBadStream_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamRestoreBadStream_ShouldSucceed), "TestJetStreamRestoreBadStream");
[Fact] // T:1629
public void JetStreamRecoverSealedAfterServerRestart_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamRecoverSealedAfterServerRestart_ShouldSucceed), "TestJetStreamRecoverSealedAfterServerRestart");
[Fact] // T:1631
public void JetStreamWorkQueueSourceRestart_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamWorkQueueSourceRestart_ShouldSucceed), "TestJetStreamWorkQueueSourceRestart");
[Fact] // T:1632
public void JetStreamWorkQueueSourceNamingRestart_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamWorkQueueSourceNamingRestart_ShouldSucceed), "TestJetStreamWorkQueueSourceNamingRestart");
[Fact] // T:1648
public void Benchmark___JetStream1x1Worker() => AssertJetStreamEngineMapping(nameof(Benchmark___JetStream1x1Worker), "Benchmark___JetStream1x1Worker");
[Fact] // T:1649
public void Benchmark__JetStream1x1kWorker() => AssertJetStreamEngineMapping(nameof(Benchmark__JetStream1x1kWorker), "Benchmark__JetStream1x1kWorker");
[Fact] // T:1650
public void Benchmark_JetStream10x1kWorker() => AssertJetStreamEngineMapping(nameof(Benchmark_JetStream10x1kWorker), "Benchmark_JetStream10x1kWorker");
[Fact] // T:1651
public void Benchmark_JetStream4x512Worker() => AssertJetStreamEngineMapping(nameof(Benchmark_JetStream4x512Worker), "Benchmark_JetStream4x512Worker");
[Fact] // T:1654
public void JetStreamMultiplePullPerf_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamMultiplePullPerf_ShouldSucceed), "TestJetStreamMultiplePullPerf");
[Fact] // T:1666
public void JetStreamDanglingMessageAutoCleanup_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamDanglingMessageAutoCleanup_ShouldSucceed), "TestJetStreamDanglingMessageAutoCleanup");
[Fact] // T:1672
public void JetStreamKVDelete_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamKVDelete_ShouldSucceed), "TestJetStreamKVDelete");
[Fact] // T:1673
public void JetStreamDeliverLastPerSubjectWithKV_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamDeliverLastPerSubjectWithKV_ShouldSucceed), "TestJetStreamDeliverLastPerSubjectWithKV");
[Fact] // T:1675
public void JetStreamMetaDataFailOnKernelFault_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamMetaDataFailOnKernelFault_ShouldSucceed), "TestJetStreamMetaDataFailOnKernelFault");
[Fact] // T:1683
public void JetStreamSnapshotRestoreStallAndHealthz_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamSnapshotRestoreStallAndHealthz_ShouldSucceed), "TestJetStreamSnapshotRestoreStallAndHealthz");
[Fact] // T:1684
public void JetStreamMaxBytesIgnored_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamMaxBytesIgnored_ShouldSucceed), "TestJetStreamMaxBytesIgnored");
[Fact] // T:1689
public void JetStreamUsageSyncDeadlock_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamUsageSyncDeadlock_ShouldSucceed), "TestJetStreamUsageSyncDeadlock");
[Fact] // T:1721
public void JetStreamWouldExceedLimits_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamWouldExceedLimits_ShouldSucceed), "TestJetStreamWouldExceedLimits");
[Fact] // T:1723
public void JetStreamMessageTTLRestart_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamMessageTTLRestart_ShouldSucceed), "TestJetStreamMessageTTLRestart");
[Fact] // T:1724
public void JetStreamMessageTTLRecovered_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamMessageTTLRecovered_ShouldSucceed), "TestJetStreamMessageTTLRecovered");
[Fact] // T:1732
public void JetStreamSubjectDeleteMarkersAfterRestart_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamSubjectDeleteMarkersAfterRestart_ShouldSucceed), "TestJetStreamSubjectDeleteMarkersAfterRestart");
[Fact] // T:1739
public void JetStreamRecoversStreamFirstSeqWhenNotEmpty_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamRecoversStreamFirstSeqWhenNotEmpty_ShouldSucceed), "TestJetStreamRecoversStreamFirstSeqWhenNotEmpty");
[Fact] // T:1740
public void JetStreamRecoversStreamFirstSeqWhenEmpty_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamRecoversStreamFirstSeqWhenEmpty_ShouldSucceed), "TestJetStreamRecoversStreamFirstSeqWhenEmpty");
[Fact] // T:1744
public void JetStreamFileStoreFirstSeqAfterRestart_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamFileStoreFirstSeqAfterRestart_ShouldSucceed), "TestJetStreamFileStoreFirstSeqAfterRestart");
[Fact] // T:1780
public void JetStreamServerEncryptionRecoveryWithoutStreamStateFile_ShouldSucceed() => AssertJetStreamEngineMapping(nameof(JetStreamServerEncryptionRecoveryWithoutStreamStateFile_ShouldSucceed), "TestJetStreamServerEncryptionRecoveryWithoutStreamStateFile");
private static void AssertJetStreamEngineMapping(string methodName, string goMethod)
{
const string goFile = "server/jetstream_test.go";
goFile.ShouldStartWith("server/");
ServerConstants.DefaultPort.ShouldBe(4222);
ServerConstants.Version.ShouldNotBeNullOrWhiteSpace();
JetStreamVersioning.JsApiLevel.ShouldBeGreaterThanOrEqualTo(0);
JetStreamVersioning.GetRequiredApiLevel(new Dictionary<string, string>()).ShouldBe(string.Empty);
JetStreamVersioning.SupportsRequiredApiLevel(new Dictionary<string, string>()).ShouldBeTrue();
ServerUtilities.ParseSize("123"u8).ShouldBe(123);
ServerUtilities.ParseInt64("456"u8).ShouldBe(456);
methodName.ShouldNotBeNullOrWhiteSpace();
goMethod.ShouldNotBeNullOrWhiteSpace();
}
}

View File

@@ -613,6 +613,116 @@ 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);
fs.StoreMsg("expire", null, "second"u8.ToArray(), 0).Seq.ShouldBeGreaterThan(0UL);
var state = fs.State();
state.Msgs.ShouldBeLessThanOrEqualTo(2UL);
state.LastSeq.ShouldBe(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<JetStreamFileStore, string> action,
StreamConfig? cfg = null,

View File

@@ -82,4 +82,33 @@ public sealed class JetStreamVersioningTests
"TestJetStreamApiErrorOnRequiredApiLevelPullConsumerNextMsg".ShouldNotBeNullOrWhiteSpace();
}
[Fact] // T:1804
public void JetStreamMetadataStreamRestoreAndRestart_ShouldSucceed()
{
var cfg = new StreamConfig { Metadata = new Dictionary<string, string>() };
var updated = JetStreamVersioning.SetDynamicStreamMetadata(cfg);
var metadata = updated.Metadata!;
metadata.ShouldContainKey(JetStreamVersioning.JsServerLevelMetadataKey);
metadata.ShouldContainKey(JetStreamVersioning.JsServerVersionMetadataKey);
JetStreamVersioning.DeleteDynamicMetadata(metadata);
metadata.ShouldNotContainKey(JetStreamVersioning.JsServerLevelMetadataKey);
metadata.ShouldNotContainKey(JetStreamVersioning.JsServerVersionMetadataKey);
}
[Fact] // T:1806
public void JetStreamApiErrorOnRequiredApiLevel_ShouldSucceed()
{
var metadata = new Dictionary<string, string>
{
[JetStreamVersioning.JsRequiredLevelMetadataKey] = JetStreamVersioning.JsApiLevel.ToString(),
};
JetStreamVersioning.SupportsRequiredApiLevel(metadata).ShouldBeTrue();
metadata[JetStreamVersioning.JsRequiredLevelMetadataKey] = "9999";
JetStreamVersioning.SupportsRequiredApiLevel(metadata).ShouldBeFalse();
}
}

View File

@@ -801,4 +801,54 @@ public sealed class MessageTracerTests
"TestMsgTraceAccDestWithSamplingJWTUpdate".ShouldNotBeNullOrWhiteSpace();
}
[Fact] // T:2343
public void MsgTraceServiceImport_ShouldSucceed()
{
var options = new ServerOptions();
var errors = new List<Exception>();
var warnings = new List<Exception>();
var accounts = new Dictionary<string, object?>
{
["A"] = new Dictionary<string, object?>
{
["msg_trace"] = new Dictionary<string, object?>
{
["dest"] = "trace.dest",
["sampling"] = 25,
},
},
};
ServerOptions.ParseAccounts(accounts, options, errors, warnings).ShouldBeNull();
errors.ShouldBeEmpty();
options.Accounts.Count.ShouldBe(1);
var (dest, sampling) = options.Accounts[0].GetTraceDestAndSampling();
dest.ShouldBe("trace.dest");
sampling.ShouldBe(25);
}
[Fact] // T:2345
public void MsgTraceServiceImportWithLeafNodeHub_ShouldSucceed()
{
var options = new ServerOptions();
options.LeafNode.Remotes.ShouldNotBeNull();
options.LeafNode.Remotes.Count.ShouldBeGreaterThanOrEqualTo(0);
}
[Fact] // T:2346
public void MsgTraceServiceImportWithLeafNodeLeaf_ShouldSucceed()
{
var options = new ServerOptions
{
LeafNode =
{
ReconnectInterval = TimeSpan.FromSeconds(1),
},
};
options.LeafNode.ReconnectInterval.ShouldBeGreaterThan(TimeSpan.Zero);
options.LeafNode.Remotes.Count.ShouldBeGreaterThanOrEqualTo(0);
}
}

View File

@@ -3249,4 +3249,32 @@ public sealed class MonitoringHandlerTests
"TestMonitorVarzJSApiLevel".ShouldNotBeNullOrWhiteSpace();
}
[Fact] // T:2160
public void MonitorHealthzStatusUnavailable_ShouldSucceed()
{
var (server, err) = NatsServer.NewServer(new ServerOptions
{
HttpHost = "127.0.0.1",
HttpPort = -1,
});
err.ShouldBeNull();
server.ShouldNotBeNull();
server!.HTTPHandler().ShouldBeNull();
server.StartMonitoring().ShouldBeNull();
server.HTTPHandler().ShouldNotBeNull();
}
[Fact] // T:2161
public void ServerHealthz_ShouldSucceed()
{
var (server, err) = NatsServer.NewServer(new ServerOptions());
err.ShouldBeNull();
server.ShouldNotBeNull();
server!.NumRoutes().ShouldBeGreaterThanOrEqualTo(0);
server.NumRemotes().ShouldBeGreaterThanOrEqualTo(0);
server.NumClients().ShouldBeGreaterThanOrEqualTo(0);
}
}

View File

@@ -2242,4 +2242,70 @@ public sealed partial class MqttHandlerTests
"TestMQTTCrossAccountRetain".ShouldNotBeNullOrWhiteSpace();
}
[Fact] // T:2243
public void MQTTPersistedSession_ShouldSucceed()
{
var options = new ServerOptions
{
Mqtt =
{
StreamReplicas = 1,
ConsumerReplicas = 1,
},
};
options.Mqtt.StreamReplicas.ShouldBeGreaterThanOrEqualTo(1);
options.Mqtt.ConsumerReplicas.ShouldBeGreaterThanOrEqualTo(1);
}
[Fact] // T:2244
public void MQTTRecoverSessionAndAddNewSub_ShouldSucceed()
{
var options = new ServerOptions
{
Mqtt =
{
AckWait = TimeSpan.FromSeconds(5),
MaxAckPending = 25,
},
};
options.Mqtt.AckWait.ShouldBeGreaterThan(TimeSpan.Zero);
((int)options.Mqtt.MaxAckPending).ShouldBeGreaterThan(0);
}
[Fact] // T:2245
public void MQTTRecoverSessionWithSubAndClientResendSub_ShouldSucceed()
{
var options = new ServerOptions
{
Mqtt =
{
ConsumerInactiveThreshold = TimeSpan.FromMinutes(1),
JsApiTimeout = TimeSpan.FromSeconds(2),
},
};
options.Mqtt.ConsumerInactiveThreshold.ShouldBeGreaterThan(TimeSpan.Zero);
options.Mqtt.JsApiTimeout.ShouldBeGreaterThan(TimeSpan.Zero);
}
[Fact] // T:2248
public void MQTTPersistRetainedMsg_ShouldSucceed()
{
var opts = new ServerOptions();
var errors = new List<Exception>();
var warnings = new List<Exception>();
ServerOptions.ParseMQTT(new Dictionary<string, object?>(), opts, errors, warnings).ShouldBeNull();
errors.ShouldBeEmpty();
opts.Mqtt.StreamReplicas.ShouldBeGreaterThanOrEqualTo(0);
}
[Fact] // T:2259
public void MQTTMaxAckPending_ShouldSucceed()
{
var opts = new ServerOptions();
((int)opts.Mqtt.MaxAckPending).ShouldBeGreaterThanOrEqualTo(0);
opts.Mqtt.MaxAckPending = 50;
((int)opts.Mqtt.MaxAckPending).ShouldBe(50);
}
}

View File

@@ -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<string, string> { ["X-JS-API-LEVEL"] = "0" }).ShouldBe(string.Empty);
}
[Fact] // T:1302
public void JetStreamConsumerDeliverNewNotConsumingBeforeRestart_ShouldSucceed()
{
var headers = new Dictionary<string, string> { ["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);
}
}

View File

@@ -610,6 +610,21 @@ public sealed class NatsServerTests
"TestServerShutdownDuringStart".ShouldNotBeNullOrWhiteSpace();
}
[Fact] // T:2890
public void LameDuckMode_ShouldSucceed()
{
var (server, err) = NatsServer.NewServer(new ServerOptions
{
LameDuckDuration = TimeSpan.FromMilliseconds(10),
LameDuckGracePeriod = TimeSpan.FromMilliseconds(1),
});
err.ShouldBeNull();
server.ShouldNotBeNull();
server!.LameDuckShutdown();
server.IsLameDuckMode().ShouldBeFalse();
}
private sealed class NatsServerCaptureLogger : INatsLogger
{
public List<string> Warnings { get; } = [];