public void SetLeaderIdWhenFollowerAndAppendEntriesRecieved() { // Arrange var message = new AppendEntriesRequest { Term = 0, PreviousLogIndex = 0, PreviousLogTerm = 0 }; var raftNode = Substitute.For <INode>(); raftNode.CurrentState.Returns(NodeState.Follower); raftNode.Data.Returns(new NodeData()); var timer = Substitute.For <INodeTimer>(); var appendEntriesPublisher = Substitute.For <IPublishToBuffer <AppendEntriesRequested> >(); var nodePublisher = new TestBufferPublisher <NodeCommandScheduled, NodeCommandResult>(); var service = new RaftService(appendEntriesPublisher, nodePublisher, timer, raftNode); // Act service.AppendEntries(message); // Assert nodePublisher.Events.Should().HaveCount(1); nodePublisher.Events[0].Command.Should().BeOfType <SetLeaderInformation>(); }
public void ThrowsWhenAppendEntriesReceivedAndNodeWillNotBeTransitionedToFollower() { // Arrange var message = new AppendEntriesRequest { Term = 24, PreviousLogIndex = 0, PreviousLogTerm = 0 }; var raftNode = Substitute.For <INode>(); raftNode.CurrentState.Returns(NodeState.Leader); raftNode.Data.Returns(new NodeData { CurrentTerm = 24 }); var timer = Substitute.For <INodeTimer>(); var appendEntriesPublisher = Substitute.For <IPublishToBuffer <AppendEntriesRequested> >(); var nodePublisher = new TestBufferPublisher <NodeCommandScheduled, NodeCommandResult>(); var service = new RaftService(appendEntriesPublisher, nodePublisher, timer, raftNode); // Act var actAction = new Action(() => service.AppendEntries(message)); // Assert actAction.ShouldThrow <FaultException <MultipleLeadersForTermFault> >(); }
public void CancelElectionIfCandidateAndReceiveAppendEntries() { // Arrange var message = new AppendEntriesRequest { Term = 0, PreviousLogIndex = 0, PreviousLogTerm = 0 }; var raftNode = Substitute.For <INode>(); raftNode.CurrentState.Returns(NodeState.Candidate); raftNode.Data.Returns(new NodeData()); var timer = Substitute.For <INodeTimer>(); var appendEntriesPublisher = Substitute.For <IPublishToBuffer <AppendEntriesRequested> >(); var nodePublisher = new TestBufferPublisher <NodeCommandScheduled, NodeCommandResult>(); nodePublisher.OnPublish(() => raftNode.CurrentState.Returns(NodeState.Follower)); var service = new RaftService(appendEntriesPublisher, nodePublisher, timer, raftNode); // Act service.AppendEntries(message); // Assert nodePublisher.Events.Should().HaveCount(2); nodePublisher.Events[0].Command.Should().BeOfType <CancelElection>(); }
public void AppendEntriesAmendsTermOnRaftNodeWhenTermIsGreaterThanCurrentTerm() { // Arrange var message = new AppendEntriesRequest { Term = 1, PreviousLogIndex = 1, PreviousLogTerm = 0 }; var raftNode = Substitute.For <INode>(); raftNode.CurrentState.Returns(NodeState.Follower); var timer = Substitute.For <INodeTimer>(); var appendEntriesPublisher = Substitute.For <IPublishToBuffer <AppendEntriesRequested> >(); var nodePublisher = new TestBufferPublisher <NodeCommandScheduled, NodeCommandResult>(); var service = new RaftService(appendEntriesPublisher, nodePublisher, timer, raftNode); var nodeData = new NodeData { Log = new NodeLog() }; nodeData.Log.SetLogEntry(1, 0); raftNode.Data.Returns(nodeData); // Act service.AppendEntries(message); // Assert nodePublisher.Events.Should().HaveCount(2); nodePublisher.Events[0].Command.Should().BeOfType <SetNewTerm>(); }
public void PublishesTruncateLogCommandToNodeAfterEntrySuccessfullyWritten() { // Arrange var @event = new AppendEntriesRequested { PreviousLogTerm = 1, PreviousLogIndex = 5 }; var nodeData = new NodeData { CommitIndex = 20, CurrentTerm = 2 }; var writeDataBlocks = Substitute.For <IWriteDataBlocks>(); var nodePublisher = new TestBufferPublisher <NodeCommandScheduled, NodeCommandResult>(); var raftNode = Substitute.For <INode>(); raftNode.Data.Returns(nodeData); var handler = new RpcLogTruncator(raftNode, writeDataBlocks, nodePublisher); // Act handler.OnNext(@event, 0L, false); // Assert writeDataBlocks.Received().WriteBlock(Arg.Any <byte[]>()); nodePublisher.Events.Should().HaveCount(1); nodePublisher.Events[0].Command.Should().BeOfType <TruncateLog>(); ((TruncateLog)nodePublisher.Events[0].Command).TruncateFromIndex.Should().Be(@event.PreviousLogIndex); }
public void PublishesToBufferAfterSafetyChecks() { // Arrange var message = new AppendEntriesRequest { Term = 11, PreviousLogIndex = 2, PreviousLogTerm = 13, LeaderCommit = 12, Entries = new [] { BitConverter.GetBytes(100), BitConverter.GetBytes(200) } }; var raftNode = Substitute.For <INode>(); raftNode.CurrentState.Returns(NodeState.Follower); var nodeData = new NodeData { Log = new NodeLog() }; nodeData.Log.SetLogEntry(message.PreviousLogIndex, message.PreviousLogTerm); raftNode.Data.Returns(nodeData); var timer = Substitute.For <INodeTimer>(); var appendEntriesPublisher = Substitute.For <IPublishToBuffer <AppendEntriesRequested> >(); var nodePublisher = new TestBufferPublisher <NodeCommandScheduled, NodeCommandResult>(); var service = new RaftService(appendEntriesPublisher, nodePublisher, timer, raftNode); // Act service.AppendEntries(message); // Assert appendEntriesPublisher.Received() .PublishEvent(Arg.Is <AppendEntriesRequested>(requested => requested.PreviousLogIndex == message.PreviousLogIndex && requested.PreviousLogTerm == message.PreviousLogTerm && requested.LeaderCommit == message.LeaderCommit && requested.Entries == message.Entries)); }
public void DoesCallApplyCommandOnRaftNodeWithCorrectLogIdx() { // Arrange const long logIdx = 3L; var @event = TestEventFactory.GetCommandEvent(logIdx, new byte[8]); var nodePublisher = new TestBufferPublisher <NodeCommandScheduled, NodeCommandResult>(); var serviceLocator = Substitute.For <IServiceLocator>(); var handler = new CommandFinalizer(serviceLocator, nodePublisher); // Act handler.Handle(@event); // Assert nodePublisher.Events.Count.Should().BeGreaterThan(1); nodePublisher.Events[1].Command.Should().BeOfType <ApplyEntry>(); ((ApplyEntry)nodePublisher.Events[1].Command).EntryIdx.Should().Be(logIdx); }
public void RequestVoteAmendsTermOnRaftNodeWhenTermIsGreaterThanCurrentTerm() { // Arrange var message = new RequestVoteRequest { Term = 1 }; var raftNode = Substitute.For <INode>(); var timer = Substitute.For <INodeTimer>(); var appendEntriesPublisher = Substitute.For <IPublishToBuffer <AppendEntriesRequested> >(); var nodePublisher = new TestBufferPublisher <NodeCommandScheduled, NodeCommandResult>(); var service = new RaftService(appendEntriesPublisher, nodePublisher, timer, raftNode); raftNode.Data.Returns(new NodeData()); // Act service.RequestVote(message); // Assert nodePublisher.Events.Should().HaveCount(1); nodePublisher.Events[0].Command.Should().BeOfType <SetNewTerm>(); }
public void DoesCommitLogEntryOnRaftNode() { // Arrange const long commitIdx = 3L; const long term = 5L; var @event = TestEventFactory.GetCommandEvent(commitIdx, new byte[8]); @event.LogEntry.Term = term; var serviceLocator = Substitute.For <IServiceLocator>(); var nodePublisher = new TestBufferPublisher <NodeCommandScheduled, NodeCommandResult>(); var handler = new CommandFinalizer(serviceLocator, nodePublisher); // Act handler.Handle(@event); // Assert nodePublisher.Events.Count.Should().BeGreaterThan(0); nodePublisher.Events[0].Command.Should().BeOfType <CommitEntry>(); ((CommitEntry)nodePublisher.Events[0].Command).EntryIdx.Should().Be(commitIdx); ((CommitEntry)nodePublisher.Events[0].Command).EntryTerm.Should().Be(term); }