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.
51 lines
2.2 KiB
C#
51 lines
2.2 KiB
C#
using NATS.Server.Raft;
|
|
|
|
namespace NATS.Server.Raft.Tests.Raft;
|
|
|
|
public class RaftStrictConsensusRuntimeTests
|
|
{
|
|
[Fact]
|
|
public async Task Quorum_and_nextindex_rules_gate_commit_visibility_and_snapshot_catchup_convergence()
|
|
{
|
|
var voter = new RaftNode("v1");
|
|
voter.GrantVote(2, "cand-a").Granted.ShouldBeTrue();
|
|
voter.GrantVote(2, "cand-b").Granted.ShouldBeFalse();
|
|
|
|
var transport = new RejectingRaftTransport();
|
|
var leader = new RaftNode("n1", transport);
|
|
var followerA = new RaftNode("n2", transport);
|
|
var followerB = new RaftNode("n3", transport);
|
|
var cluster = new[] { leader, followerA, followerB };
|
|
foreach (var node in cluster)
|
|
node.ConfigureCluster(cluster);
|
|
|
|
leader.StartElection(cluster.Length);
|
|
leader.ReceiveVote(new VoteResponse { Granted = true }, cluster.Length);
|
|
leader.IsLeader.ShouldBeTrue();
|
|
|
|
_ = await leader.ProposeAsync("cmd-1", default);
|
|
leader.AppliedIndex.ShouldBe(0);
|
|
followerA.AppliedIndex.ShouldBe(0);
|
|
followerB.AppliedIndex.ShouldBe(0);
|
|
}
|
|
|
|
private sealed class RejectingRaftTransport : IRaftTransport
|
|
{
|
|
public Task<IReadOnlyList<AppendResult>> AppendEntriesAsync(string leaderId, IReadOnlyList<string> followerIds, RaftLogEntry entry, CancellationToken ct)
|
|
=> Task.FromResult<IReadOnlyList<AppendResult>>(
|
|
followerIds.Select(id => new AppendResult { FollowerId = id, Success = false }).ToArray());
|
|
|
|
public Task<VoteResponse> RequestVoteAsync(string candidateId, string voterId, VoteRequest request, CancellationToken ct)
|
|
=> Task.FromResult(new VoteResponse { Granted = true });
|
|
|
|
public Task InstallSnapshotAsync(string leaderId, string followerId, RaftSnapshot snapshot, CancellationToken ct)
|
|
=> Task.CompletedTask;
|
|
|
|
public Task SendTimeoutNowAsync(string leaderId, string targetId, ulong term, CancellationToken ct)
|
|
=> Task.CompletedTask;
|
|
|
|
public Task SendHeartbeatAsync(string leaderId, IReadOnlyList<string> followerIds, int term, Action<string> onAck, CancellationToken ct)
|
|
=> Task.CompletedTask;
|
|
}
|
|
}
|