public async Task CandidateShouldApplyLogsToFsm()
        {
            var currentState  = new CurrentState(Guid.NewGuid().ToString(), 0, default(string), 0, 0, default(string));
            var fsm           = new InMemoryStateMachine();
            var candidate     = new Candidate(currentState, fsm, _peers, _log, _random, _node, _settings, _rules, _loggerFactory.Object);
            var log           = new LogEntry(new FakeCommand("test"), typeof(string), 1);
            var appendEntries = new AppendEntriesBuilder()
                                .WithTerm(1)
                                .WithPreviousLogTerm(1)
                                .WithEntry(log)
                                .WithPreviousLogIndex(1)
                                .WithLeaderCommitIndex(1)
                                .Build();
            await _log.Apply(log);

            var appendEntriesResponse = await candidate.Handle(appendEntries);

            appendEntriesResponse.Success.ShouldBeTrue();
            candidate.CurrentState.CurrentTerm.ShouldBe(1);
            candidate.CurrentState.LastApplied.ShouldBe(1);
            fsm.HandledLogEntries.ShouldBe(1);
            var node = (NothingNode)_node;

            node.BecomeFollowerCount.ShouldBe(1);
        }
예제 #2
0
        public void CandidateShouldApplyLogsToFsm()
        {
            var currentState  = new CurrentState(Guid.NewGuid(), 0, default(Guid), 0, 0, default(Guid));
            var fsm           = new Rafty.FiniteStateMachine.InMemoryStateMachine();
            var candidate     = new Candidate(currentState, fsm, _peers, _log, _random, _node, _settings, _rules);
            var log           = new LogEntry(new FakeCommand("test"), typeof(string), 1);
            var appendEntries = new AppendEntriesBuilder()
                                .WithTerm(1)
                                .WithPreviousLogTerm(1)
                                .WithEntry(log)
                                .WithPreviousLogIndex(1)
                                .WithLeaderCommitIndex(1)
                                .Build();

            //assume node has added the log..
            _log.Apply(log);
            var appendEntriesResponse = candidate.Handle(appendEntries);

            candidate.CurrentState.CurrentTerm.ShouldBe(1);
            candidate.CurrentState.LastApplied.ShouldBe(1);
            fsm.ExposedForTesting.ShouldBe(1);
            var node = (NothingNode)_node;

            node.BecomeFollowerCount.ShouldBe(1);
        }
예제 #3
0
        public void ShouldReplyFalseIfRpcTermLessThanCurrentTerm()
        {
            _currentState = new CurrentState(Guid.NewGuid(), 1, default(Guid), 0, 0, default(Guid));
            var appendEntriesRpc      = new AppendEntriesBuilder().WithTerm(0).Build();
            var follower              = new Follower(_currentState, _fsm, _log, _random, _node, _settings, _rules, _peers);
            var appendEntriesResponse = follower.Handle(appendEntriesRpc);

            appendEntriesResponse.Success.ShouldBe(false);
            appendEntriesResponse.Term.ShouldBe(1);
        }
예제 #4
0
        public async Task ShouldReplyFalseIfRpcTermLessThanCurrentTerm()
        {
            _currentState = new CurrentState(Guid.NewGuid().ToString(), 1, default(string), 0, 0, default(string));
            var appendEntriesRpc      = new AppendEntriesBuilder().WithTerm(0).Build();
            var follower              = new Follower(_currentState, _fsm, _log, _random, _node, _settings, _rules, _peers, _loggerFactory.Object);
            var appendEntriesResponse = await follower.Handle(appendEntriesRpc);

            appendEntriesResponse.Success.ShouldBe(false);
            appendEntriesResponse.Term.ShouldBe(1);
        }
예제 #5
0
        public void ShouldReplyFalseIfLogDoesntContainEntryAtPreviousLogIndexWhoseTermMatchesRpcPrevLogTerm()
        {
            _currentState = new CurrentState(Guid.NewGuid(), 2, default(Guid), 0, 0, default(Guid));
            _log.Apply(new LogEntry(new FakeCommand(""), typeof(string), 2));
            var appendEntriesRpc      = new AppendEntriesBuilder().WithTerm(2).WithPreviousLogIndex(1).WithPreviousLogTerm(1).Build();
            var follower              = new Follower(_currentState, _fsm, _log, _random, _node, _settings, _rules, _peers);
            var appendEntriesResponse = follower.Handle(appendEntriesRpc);

            appendEntriesResponse.Success.ShouldBe(false);
            appendEntriesResponse.Term.ShouldBe(2);
        }
예제 #6
0
        public async Task FollowerShouldAppendNewEntries()
        {
            _currentState = new CurrentState(Guid.NewGuid().ToString(), 0, default(string), 0, 0, default(string));
            var follower      = new Follower(_currentState, _fsm, _log, _random, _node, _settings, _rules, _peers, _loggerFactory.Object);
            var logEntry      = new LogEntry(new FakeCommand(), typeof(FakeCommand), 1);
            var appendEntries = new AppendEntriesBuilder().WithTerm(1).WithEntry(logEntry).Build();
            var response      = await follower.Handle(appendEntries);

            response.Success.ShouldBeTrue();
            response.Term.ShouldBe(1);
            var inMemoryLog = (InMemoryLog)_log;

            inMemoryLog.ExposedForTesting.Count.ShouldBe(1);
        }
