batch36 task2 implement group-a lifecycle primitives

This commit is contained in:
Joseph Doherty
2026-02-28 22:52:06 -05:00
parent 0860afc886
commit 82c2f4ed1c
8 changed files with 424 additions and 1 deletions

View File

@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0
using Shouldly;
using NSubstitute;
using ZB.MOM.NatsNet.Server;
namespace ZB.MOM.NatsNet.Server.Tests.JetStream;
@@ -40,4 +41,58 @@ public sealed class NatsStreamTests
stream.Delete();
stream.IsLeader().ShouldBeFalse();
}
[Fact]
public void LifecyclePrimitives_AssignmentAndChannels_ShouldBehave()
{
var account = new Account { Name = "A" };
var stream = NatsStream.Create(
account,
new StreamConfig { Name = "ORDERS", Subjects = ["orders.*"], Storage = StorageType.MemoryStorage },
null,
new JetStreamMemStore(new StreamConfig { Name = "ORDERS", Subjects = ["orders.*"], Storage = StorageType.MemoryStorage }),
null,
null)!;
stream.AccountLocked(true).ShouldBe(account);
stream.StreamAssignment().ShouldBeNull();
var assignment = new StreamAssignment { Sync = "sync.inbox" };
stream.SetStreamAssignment(assignment);
stream.StreamAssignment().ShouldBe(assignment);
stream.UpdateC().TryRead(out var updateSignal).ShouldBeTrue();
updateSignal.ShouldBeTrue();
stream.StartClusterSubs();
stream.ClusterSubsActive().ShouldBeTrue();
stream.StopClusterSubs();
stream.ClusterSubsActive().ShouldBeFalse();
var monitor = stream.MonitorQuitC();
monitor.ShouldNotBeNull();
stream.SignalMonitorQuit();
stream.MonitorQuitC().ShouldNotBeNull();
}
[Fact]
public void IsLeaderInternal_WhenAssignedToRaftNode_UsesNodeLeaderState()
{
var account = new Account { Name = "A" };
var stream = NatsStream.Create(
account,
new StreamConfig { Name = "ORDERS", Subjects = ["orders.*"], Storage = StorageType.MemoryStorage },
null,
new JetStreamMemStore(new StreamConfig { Name = "ORDERS", Subjects = ["orders.*"], Storage = StorageType.MemoryStorage }),
null,
null)!;
var raftNode = Substitute.For<IRaftNode>();
raftNode.Leader().Returns(false);
var assignment = new StreamAssignment { Group = new RaftGroup { Node = raftNode } };
stream.SetStreamAssignment(assignment);
stream.IsLeaderInternal().ShouldBeFalse();
}
}

View File

@@ -277,6 +277,47 @@ public class StoreTypesTests
JsonSerializer.Deserialize<StorageType>("\"file\"").ShouldBe(StorageType.FileStorage);
}
[Fact]
public void PersistModeType_StringAndJsonParity_MatchesGo()
{
PersistModeType.DefaultPersistMode.String().ShouldBe("Default");
PersistModeType.AsyncPersistMode.String().ShouldBe("Async");
((PersistModeType)99).String().ShouldBe("Unknown Persist Mode Type");
JsonSerializer.Serialize(PersistModeType.DefaultPersistMode).ShouldBe("\"default\"");
JsonSerializer.Serialize(PersistModeType.AsyncPersistMode).ShouldBe("\"async\"");
JsonSerializer.Deserialize<PersistModeType>("\"default\"").ShouldBe(PersistModeType.DefaultPersistMode);
JsonSerializer.Deserialize<PersistModeType>("\"async\"").ShouldBe(PersistModeType.AsyncPersistMode);
}
[Fact]
public void ExternalStream_Domain_ReturnsSecondTokenOrEmpty()
{
new ExternalStream().Domain().ShouldBe(string.Empty);
new ExternalStream { ApiPrefix = "$JS.D1.API" }.Domain().ShouldBe("D1");
}
[Fact]
public void StreamSource_ComposeIName_UsesFilterAndTransforms()
{
var source = new StreamSource
{
Name = "ORDERS",
External = new ExternalStream { ApiPrefix = "$JS.EU.API" },
SubjectTransforms =
[
new SubjectTransformConfig { Source = "foo.*", Destination = "bar.*" },
new SubjectTransformConfig { Source = string.Empty, Destination = "baz.>" },
],
};
source.ComposeIName().ShouldContain("ORDERS:");
source.ComposeIName().ShouldContain("foo.*\f>");
source.ComposeIName().ShouldContain("bar.*\fbaz.>");
source.SetIndexName();
source.IndexName.ShouldBe(source.ComposeIName());
}
[Fact]
public void AckPolicy_JsonParity_MatchesGo()
{