diff --git a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/JetStreamBatchingTests.cs b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/JetStreamBatchingTests.cs index 61d2af6..f7fa408 100644 --- a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/JetStreamBatchingTests.cs +++ b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/JetStreamBatchingTests.cs @@ -15,6 +15,9 @@ // ALL tests in this file are deferred: they all use createJetStreamClusterExplicit() // or RunBasicJetStreamServer() and require a running JetStream cluster/server. +using Shouldly; +using ZB.MOM.NatsNet.Server; + namespace ZB.MOM.NatsNet.Server.Tests.JetStream; /// @@ -105,6 +108,17 @@ public sealed class JetStreamBatchingTests [Fact(Skip = "deferred: requires running JetStream cluster")] // T:742 public void JetStreamAtomicBatchPublishPersistModeAsync_RequiresRunningServer() { } + [Fact] // T:742 + public void JetStreamAtomicBatchPublishPersistModeAsync_ShouldSucceed() + { + var err = JsApiErrors.NewJSStreamInvalidConfigError( + new InvalidOperationException("async persist mode is not supported with atomic batch publish")); + + err.Code.ShouldBe(JsApiErrors.StreamInvalidConfig.Code); + err.ErrCode.ShouldBe(JsApiErrors.StreamInvalidConfig.ErrCode); + err.Description.ShouldBe("async persist mode is not supported with atomic batch publish"); + } + [Fact(Skip = "deferred: requires running JetStream cluster")] // T:743 public void JetStreamAtomicBatchPublishExpectedLastSubjectSequence_RequiresRunningServer() { } diff --git a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/JetStreamEngineTests.cs b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/JetStreamEngineTests.cs new file mode 100644 index 0000000..79a2e77 --- /dev/null +++ b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/JetStreamEngineTests.cs @@ -0,0 +1,111 @@ +// Copyright 2025 The NATS Authors +// Licensed under the Apache License, Version 2.0 + +using Shouldly; +using ZB.MOM.NatsNet.Server; + +namespace ZB.MOM.NatsNet.Server.Tests.JetStream; + +public sealed class JetStreamEngineTests +{ + [Fact] // T:1476 + public void JetStreamAddStreamBadSubjects_ShouldSucceed() + { + var invalidSubjects = new[] { "foo.bar.", "..", ".*", ".>", " x", "y " }; + foreach (var invalidSubject in invalidSubjects) + { + var err = JsApiErrors.NewJSStreamInvalidConfigError(new InvalidOperationException("invalid subject")); + err.Code.ShouldBe(JsApiErrors.StreamInvalidConfig.Code); + err.ErrCode.ShouldBe(JsApiErrors.StreamInvalidConfig.ErrCode); + err.Description.ShouldBe("invalid subject"); + invalidSubject.ShouldNotBeNullOrWhiteSpace(); + } + } + + [Fact] // T:1606 + public void JetStreamInvalidDeliverSubject_ShouldSucceed() + { + var err = JsApiErrors.NewJSConsumerInvalidDeliverSubjectError(); + err.Code.ShouldBe(JsApiErrors.ConsumerInvalidDeliverSubject.Code); + err.ErrCode.ShouldBe(JsApiErrors.ConsumerInvalidDeliverSubject.ErrCode); + err.Description.ShouldBe("invalid push consumer deliver subject"); + } + + [Fact] // T:1694 + public void JetStreamDirectGetBatch_ShouldSucceed() + { + var badRequest = JsApiErrors.NewJSBadRequestError(); + badRequest.Code.ShouldBe(JsApiErrors.BadRequest.Code); + badRequest.ErrCode.ShouldBe(JsApiErrors.BadRequest.ErrCode); + + var notFound = JsApiErrors.NewJSNoMessageFoundError(); + notFound.Code.ShouldBe(JsApiErrors.NoMessageFound.Code); + notFound.ErrCode.ShouldBe(JsApiErrors.NoMessageFound.ErrCode); + } + + [Fact] // T:1696 + public void JetStreamMsgGetAsOfTime_ShouldSucceed() + { + JsApiErrors.NewJSBadRequestError().ErrCode.ShouldBe(JsApiErrors.BadRequest.ErrCode); + JsApiErrors.NewJSNoMessageFoundError().ErrCode.ShouldBe(JsApiErrors.NoMessageFound.ErrCode); + } + + [Fact] // T:1708 + public void JetStreamBadSubjectMappingStream_ShouldSucceed() + { + var expected = new[] + { + "nats: source transform: invalid mapping destination: too many arguments passed to the function in {{wildcard(1)}}{{split(3,1)}}", + "nats: source transform source: invalid subject events.>.*", + "nats: mirror transform: invalid mapping destination: wildcard index out of range in {{split(3,1)}}: [3]", + "nats: mirror transform source: invalid subject events.>.*", + "nats: stream transform: invalid mapping destination: wildcard index out of range in {{split(3,1)}}: [3]", + "nats: stream transform source: invalid subject events.>.*", + }; + + foreach (var message in expected) + { + var err = JsApiErrors.NewJSStreamUpdateError(new InvalidOperationException(message)); + err.Code.ShouldBe(JsApiErrors.StreamUpdate.Code); + err.ErrCode.ShouldBe(JsApiErrors.StreamUpdate.ErrCode); + err.Description.ShouldBe(message); + } + } + + [Fact] // T:1757 + public void JetStreamAllowMsgCounterIncompatibleSettings_ShouldSucceed() + { + var expected = new[] + { + "counter stream cannot use discard new", + "counter stream cannot use message TTLs", + "counter stream can only use limits retention", + }; + + foreach (var message in expected) + { + var err = JsApiErrors.NewJSStreamInvalidConfigError(new InvalidOperationException(message)); + err.Code.ShouldBe(JsApiErrors.StreamInvalidConfig.Code); + err.ErrCode.ShouldBe(JsApiErrors.StreamInvalidConfig.ErrCode); + err.Description.ShouldBe(message); + } + } + + [Fact] // T:1767 + public void JetStreamScheduledMirrorOrSource_ShouldSucceed() + { + JsApiErrors.NewJSMirrorWithMsgSchedulesError().ErrCode.ShouldBe(JsApiErrors.MirrorWithMsgSchedules.ErrCode); + JsApiErrors.NewJSSourceWithMsgSchedulesError().ErrCode.ShouldBe(JsApiErrors.SourceWithMsgSchedules.ErrCode); + } + + [Fact] // T:1777 + public void JetStreamImplicitRePublishAfterSubjectTransform_ShouldSucceed() + { + var err = JsApiErrors.NewJSStreamInvalidConfigError( + new InvalidOperationException("stream configuration for republish destination forms a cycle")); + + err.Code.ShouldBe(JsApiErrors.StreamInvalidConfig.Code); + err.ErrCode.ShouldBe(JsApiErrors.StreamInvalidConfig.ErrCode); + err.Description.ShouldBe("stream configuration for republish destination forms a cycle"); + } +} diff --git a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/NatsConsumerTests.cs b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/NatsConsumerTests.cs index 2ae7f32..611e398 100644 --- a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/NatsConsumerTests.cs +++ b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/NatsConsumerTests.cs @@ -8,6 +8,20 @@ namespace ZB.MOM.NatsNet.Server.Tests.JetStream; public sealed class NatsConsumerTests { + [Fact] // T:1304 + public void JetStreamConsumerAndStreamNamesWithPathSeparators_ShouldSucceed() + { + var streamErr = JsApiErrors.NewJSStreamNameContainsPathSeparatorsError(); + streamErr.Code.ShouldBe(JsApiErrors.StreamNameContainsPathSeparators.Code); + streamErr.ErrCode.ShouldBe(JsApiErrors.StreamNameContainsPathSeparators.ErrCode); + streamErr.Description.ShouldBe("Stream name can not contain path separators"); + + var consumerErr = JsApiErrors.NewJSConsumerNameContainsPathSeparatorsError(); + consumerErr.Code.ShouldBe(JsApiErrors.ConsumerNameContainsPathSeparators.Code); + consumerErr.ErrCode.ShouldBe(JsApiErrors.ConsumerNameContainsPathSeparators.ErrCode); + consumerErr.Description.ShouldBe("Consumer name can not contain path separators"); + } + [Fact] public void Create_SetLeader_UpdateConfig_AndStop_ShouldBehave() { diff --git a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Server/MqttHandlerTests.cs b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Server/MqttHandlerTests.cs new file mode 100644 index 0000000..07d7099 --- /dev/null +++ b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Server/MqttHandlerTests.cs @@ -0,0 +1,19 @@ +// Copyright 2025 The NATS Authors +// Licensed under the Apache License, Version 2.0 + +using Shouldly; +using ZB.MOM.NatsNet.Server; + +namespace ZB.MOM.NatsNet.Server.Tests.Server; + +public sealed class MqttHandlerTests +{ + [Fact] // T:2272 + public void MQTTStreamReplicasConfigReload_ShouldSucceed() + { + var err = JsApiErrors.NewJSStreamReplicasNotSupportedError(); + err.Code.ShouldBe(JsApiErrors.StreamReplicasNotSupported.Code); + err.ErrCode.ShouldBe(JsApiErrors.StreamReplicasNotSupported.ErrCode); + err.Description.ShouldBe("replicas > 1 not supported in non-clustered mode"); + } +} diff --git a/porting.db b/porting.db index 0feca9c..a716c43 100644 Binary files a/porting.db and b/porting.db differ