예제 #7
0
        public void ShouldDeleteExistingEntryIfItConflictsWithNewOne()
        {
            _currentState = new CurrentState(Guid.NewGuid(), 1, default(Guid), 2, 0, default(Guid));
            _log.Apply(new LogEntry(new FakeCommand("term 1 commit index 0"), typeof(string), 1));
            _log.Apply(new LogEntry(new FakeCommand("term 1 commit index 1"), typeof(string), 1));
            _log.Apply(new LogEntry(new FakeCommand("term 1 commit index 2"), typeof(string), 1));
            var appendEntriesRpc = new AppendEntriesBuilder()
                                   .WithEntry(new LogEntry(new FakeCommand("term 2 commit index 2"), typeof(string), 2))
                                   .WithTerm(2)
                                   .WithPreviousLogIndex(1)
                                   .WithPreviousLogTerm(1)
                                   .Build();
            var follower = new Follower(_currentState, _fsm, _log, _random, _node, _settings, _rules, _peers);
            var appendEntriesResponse = follower.Handle(appendEntriesRpc);

            appendEntriesResponse.Success.ShouldBe(true);
            appendEntriesResponse.Term.ShouldBe(2);
        }
예제 #8
0
        public void FollowerShouldSetCommitIndexIfLeaderCommitGreaterThanCommitIndex()
        {
            _currentState = new CurrentState(Guid.NewGuid(), 1, default(Guid), 0, 0, default(Guid));
            var log = new LogEntry(new FakeCommand("term 1 commit index 0"), typeof(string), 1);

            _log.Apply(log);
            var appendEntriesRpc = new AppendEntriesBuilder()
                                   .WithEntry(log)
                                   .WithTerm(1)
                                   .WithPreviousLogIndex(1)
                                   .WithPreviousLogTerm(1)
                                   .WithLeaderCommitIndex(1)
                                   .Build();
            //assume node has applied log..
            var follower = new Follower(_currentState, _fsm, _log, _random, _node, _settings, _rules, _peers);
            var appendEntriesResponse = follower.Handle(appendEntriesRpc);

            follower.CurrentState.CommitIndex.ShouldBe(1);
        }
예제 #9
0
        public void ShouldAppendAnyEntriesNotInTheLog()
        {
            _currentState = new CurrentState(Guid.NewGuid(), 1, default(Guid), 0, 0, default(Guid));
            _log.Apply(new LogEntry(new FakeCommand("term 1 commit index 0"), typeof(string), 1));
            var appendEntriesRpc = new AppendEntriesBuilder()
                                   .WithEntry(new LogEntry(new FakeCommand("term 1 commit index 1"), typeof(string), 1))
                                   .WithTerm(1)
                                   .WithPreviousLogIndex(1)
                                   .WithPreviousLogTerm(1)
                                   .WithLeaderId(Guid.NewGuid())
                                   .Build();
            var follower = new Follower(_currentState, _fsm, _log, _random, _node, _settings, _rules, _peers);
            var appendEntriesResponse = follower.Handle(appendEntriesRpc);

            appendEntriesResponse.Success.ShouldBe(true);
            appendEntriesResponse.Term.ShouldBe(1);
            _log.GetTermAtIndex(1).ShouldBe(1);
            follower.CurrentState.LeaderId.ShouldBe(appendEntriesRpc.LeaderId);
        }
예제 #10
0
        public async Task CandidateShouldNotAppendDuplicateEntry()
        {
            _node         = new NothingNode();
            _currentState = new CurrentState(Guid.NewGuid().ToString(), 0, default(string), 0, 0, default(string));
            var candidate     = new Candidate(_currentState, _fsm, _peers, _log, _random, _node, _settings, _rules, _loggerFactory.Object);
            var logEntry      = new LogEntry(new FakeCommand(), typeof(FakeCommand), 1);
            var appendEntries = new AppendEntriesBuilder().WithPreviousLogIndex(1).WithPreviousLogTerm(1).WithTerm(1).WithEntry(logEntry).WithTerm(1).WithLeaderCommitIndex(1).Build();
            var response      = await candidate.Handle(appendEntries);

            response.Success.ShouldBeTrue();
            response.Term.ShouldBe(1);
            response = await candidate.Handle(appendEntries);

            response.Success.ShouldBeTrue();
            response.Term.ShouldBe(1);
            var inMemoryLog = (InMemoryLog)_log;

            inMemoryLog.ExposedForTesting.Count.ShouldBe(1);
        }
