using NATS.Server.Raft; namespace NATS.Server.Raft.Tests.Raft; public class RaftParityBatch3Tests { [Fact] public async Task ProposeMulti_proposes_entries_in_order() { using var leader = ElectSingleNodeLeader(); var indexes = await leader.ProposeMultiAsync(["cmd-1", "cmd-2", "cmd-3"], CancellationToken.None); indexes.Count.ShouldBe(3); indexes[0].ShouldBe(1); indexes[1].ShouldBe(2); indexes[2].ShouldBe(3); leader.Log.Entries.Count.ShouldBe(3); } [Fact] public void PeerState_tracks_lag_and_current_flags() { var peer = new RaftPeerState { PeerId = "n2", NextIndex = 10, MatchIndex = 7, LastContact = DateTime.UtcNow, }; peer.RecalculateLag(); peer.RefreshCurrent(TimeSpan.FromSeconds(1)); peer.Lag.ShouldBe(2); peer.Current.ShouldBeTrue(); peer.LastContact = DateTime.UtcNow - TimeSpan.FromSeconds(5); peer.RefreshCurrent(TimeSpan.FromSeconds(1)); peer.Current.ShouldBeFalse(); } [Fact] public void CommittedEntry_contains_index_and_entries() { var entries = new[] { new RaftLogEntry(42, 3, "set x"), new RaftLogEntry(43, 3, "set y"), }; var committed = new CommittedEntry(43, entries); committed.Index.ShouldBe(43); committed.Entries.Count.ShouldBe(2); committed.Entries[0].Command.ShouldBe("set x"); } [Fact] public void RaftEntry_roundtrips_to_wire_shape() { var entry = new RaftEntry(RaftEntryType.AddPeer, new byte[] { 1, 2, 3 }); var wire = entry.ToWire(); var decoded = RaftEntry.FromWire(wire); decoded.Type.ShouldBe(RaftEntryType.AddPeer); decoded.Data.ShouldBe(new byte[] { 1, 2, 3 }); } private static RaftNode ElectSingleNodeLeader() { var node = new RaftNode("n1"); node.ConfigureCluster([node]); node.StartElection(1); node.IsLeader.ShouldBeTrue(); return node; } }