Files
natsdotnet/tests/NATS.Server.Raft.Tests/Raft/RaftNodeParityBatch2Tests.cs
Joseph Doherty edf9ed770e refactor: extract NATS.Server.Raft.Tests project
Move 43 Raft consensus test files (8 root-level + 35 in Raft/ subfolder)
from NATS.Server.Tests into a dedicated NATS.Server.Raft.Tests project.
Update namespaces, add InternalsVisibleTo, and fix timing/exception
handling issues in moved test files.
2026-03-12 15:36:02 -04:00

150 lines
4.6 KiB
C#

using NATS.Server.Raft;
namespace NATS.Server.Raft.Tests.Raft;
public class RaftNodeParityBatch2Tests
{
private static RaftNode ElectSingleNodeLeader()
{
var node = new RaftNode("n1");
node.ConfigureCluster([node]);
node.StartElection(1);
node.IsLeader.ShouldBeTrue();
return node;
}
[Fact]
public void Leader_tracking_flags_update_on_election_and_heartbeat()
{
var node1 = new RaftNode("n1");
var node2 = new RaftNode("n2");
var node3 = new RaftNode("n3");
node1.ConfigureCluster([node1, node2, node3]);
node2.ConfigureCluster([node1, node2, node3]);
node3.ConfigureCluster([node1, node2, node3]);
node1.StartElection(3);
node1.ReceiveVote(node2.GrantVote(node1.Term, node1.Id), 3);
node1.IsLeader.ShouldBeTrue();
node1.GroupLeader.ShouldBe("n1");
node1.Leaderless.ShouldBeFalse();
node1.HadPreviousLeader.ShouldBeTrue();
node1.LeaderSince.ShouldNotBeNull();
node2.ReceiveHeartbeat(node1.Term, fromPeerId: "n1");
node2.IsLeader.ShouldBeFalse();
node2.GroupLeader.ShouldBe("n1");
node2.Leaderless.ShouldBeFalse();
node2.HadPreviousLeader.ShouldBeTrue();
node2.LeaderSince.ShouldBeNull();
}
[Fact]
public void Stepdown_clears_group_leader_and_leader_since()
{
using var leader = ElectSingleNodeLeader();
leader.GroupLeader.ShouldBe("n1");
leader.LeaderSince.ShouldNotBeNull();
leader.RequestStepDown();
leader.Leaderless.ShouldBeTrue();
leader.GroupLeader.ShouldBe(RaftNode.NoLeader);
leader.LeaderSince.ShouldBeNull();
}
[Fact]
public void Observer_mode_can_be_toggled()
{
using var node = new RaftNode("n1");
node.IsObserver.ShouldBeFalse();
node.SetObserver(true);
node.IsObserver.ShouldBeTrue();
node.SetObserver(false);
node.IsObserver.ShouldBeFalse();
}
[Fact]
public void Cluster_size_adjustments_enforce_boot_and_leader_rules()
{
using var node = new RaftNode("n1");
node.ClusterSize().ShouldBe(1);
node.AdjustBootClusterSize(1).ShouldBeTrue();
node.ClusterSize().ShouldBe(2); // floor is 2
node.ConfigureCluster([node]);
node.StartElection(1);
node.IsLeader.ShouldBeTrue();
node.AdjustClusterSize(5).ShouldBeTrue();
node.ClusterSize().ShouldBe(5);
node.AdjustBootClusterSize(7).ShouldBeFalse();
}
[Fact]
public async Task Progress_size_and_applied_accessors_report_expected_values()
{
using var leader = ElectSingleNodeLeader();
await leader.ProposeAsync("abc", CancellationToken.None);
await leader.ProposeAsync("de", CancellationToken.None);
var progress = leader.Progress();
progress.Index.ShouldBe(2);
progress.Commit.ShouldBe(2);
progress.Applied.ShouldBe(2);
var size = leader.Size();
size.Entries.ShouldBe(2);
size.Bytes.ShouldBe(5);
var applied = leader.Applied(1);
applied.Entries.ShouldBe(1);
applied.Bytes.ShouldBe(3);
leader.ProcessedIndex.ShouldBe(1);
}
[Fact]
public void Campaign_timeout_randomization_and_defaults_match_go_constants()
{
using var node = new RaftNode("n1");
for (var i = 0; i < 20; i++)
{
var timeout = node.RandomizedCampaignTimeout();
timeout.ShouldBeGreaterThanOrEqualTo(RaftNode.MinCampaignTimeoutDefault);
timeout.ShouldBeLessThan(RaftNode.MaxCampaignTimeoutDefault);
}
RaftNode.HbIntervalDefault.ShouldBe(TimeSpan.FromSeconds(1));
RaftNode.LostQuorumIntervalDefault.ShouldBe(TimeSpan.FromSeconds(10));
RaftNode.ObserverModeIntervalDefault.ShouldBe(TimeSpan.FromHours(48));
RaftNode.PeerRemoveTimeoutDefault.ShouldBe(TimeSpan.FromMinutes(5));
RaftNode.NoLeader.ShouldBe(string.Empty);
RaftNode.NoVote.ShouldBe(string.Empty);
}
[Fact]
public void Stop_wait_for_stop_and_delete_set_lifecycle_state()
{
var path = Path.Combine(Path.GetTempPath(), $"raft-node-delete-{Guid.NewGuid():N}");
Directory.CreateDirectory(path);
File.WriteAllText(Path.Combine(path, "marker.txt"), "x");
using var node = new RaftNode("n1", persistDirectory: path);
node.IsDeleted.ShouldBeFalse();
node.Stop();
node.WaitForStop();
node.IsDeleted.ShouldBeFalse();
Directory.Exists(path).ShouldBeTrue();
node.Delete();
node.IsDeleted.ShouldBeTrue();
Directory.Exists(path).ShouldBeFalse();
}
}