예제 #11
0
        public async Task FollowerShouldSetCommitIndexIfLeaderCommitGreaterThanCommitIndex()
        {
            _currentState = new CurrentState(Guid.NewGuid().ToString(), 1, default(string), 0, 0, default(string));
            var log = new LogEntry(new FakeCommand("term 1 commit index 0"), typeof(string), 1);
            await _log.Apply(log);

            var appendEntriesRpc = new AppendEntriesBuilder()
                                   .WithEntry(log)
                                   .WithTerm(1)
                                   .WithPreviousLogIndex(1)
                                   .WithPreviousLogTerm(1)
                                   .WithLeaderCommitIndex(1)
                                   .Build();
            var follower = new Follower(_currentState, _fsm, _log, _random, _node, _settings, _rules, _peers, _loggerFactory.Object);
            var response = await follower.Handle(appendEntriesRpc);

            response.Success.ShouldBeTrue();
            follower.CurrentState.CommitIndex.ShouldBe(1);
        }
예제 #12
0
        public void LeaderShouldSetCommitIndexIfLeaderCommitGreaterThanCommitIndex()
        {
            _currentState = new CurrentState(Guid.NewGuid(), 0, default(Guid), 0, 0, default(Guid));
            //assume log applied by node?
            var log = new LogEntry(new FakeCommand("term 1 commit index 0"), typeof(string), 1);

            _log.Apply(log);
            var appendEntriesRpc = new AppendEntriesBuilder()
                                   .WithEntry(log)
                                   .WithTerm(1)
                                   .WithPreviousLogIndex(1)
                                   .WithPreviousLogTerm(1)
                                   .WithLeaderCommitIndex(1)
                                   .WithLeaderId(Guid.NewGuid())
                                   .Build();
            var leader = new Leader(_currentState, _fsm, (s) => _peers, _log, _node, _settings, _rules);
            var state  = leader.Handle(appendEntriesRpc);

            leader.CurrentState.CommitIndex.ShouldBe(1);
            leader.CurrentState.LeaderId.ShouldBe(appendEntriesRpc.LeaderId);
        }
예제 #13
0
        public async Task CandidateShouldSetCommitIndexIfLeaderCommitGreaterThanCommitIndex()
        {
            _currentState = new CurrentState(Guid.NewGuid().ToString(), 0, default(string), 0, 0, default(string));
            //assume log applied by node?
            var log = new LogEntry(new FakeCommand("term 1 commit index 0"), typeof(string), 1);
            await _log.Apply(log);

            var appendEntriesRpc = new AppendEntriesBuilder()
                                   .WithEntry(log)
                                   .WithTerm(1)
                                   .WithPreviousLogIndex(1)
                                   .WithPreviousLogTerm(1)
                                   .WithLeaderCommitIndex(1)
                                   .WithLeaderId(Guid.NewGuid().ToString())
                                   .Build();
            var candidate             = new Candidate(_currentState, _fsm, _peers, _log, _random, _node, _settings, _rules);
            var appendEntriesResponse = await candidate.Handle(appendEntriesRpc);

            candidate.CurrentState.CommitIndex.ShouldBe(1);
            candidate.CurrentState.LeaderId.ShouldBe(appendEntriesRpc.LeaderId);
        }
        public async Task LeaderShouldApplyLogsToFsm()
        {
            var currentState  = new CurrentState(Guid.NewGuid().ToString(), 0, default(string), 0, 0, default(string));
            var fsm           = new Rafty.FiniteStateMachine.InMemoryStateMachine();
            var leader        = new Leader(currentState, fsm, (s) => _peers, _log, _node, _settings, _rules);
            var log           = new LogEntry(new FakeCommand("test"), typeof(string), 1);
            var appendEntries = new AppendEntriesBuilder()
                                .WithTerm(1)
                                .WithPreviousLogTerm(1)
                                .WithEntry(log)
                                .WithPreviousLogIndex(1)
                                .WithLeaderCommitIndex(1)
                                .Build();
            //assume node has added the log..
            await _log.Apply(log);

            var appendEntriesResponse = leader.Handle(appendEntries);

            leader.CurrentState.CurrentTerm.ShouldBe(1);
            leader.CurrentState.LastApplied.ShouldBe(1);
            fsm.HandledLogEntries.ShouldBe(1);
        }
예제 #15
0
        public async Task ShouldDeleteExistingEntryIfItConflictsWithNewOne()
        {
            _currentState = new CurrentState(Guid.NewGuid().ToString(), 1, default(string), 2, 0, default(string));
            await _log.Apply(new LogEntry(new FakeCommand("term 1 commit index 1"), typeof(string), 1));

            await _log.Apply(new LogEntry(new FakeCommand("term 1 commit index 2"), typeof(string), 1));

            await _log.Apply(new LogEntry(new FakeCommand("term 1 commit index 3"), typeof(string), 1));

            var appendEntriesRpc = new AppendEntriesBuilder()
                                   .WithEntry(new LogEntry(new FakeCommand("term 2 commit index 3"), typeof(string), 2))
                                   .WithTerm(2)
                                   .WithPreviousLogIndex(2)
                                   .WithPreviousLogTerm(1)
                                   .WithLeaderCommitIndex(3)
                                   .Build();
            var follower = new Follower(_currentState, _fsm, _log, _random, _node, _settings, _rules, _peers, _loggerFactory.Object);
            var appendEntriesResponse = await follower.Handle(appendEntriesRpc);

            appendEntriesResponse.Success.ShouldBe(true);
            appendEntriesResponse.Term.ShouldBe(2);
        }