task2: implement batch38 group A consumer lifecycle features

This commit is contained in:
Joseph Doherty
2026-03-01 00:11:47 -05:00
parent ad3a1bbb38
commit fce6bd7dca
13 changed files with 725 additions and 3 deletions

View File

@@ -0,0 +1,133 @@
using System.Text.Json;
using Shouldly;
using ZB.MOM.NatsNet.Server;
namespace ZB.MOM.NatsNet.Server.Tests.JetStream;
public sealed class ConsumerPoliciesTests
{
[Fact]
public void ConsumerAction_StringAndJsonParity_ShouldMatchGo()
{
ConsumerAction.CreateOrUpdate.String().ShouldBe("\"create_or_update\"");
ConsumerAction.Create.String().ShouldBe("\"create\"");
ConsumerAction.Update.String().ShouldBe("\"update\"");
JsonSerializer.Serialize(ConsumerAction.Create).ShouldBe("\"create\"");
JsonSerializer.Deserialize<ConsumerAction>("\"update\"").ShouldBe(ConsumerAction.Update);
Should.Throw<JsonException>(() => JsonSerializer.Deserialize<ConsumerAction>("\"bogus\""));
}
[Fact]
public void PriorityPolicy_StringAndJsonParity_ShouldMatchGo()
{
PriorityPolicy.PriorityNone.String().ShouldBe("\"none\"");
PriorityPolicy.PriorityOverflow.String().ShouldBe("\"overflow\"");
PriorityPolicy.PriorityPinnedClient.String().ShouldBe("\"pinned_client\"");
PriorityPolicy.PriorityPrioritized.String().ShouldBe("\"prioritized\"");
JsonSerializer.Serialize(PriorityPolicy.PriorityPinnedClient).ShouldBe("\"pinned_client\"");
JsonSerializer.Deserialize<PriorityPolicy>("\"prioritized\"").ShouldBe(PriorityPolicy.PriorityPrioritized);
Should.Throw<JsonException>(() => JsonSerializer.Deserialize<PriorityPolicy>("\"none-ish\""));
}
[Fact]
public void ConsumerPolicies_StringParity_ShouldMatchGo()
{
DeliverPolicy.DeliverByStartSequence.String().ShouldBe("by_start_sequence");
AckPolicy.AckExplicit.String().ShouldBe("explicit");
ReplayPolicy.ReplayInstant.String().ShouldBe("instant");
}
[Fact]
public void SubjectTokens_Subjects_RemovesEmptyValues()
{
var subjects = SubjectTokens.Subjects(new[] { "foo.*", string.Empty, " ", "bar.>" });
subjects.ShouldBe(["foo.*", "bar.>"]);
}
[Fact]
public void SetConsumerConfigDefaults_InvalidNegativesInPedanticMode_ReturnsError()
{
var cfg = new ConsumerConfig { MaxDeliver = -2 };
var streamCfg = new StreamConfig { Name = "ORDERS", Replicas = 3 };
var err = NatsConsumer.SetConsumerConfigDefaults(cfg, streamCfg, null, pedantic: true);
err.ShouldNotBeNull();
cfg.MaxDeliver.ShouldBe(-2);
}
[Fact]
public void SetConsumerConfigDefaults_AppliesGoDefaults_ShouldPopulateExpectedValues()
{
var cfg = new ConsumerConfig
{
Durable = "D",
MaxDeliver = 0,
AckPolicy = AckPolicy.AckExplicit,
Replicas = 0,
};
var streamCfg = new StreamConfig { Name = "ORDERS", Replicas = 3 };
var limits = new JetStreamAccountLimits { MaxAckPending = 2500 };
var err = NatsConsumer.SetConsumerConfigDefaults(cfg, streamCfg, limits, pedantic: false);
err.ShouldBeNull();
cfg.MaxDeliver.ShouldBe(-1);
cfg.AckWait.ShouldBe(TimeSpan.FromSeconds(30));
cfg.MaxAckPending.ShouldBe(2500);
cfg.Replicas.ShouldBe(3);
}
[Fact]
public void CheckConsumerCfg_DurableNameMismatch_ReturnsError()
{
var cfg = new ConsumerConfig { Name = "A", Durable = "B", AckPolicy = AckPolicy.AckExplicit };
var streamCfg = new StreamConfig { Name = "ORDERS", Replicas = 1 };
var err = NatsConsumer.CheckConsumerCfg(cfg, streamCfg, null, isRecovering: false);
err.ShouldNotBeNull();
err.ErrCode.ShouldBe(JsApiErrors.ConsumerCreateDurableAndNameMismatch.ErrCode);
}
[Fact]
public void CheckConsumerCfg_OverlappingFilterSubjects_ReturnsError()
{
var cfg = new ConsumerConfig
{
Durable = "D",
AckPolicy = AckPolicy.AckExplicit,
FilterSubjects = ["orders.*", "orders.created"],
};
var streamCfg = new StreamConfig { Name = "ORDERS", Replicas = 1 };
var err = NatsConsumer.CheckConsumerCfg(cfg, streamCfg, null, isRecovering: false);
err.ShouldNotBeNull();
err.ErrCode.ShouldBe(JsApiErrors.ConsumerOverlappingSubjectFilters.ErrCode);
}
[Fact]
public void CheckConsumerCfg_WithValidPullConfig_ReturnsNull()
{
var cfg = new ConsumerConfig
{
Durable = "D",
AckPolicy = AckPolicy.AckExplicit,
FilterSubject = "orders.created",
};
var streamCfg = new StreamConfig
{
Name = "ORDERS",
Replicas = 1,
Retention = RetentionPolicy.LimitsPolicy,
Subjects = ["orders.>"],
};
var err = NatsConsumer.CheckConsumerCfg(cfg, streamCfg, null, isRecovering: false);
err.ShouldBeNull();
}
}