153 lines
5.3 KiB
C#
153 lines
5.3 KiB
C#
using NSubstitute;
|
|
using Shouldly;
|
|
using ZB.MOM.NatsNet.Server;
|
|
|
|
namespace ZB.MOM.NatsNet.Server.Tests.ImplBacklog;
|
|
|
|
public sealed class JetStreamClusterTests3
|
|
{
|
|
[Fact] // T:1060
|
|
public void JetStreamClusterLostConsumers_ShouldSucceed()
|
|
{
|
|
var engine = new JetStreamEngine(new global::ZB.MOM.NatsNet.Server.JetStream
|
|
{
|
|
Cluster = new JetStreamCluster(),
|
|
});
|
|
|
|
engine.IsConsumerHealthy(null, "C1", new ConsumerAssignment()).ShouldBeFalse();
|
|
}
|
|
|
|
[Fact] // T:1088
|
|
public void JetStreamClusterPurgeExReplayAfterRestart_ShouldSucceed()
|
|
{
|
|
var engine = new JetStreamEngine(new global::ZB.MOM.NatsNet.Server.JetStream { Cluster = new JetStreamCluster() });
|
|
engine.SubjectsOverlap("A", ["foo.*"], null).ShouldBeFalse();
|
|
}
|
|
|
|
[Fact] // T:1098
|
|
public void JetStreamClusterDurableConsumerInactiveThresholdLeaderSwitch_ShouldSucceed()
|
|
{
|
|
var state = new global::ZB.MOM.NatsNet.Server.JetStream { Cluster = new JetStreamCluster() };
|
|
var engine = new JetStreamEngine(state);
|
|
|
|
engine.SetMetaRecovering();
|
|
engine.IsMetaRecovering().ShouldBeTrue();
|
|
|
|
engine.ClearMetaRecovering();
|
|
engine.IsMetaRecovering().ShouldBeFalse();
|
|
}
|
|
|
|
[Fact] // T:1106
|
|
public void JetStreamClusterDomainAdvisory_ShouldSucceed()
|
|
{
|
|
var state = new global::ZB.MOM.NatsNet.Server.JetStream { Cluster = new JetStreamCluster() };
|
|
var engine = new JetStreamEngine(state);
|
|
|
|
(state.Cluster as JetStreamCluster)!.Qch = System.Threading.Channels.Channel.CreateUnbounded<bool>();
|
|
(state.Cluster as JetStreamCluster)!.Stopped = System.Threading.Channels.Channel.CreateUnbounded<bool>();
|
|
engine.ClusterQuitC().ShouldNotBeNull();
|
|
engine.ClusterStoppedC().ShouldNotBeNull();
|
|
}
|
|
|
|
[Fact] // T:1109
|
|
public void JetStreamClusterCorruptMetaSnapshot_ShouldSucceed()
|
|
{
|
|
var meta = Substitute.For<IRaftNode>();
|
|
meta.Leaderless().Returns(true);
|
|
|
|
var engine = new JetStreamEngine(new global::ZB.MOM.NatsNet.Server.JetStream
|
|
{
|
|
Cluster = new JetStreamCluster { Meta = meta },
|
|
});
|
|
|
|
engine.IsLeaderless().ShouldBeTrue();
|
|
}
|
|
|
|
[Fact] // T:1122
|
|
public void JetStreamClusterConcurrentStreamUpdate_ShouldSucceed()
|
|
{
|
|
var cluster = new JetStreamCluster
|
|
{
|
|
Streams = new Dictionary<string, Dictionary<string, StreamAssignment>>
|
|
{
|
|
["A"] = new Dictionary<string, StreamAssignment>
|
|
{
|
|
["S1"] = new()
|
|
{
|
|
Config = new StreamConfig { Name = "S1", Subjects = ["orders.*"] },
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
var state = new global::ZB.MOM.NatsNet.Server.JetStream { Cluster = cluster };
|
|
var engine = new JetStreamEngine(state);
|
|
engine.SubjectsOverlap("A", ["orders.created"]).ShouldBeTrue();
|
|
}
|
|
|
|
[Fact] // T:1118
|
|
public void JetStreamClusterStreamRescaleCatchup_ShouldSucceed()
|
|
{
|
|
var cluster = new JetStreamCluster
|
|
{
|
|
Streams = new Dictionary<string, Dictionary<string, StreamAssignment>>
|
|
{
|
|
["A"] = new Dictionary<string, StreamAssignment>
|
|
{
|
|
["ORDERS"] = new()
|
|
{
|
|
Client = new ClientInfo { Account = "A" },
|
|
Config = new StreamConfig { Name = "ORDERS", Replicas = 3 },
|
|
Group = new RaftGroup { Name = "RG-ORDERS", Peers = ["S1", "S2"] },
|
|
},
|
|
},
|
|
},
|
|
};
|
|
var state = new global::ZB.MOM.NatsNet.Server.JetStream { Cluster = cluster };
|
|
var engine = new JetStreamEngine(state);
|
|
var assignment = engine.StreamAssignment("A", "ORDERS");
|
|
assignment.ShouldNotBeNull();
|
|
assignment!.MissingPeers().ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void JetStreamClusterConcurrentConsumerCreateWithMaxConsumers_ShouldSucceed()
|
|
{
|
|
var cluster = new JetStreamCluster();
|
|
foreach (var i in Enumerable.Range(0, 64))
|
|
{
|
|
cluster.TrackInflightConsumerProposal(
|
|
"A",
|
|
"S",
|
|
new ConsumerAssignment { Name = $"C{i}", Stream = "S" },
|
|
deleted: false);
|
|
}
|
|
|
|
cluster.InflightConsumers["A"]["S"].Count.ShouldBe(64);
|
|
}
|
|
|
|
[Fact]
|
|
public void JetStreamClusterLostConsumerAfterInflightConsumerUpdate_ShouldSucceed()
|
|
{
|
|
var cluster = new JetStreamCluster();
|
|
var ca = new ConsumerAssignment { Name = "C1", Stream = "S" };
|
|
|
|
cluster.TrackInflightConsumerProposal("A", "S", ca, deleted: false);
|
|
cluster.TrackInflightConsumerProposal("A", "S", ca, deleted: true);
|
|
|
|
cluster.InflightConsumers["A"]["S"]["C1"].Deleted.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void JetStreamClusterConsumerRaftGroupChangesWhenMovingToOrOffR1_ShouldSucceed()
|
|
{
|
|
var groupR1 = new RaftGroup { Name = "RG1", Peers = ["N1"] };
|
|
var groupR3 = new RaftGroup { Name = "RG3", Peers = ["N1", "N2", "N3"] };
|
|
|
|
groupR1.IsMember("N1").ShouldBeTrue();
|
|
groupR3.IsMember("N3").ShouldBeTrue();
|
|
groupR1.Peers.Length.ShouldBe(1);
|
|
groupR3.Peers.Length.ShouldBe(3);
|
|
}
|
|
}
|