Esempio n. 1
0
    def test_setAndGetCurrentTerm(self):
        '''getCurrentTerm should return the current term; if the persister is
        new, the term should be 0.  setcurrentTerm should durably set
        the current term, and it should be retrievable by
        getCurrentTerm.

        '''
        results = self.persister.getCurrentTerm()

        zeroFailureMessage = 'getCurrentTerm for new persister should return 0'
        results.addCallback(self.assertEqual, 0, msg=zeroFailureMessage)

        results.addCallback(
            dropResult(self.persister.setCurrentTerm, 123))

        setCurrentTermFailureMessage = 'setCurrentTerm did not set the term'
        results.addCallback(self.assertEqual, 123,
                            msg=setCurrentTermFailureMessage)

        results.addCallback(dropResult(self.persister.getCurrentTerm))

        getCurrentTermFailureMessage = ('getCurrentTerm did not agree'
                                        ' with setCurrentTerm')
        results.addCallback(self.assertEqual, 123,
                            msg=getCurrentTermFailureMessage)
        return results
Esempio n. 2
0
    def test_votedForAndvoteFor(self):
        '''votedFor should return the identity of the candidate voted for most
        recently; if the persister is new, it should return None.

        voteFor should durably set the identity of the candidate voted
        for, and that identity should be retrievable by votedFor

        '''
        results = self.persister.votedFor()

        noneVotedForFailure = 'votedFor for a empty persister should be None'

        results.addCallback(self.assertEqual, None, msg=noneVotedForFailure)

        for identity in ('first id', 'second id'):
            results.addCallback(dropResult(self.persister.voteFor, identity))

            voteForFailureMessage = ('voteFor did not correctly set the'
                                     ' candidate identity')
            results.addCallback(self.assertEqual, identity,
                                msg=voteForFailureMessage)

            results.addCallback(dropResult(self.persister.votedFor))

            votedForFailureMessage = 'votedFor disagreed with voteFor'
            results.addCallback(self.assertEqual, identity,
                                msg=votedForFailureMessage)

        return results
Esempio n. 3
0
    def test_overlappingMatchAndAppendNewLogEntries(self):
        '''matchAndAppendNewLogEntries should delete conflicting entries and
        ignore ones that match.

        '''
        results = defer.succeed(None)

        for idx in xrange(len(firstEntries)):
            # drop existing data
            results.addCallback(dropResult(self.persister._truncateLog))

            results.addCallback(
                dropResult(self.persister.addNewEntries, firstEntries))

            # construct overlappingEntries such that:
            # 1) its 0th item matches the currentLog[idx]
            # 2) its subsequent items do not match currentLog[idx+1:]
            #
            # then ensure that it's inserted at lastIndex = idx - 1
            #
            # overlappingLog:      [1][4][5]
            # currentlog:    ...[1][1][2][3]...
            #                       ^  ^
            #                      /    \
            #               lastIndex   idx
            #
            # matchAndAppendNewLogEntries should combine these such
            # that:
            #
            # currentLog:    ...[1][1][4][5]

            lastMatchingIndex = idx - 1
            overlappingEntries = [firstEntries[idx]] + appendedEntries
            expectedEntries = firstEntries[:idx] + overlappingEntries

            results.addCallback(
                dropResult(self.persister.matchAndAppendNewLogEntries,
                           lastMatchingIndex, overlappingEntries))

            results.addCallback(
                dropResult(self.persister._logSlice, 0, -1))

            def assertMatch(logSlice,
                            idx=idx,
                            overlappingEntries=overlappingEntries,
                            expectedEntries=expectedEntries):
                failureMessage = ('logSlice disagrees with overlapping'
                                  ' matchAndAppendNewLogEntries @ %d' % idx)
                self.assertEqual(logSlice,
                                 expectedEntries,
                                 msg=failureMessage)

            results.addCallback(assertMatch)

        return results
Esempio n. 4
0
            def closureCallbacks(idx=idx, entry=entry):
                results.addCallback(
                    dropResult(self.persister.addNewEntries,
                               [entry]))

                results.addCallback(
                    dropResult(self.persister.lastIndexLETerm,
                               entry.term))

                failureMessage = ('lastIndexLETerm returned False for'
                                  ' idx %d and term %d' % (idx, entry.term))
                results.addCallback(self.assertTrue, msg=failureMessage)
Esempio n. 5
0
    def test__truncateLog(self):
        '''Sanity test for test crutch _truncateLog.  _truncateLog should do
        just that: truncate the log.

        '''
        results = self.persister.addNewEntries(firstEntries)
        results.addCallback(dropResult(self.persister._truncateLog))
        results.addCallback(dropResult(self.persister._logSlice, 0, -1))

        emptyLogFailure = "_truncateLog didn't truncate the log"
        results.addCallback(self.assertFalse, msg=emptyLogFailure)
        return results
Esempio n. 6
0
    def test_indexMatchesTerm(self):
        '''indexMatchesTerm should return True if the log entry's term matches
        term at the index, or if there are no entries in the log.

        '''
        results = self.persister.indexMatchesTerm(10, 123)
        trueFailureMessage = ('indexMatchesTerm should return True for'
                              ' an empty persister')
        results.addCallback(self.assertTrue, msg=trueFailureMessage)

        results.addCallback(
            dropResult(self.persister.addNewEntries, firstEntries))

        for idx, entry in enumerate(firstEntries):

            def closureCallbacks(idx=idx, entry=entry):
                results.addCallback(
                    dropResult(self.persister.indexMatchesTerm,
                               idx, entry.term))

                failureMessage = ('indexMatchesTerm returned False for'
                                  ' idx %d and term %d' % (idx, entry.term))
                results.addCallback(self.assertTrue, msg=failureMessage)

            closureCallbacks()

        return results
Esempio n. 7
0
            def closureCallbacks(idx=idx, entry=entry):
                results.addCallback(
                    dropResult(self.persister.indexMatchesTerm,
                               idx, entry.term))

                failureMessage = ('indexMatchesTerm returned False for'
                                  ' idx %d and term %d' % (idx, entry.term))
                results.addCallback(self.assertTrue, msg=failureMessage)
Esempio n. 8
0
            def closureCallbacks(gte=gte, lt=lt):
                results.addCallback(
                    dropResult(self.persister._logSlice, gte, lt))

                failureMesage = '_logSlice(%d, %d) returned incorrect list'

                results.addCallback(self.assertEquals,
                                    firstEntries[gte:lt],
                                    msg=failureMesage)
Esempio n. 9
0
 def test_willBecomeLeader_True(self):
     self.state.peers = set([1, 2])
     results = self.state.willBecomeLeader(votesSoFar=2)
     msg = 'Should be true with 2 votes'
     results.addCallback(self.assertFalse, msg=msg)
     results.addCallback(
         dropResult(self.assertTrue,
                    isinstance(self.server.state, raft.Leader)))
     return results
 def test_willBecomeLeader_True(self):
     self.state.peers = set([1, 2])
     results = self.state.willBecomeLeader(votesSoFar=2)
     msg = 'Should be true with 2 votes'
     results.addCallback(self.assertFalse, msg=msg)
     results.addCallback(dropResult(self.assertTrue,
                                    isinstance(self.server.state,
                                               raft.Leader)))
     return results
Esempio n. 11
0
    def test_disjointMatchAndAppendNewLogEntries(self):
        '''matchAndAppendNewLogEntries should append disjoint logs.

        '''
        results = self.persister.matchAndAppendNewLogEntries(-1, firstEntries)

        results.addCallback(dropResult(self.persister.getLastIndex))

        indexWrongFailure = ('getLastIndex claims'
                             ' matchAndAppendNewLogEntries'
                             ' failed to append entries')

        firstEntriesNewIndex = len(firstEntries) - 1

        results.addCallback(self.assertEqual, firstEntriesNewIndex,
                            msg=indexWrongFailure)

        results.addCallback(dropResult(self.persister._logSlice, 0, -1))

        logSliceWrongFailure = ('logSlice claims matchAndAppendNewLogEntries'
                                ' failed to append entries')

        results.addCallback(self.assertEqual, firstEntries,
                            msg=logSliceWrongFailure)

        results.addCallback(
            dropResult(self.persister.matchAndAppendNewLogEntries,
                       firstEntriesNewIndex, appendedEntries))

        results.addCallback(
            dropResult(self.persister.getLastIndex))

        results.addCallback(self.assertEqual,
                            len(firstEntries) + len(appendedEntries) - 1,
                            msg=indexWrongFailure)

        results.addCallback(
            dropResult(self.persister._logSlice, 0, -1))

        results.addCallback(self.assertEqual, firstEntries + appendedEntries,
                            msg=logSliceWrongFailure)
        return results
Esempio n. 12
0
    def test_addNewEntries(self):
        '''addNewEntries should append the entries to the end of the log
        without any matching.

        '''
        results = self.persister.addNewEntries(firstEntries)

        results.addCallback(dropResult(self.persister._logSlice, 0, -1))

        entriesFailureMessage = 'addNewEntries failed to add all entries'
        results.addCallback(self.assertEqual, firstEntries,
                            msg=entriesFailureMessage)

        results.addCallback(dropResult(self.persister.addNewEntries,
                                       appendedEntries))

        results.addCallback(dropResult(self.persister._logSlice, 0, -1))
        results.addCallback(self.assertEqual,
                            firstEntries + appendedEntries,
                            msg=entriesFailureMessage)
        return results
Esempio n. 13
0
    def test_getLastTerm(self):
        '''getLastTerm should return the term of the last log entry; an empty
        persister's getLastTerm should return 0.

        '''
        results = self.persister.getLastTerm()

        zeroFailureMessage = "getLastTerm for an empty persister should return 0"
        results.addCallback(self.assertEqual, 0, msg=zeroFailureMessage)

        for entries in (firstEntries, appendedEntries):
            results.addCallback(
                dropResult(self.persister.addNewEntries, entries))

            results.addCallback(
                dropResult(self.persister.getLastTerm))

            failureMessage = 'getLastTerm returned wrong term'

            results.addCallback(self.assertEqual, entries[-1].term,
                                msg=failureMessage)
        return results
Esempio n. 14
0
    def test_committableLogEntries(self):
        '''committableLogEntries should return log entries with indices in the
        range (lastApplied, commitIndex].  An empty persister has no
        committable log entries.

        '''
        results = self.persister.committableLogEntries(0, 100)

        emptyFailureMessage = ('committableLogEntries for an empty'
                               ' persister should return an empty list')
        results.addCallback(self.assertEqual, [], msg=emptyFailureMessage)

        results.addCallback(
            dropResult(self.persister.addNewEntries, firstEntries))

        indices = range(-1, len(firstEntries))
        for lastApplied, commitIndex in itertools.combinations(indices, 2):
            results.addCallback(
                dropResult(self.persister.committableLogEntries,
                           lastApplied, commitIndex))

            def assertEntries(result,
                              lastApplied=lastApplied,
                              commitIndex=commitIndex):
                # convert (,] interval to [,)
                start, stop = lastApplied + 1, commitIndex + 1
                expected = firstEntries[start:stop]

                failureMessage = ('committableLogEntries returned wrong'
                                  ' entries for lastApplied %d and'
                                  ' commitIndex %d' % (lastApplied,
                                                       commitIndex))

                self.assertEqual(result, expected, msg=failureMessage)

            results.addCallback(assertEntries)

        return results
Esempio n. 15
0
    def test_candidateIdOK(self):
        """
        CandidateIdOK should check whether or not we voted
        for another candidate.
        """
        ID = 'someID'
        results = self.state.candidateIdOK(candidateId=ID)

        candidateIDOKFailureMessage = ("new state's candidateIDOK should"
                                       " OK any ID")
        results.addCallback(self.assertTrue, msg=candidateIDOKFailureMessage)

        results.addCallback(dropResult(self.state.persister.votedFor))
        results.addCallback(
            dropResult(self.state.persister.voteFor, 'otherId'))
        results.addCallback(
            dropResult(self.state.candidateIdOK, candidateId=ID))

        candidateIDNotOKFailureMessage = ('candidateIDOK should return'
                                          ' False after state has voted')
        results.addCallback(self.assertFalse,
                            msg=candidateIDNotOKFailureMessage)
        return results
Esempio n. 16
0
    def test_candidateIdOK(self):
        """
        CandidateIdOK should check whether or not we voted
        for another candidate.
        """
        ID = 'someID'
        results = self.state.candidateIdOK(candidateId=ID)

        candidateIDOKFailureMessage = ("new state's candidateIDOK should"
                                       " OK any ID")
        results.addCallback(self.assertTrue, msg=candidateIDOKFailureMessage)

        results.addCallback(dropResult(self.state.persister.votedFor))
        results.addCallback(dropResult(self.state.persister.voteFor,
                                       'otherId'))
        results.addCallback(
            dropResult(self.state.candidateIdOK, candidateId=ID))

        candidateIDNotOKFailureMessage = ('candidateIDOK should return'
                                          ' False after state has voted')
        results.addCallback(self.assertFalse,
                            msg=candidateIDNotOKFailureMessage)
        return results
Esempio n. 17
0
    def test_incrementCurrentTerm(self):
        '''setCurrentTerm should durably increment the currentTerm and return
        it.

        '''
        results = defer.succeed(None)

        for expected in (1, 2, 3):
            results.addCallback(dropResult(self.persister.setCurrentTerm,
                                           None, increment=True))

            incrementFailureMessage = ('setCurrentTerm incremented term'
                                       ' incorrectly')
            results.addCallback(self.assertEqual, expected,
                                msg=incrementFailureMessage)

            results.addCallback(dropResult(self.persister.getCurrentTerm))

            getCurrentTermFailureMessage = ('getCurrentTerm disagreed with'
                                            ' incremented term')
            results.addCallback(self.assertEqual, expected,
                                msg=getCurrentTermFailureMessage)

        return results
Esempio n. 18
0
    def test_getLastIndex(self):
        '''getLastIndex should return the index of the last log entry; an empty
        persister's getLastIndex should return -1.

        '''
        results = self.persister.getLastIndex()

        negOneFailureMessage = ('getLastTerm for an empty persister'
                                ' should return -1')
        results.addCallback(self.assertEqual, -1, msg=negOneFailureMessage)

        lastIndex = -1
        for entries in (firstEntries, appendedEntries):
            lastIndex += len(entries)
            results.addCallback(
                dropResult(self.persister.addNewEntries, entries))

            results.addCallback(
                dropResult(self.persister.getLastIndex))

            failureMessage = 'getLastIndex returned the wrong index'
            results.addCallback(self.assertEqual, lastIndex,
                                msg=failureMessage)
        return results
Esempio n. 19
0
    def test__logSlice(self):
        '''Sanity test for test crutch _logSlice.  _logSlice should return
        log entries between [start, end).

        '''
        results = self.persister._logSlice(0, 1000)

        falseFailure = '_logSlice on empty persister return non-empty list'
        results.addCallback(self.assertFalse, msg=falseFailure)

        results.addCallback(dropResult(self.persister._logSlice, 0, -1))
        results.addCallback(self.assertFalse, msg=falseFailure)

        results.addCallback(dropResult(self.persister.addNewEntries,
                                       firstEntries))
        for gte, lt in itertools.combinations(range(len(firstEntries)), 2):

            def closureCallbacks(gte=gte, lt=lt):
                results.addCallback(
                    dropResult(self.persister._logSlice, gte, lt))

                failureMesage = '_logSlice(%d, %d) returned incorrect list'

                results.addCallback(self.assertEquals,
                                    firstEntries[gte:lt],
                                    msg=failureMesage)

            closureCallbacks()

        results.addCallback(dropResult(self.persister._logSlice, 0, -1))

        fullEntriesFailureMessage = '_logSlice(0, -1) returned incorrect list'
        results.addCallback(self.assertEquals, firstEntries,
                            msg=fullEntriesFailureMessage)

        return results
Esempio n. 20
0
            def closureCallback(prevLogIndex=prevLogIndex):
                results.addCallback(
                    dropResult(self.persister.appendEntriesView, prevLogIndex))

                def verifyView(view):
                    currentTerm = 0
                    prevLogTerm = firstEntries[prevLogIndex].term
                    entries = firstEntries[prevLogIndex + 1:]
                    lastLogIndex = len(firstEntries) - 1
                    expected = persist.AppendEntriesView(currentTerm,
                                                         lastLogIndex,
                                                         prevLogTerm,
                                                         entries)
                    self.assertEqual(view, expected)

                results.addCallback(verifyView)
Esempio n. 21
0
    def test_appendEntriesView(self):
        '''appendEntriesView should return a "view" tuple:

        1) the currentTerm of the persister,
        2) the lastLogIndex of the persister,
        3) the prevLogTerm for the log entry at the provided prevLogIndex,
        4) a list of entries after prevLogIndex.

        For an empty persister, these should be their defaults as above.
        '''

        results = self.persister.appendEntriesView(123)
        emptyExpected = persist.AppendEntriesView(currentTerm=0,
                                                  lastLogIndex=-1,
                                                  prevLogTerm=0,
                                                  entries=[])
        emptyFailureMessage = ('appendEntriesView empty persister returned'
                               ' incorrect AppendEntriesView object')

        results.addCallback(self.assertEqual, emptyExpected,
                            msg=emptyFailureMessage)

        results.addCallback(dropResult(self.persister.addNewEntries,
                                       firstEntries))

        for prevLogIndex in xrange(len(firstEntries)):

            def closureCallback(prevLogIndex=prevLogIndex):
                results.addCallback(
                    dropResult(self.persister.appendEntriesView, prevLogIndex))

                def verifyView(view):
                    currentTerm = 0
                    prevLogTerm = firstEntries[prevLogIndex].term
                    entries = firstEntries[prevLogIndex + 1:]
                    lastLogIndex = len(firstEntries) - 1
                    expected = persist.AppendEntriesView(currentTerm,
                                                         lastLogIndex,
                                                         prevLogTerm,
                                                         entries)
                    self.assertEqual(view, expected)

                results.addCallback(verifyView)
            closureCallback()
        return results
Esempio n. 22
0
    def test_requestVote(self):
        """
        Do I give you a vote? It depends.

        1) Is your term less than mine? If so, the answer is no.
        2) Have I voted for you before, and candidate log is up to date?
        Then yes
        """
        currentTerm = 100
        candidateId = 'ThisCandidate'
        lastLogIndex = 10
        lastLogTerm = currentTerm

        log = []
        for x in xrange(10):
            log.append(rpc_objects.LogEntry(term=currentTerm, command=x))
        results = self.state.persister.setCurrentTerm(currentTerm)
        results.addCallback(
            dropResult(self.state.persister.matchAndAppendNewLogEntries, -1,
                       log))

        # Test for term less then (case 1)
        results.addCallback(
            dropResult(self.state.requestVote,
                       term=currentTerm - 1,
                       candidateId=candidateId,
                       lastLogIndex=lastLogIndex,
                       lastLogTerm=lastLogTerm))

        results.addCallback(self.assertEquals, (currentTerm, False))

        currentTerm += 1

        # Test for success
        results.addCallback(
            dropResult(self.state.requestVote,
                       term=currentTerm,
                       candidateId=candidateId,
                       lastLogIndex=lastLogIndex,
                       lastLogTerm=lastLogTerm))
        results.addCallback(self.assertEquals, (currentTerm, True))
        results.addCallback(
            dropResult(self.assertTrue,
                       isinstance(self.server.state, raft.Follower)))

        # Test for failure (voted before, but fell behind)
        results.addCallback(
            dropResult(self.state.requestVote,
                       term=currentTerm,
                       candidateId=candidateId,
                       lastLogIndex=lastLogIndex,
                       lastLogTerm=lastLogTerm - 1))

        results.addCallback(self.assertEquals, (currentTerm, False))

        # Test for failure (already became follower for this term)
        results.addCallback(
            dropResult(self.state.requestVote,
                       term=currentTerm,
                       candidateId=candidateId,
                       lastLogIndex=lastLogIndex,
                       lastLogTerm=lastLogTerm))

        results.addCallback(self.assertEquals, (currentTerm, False))

        return results
Esempio n. 23
0
    def test_candidateLogUpToDate(self):
        """
        Is the candidate up to date? The term and the index together
        have to be at least as advanced as that of the current machine.

        """

        currentTerm = 100
        log = []
        for x in xrange(10):
            log.append(rpc_objects.LogEntry(term=currentTerm, command=x))
        results = self.state.persister.setCurrentTerm(currentTerm)
        results.addCallback(
            dropResult(self.state.persister.matchAndAppendNewLogEntries, -1,
                       log))

        # Index and term are equal
        results.addCallback(
            dropResult(self.state.candidateLogUpToDate,
                       lastLogIndex=len(log) - 1,
                       lastLogTerm=currentTerm))

        indexAndTermOKFailureMessage = fill(
            '''candidateLogUpToDate should return True when lastLogIndex and
            lastLogTerm are equal to the state's last log index and the
            term of the last log entry.''')
        results.addCallback(self.assertTrue, msg=indexAndTermOKFailureMessage)

        results.addCallback(
            dropResult(self.state.candidateLogUpToDate,
                       lastLogIndex=len(log),
                       lastLogTerm=currentTerm))

        indexIsHigherFailureMessage = fill(
            '''candidateLogUpToDate should return True when lastLogIndex is
            greater than state's last log index and the lastLogTerm is
            equal to the term of the last log entry.''')
        results.addCallback(self.assertTrue, msg=indexIsHigherFailureMessage)

        results.addCallback(
            dropResult(self.state.candidateLogUpToDate,
                       lastLogIndex=len(log) - 1,
                       lastLogTerm=currentTerm + 1))

        termIsHigherFailureMessage = fill(
            '''candidateLogUpToDate should return True when lastLogIndex is
            equal to the state's last log index and the lastLogTerm is
            greater than the term of the last log entry.''')
        results.addCallback(self.assertTrue, msg=termIsHigherFailureMessage)

        results.addCallback(
            dropResult(self.state.candidateLogUpToDate,
                       lastLogIndex=len(log) - 2,
                       lastLogTerm=currentTerm))

        indexIsLowerFailureMessage = fill(
            '''candidateLogUpToDate should return False when lastLogIndex is
            less than the state's last log index''')
        results.addCallback(self.assertFalse, msg=indexIsLowerFailureMessage)

        # # Term is lower
        results.addCallback(
            dropResult(self.state.candidateLogUpToDate,
                       lastLogIndex=len(log),
                       lastLogTerm=currentTerm - 1))

        termIsLowerFailureMessage = fill(
            '''candidateLogUpToDate should return False when lastLogTerm is
            less than the term of the last log entry.''')
        results.addCallback(self.assertFalse, msg=termIsLowerFailureMessage)
        return results
Esempio n. 24
0
    def test_candidateLogUpToDate(self):
        """
        Is the candidate up to date? The term and the index together
        have to be at least as advanced as that of the current machine.

        """

        currentTerm = 100
        log = []
        for x in xrange(10):
            log.append(rpc_objects.LogEntry(term=currentTerm, command=x))
        results = self.state.persister.setCurrentTerm(currentTerm)
        results.addCallback(
            dropResult(self.state.persister.matchAndAppendNewLogEntries,
                       -1, log))

        # Index and term are equal
        results.addCallback(
            dropResult(self.state.candidateLogUpToDate,
                       lastLogIndex=len(log) - 1,
                       lastLogTerm=currentTerm))

        indexAndTermOKFailureMessage = fill(
            '''candidateLogUpToDate should return True when lastLogIndex and
            lastLogTerm are equal to the state's last log index and the
            term of the last log entry.''')
        results.addCallback(self.assertTrue, msg=indexAndTermOKFailureMessage)

        results.addCallback(
            dropResult(self.state.candidateLogUpToDate,
                       lastLogIndex=len(log),
                       lastLogTerm=currentTerm))

        indexIsHigherFailureMessage = fill(
            '''candidateLogUpToDate should return True when lastLogIndex is
            greater than state's last log index and the lastLogTerm is
            equal to the term of the last log entry.''')
        results.addCallback(self.assertTrue, msg=indexIsHigherFailureMessage)

        results.addCallback(
            dropResult(self.state.candidateLogUpToDate,
                       lastLogIndex=len(log) - 1,
                       lastLogTerm=currentTerm + 1))

        termIsHigherFailureMessage = fill(
            '''candidateLogUpToDate should return True when lastLogIndex is
            equal to the state's last log index and the lastLogTerm is
            greater than the term of the last log entry.''')
        results.addCallback(self.assertTrue, msg=termIsHigherFailureMessage)

        results.addCallback(
            dropResult(self.state.candidateLogUpToDate,
                       lastLogIndex=len(log) - 2, lastLogTerm=currentTerm))

        indexIsLowerFailureMessage = fill(
            '''candidateLogUpToDate should return False when lastLogIndex is
            less than the state's last log index''')
        results.addCallback(self.assertFalse, msg=indexIsLowerFailureMessage)

        # # Term is lower
        results.addCallback(
            dropResult(self.state.candidateLogUpToDate,
                       lastLogIndex=len(log), lastLogTerm=currentTerm - 1))

        termIsLowerFailureMessage = fill(
            '''candidateLogUpToDate should return False when lastLogTerm is
            less than the term of the last log entry.''')
        results.addCallback(self.assertFalse, msg=termIsLowerFailureMessage)
        return results
Esempio n. 25
0
    def test_requestVote(self):
        """
        Do I give you a vote? It depends.

        1) Is your term less than mine? If so, the answer is no.
        2) Have I voted for you before, and candidate log is up to date?
        Then yes
        """
        currentTerm = 100
        candidateId = 'ThisCandidate'
        lastLogIndex = 10
        lastLogTerm = currentTerm

        log = []
        for x in xrange(10):
            log.append(rpc_objects.LogEntry(term=currentTerm, command=x))
        results = self.state.persister.setCurrentTerm(currentTerm)
        results.addCallback(
            dropResult(self.state.persister.matchAndAppendNewLogEntries,
                       -1, log))

        # Test for term less then (case 1)
        results.addCallback(
            dropResult(self.state.requestVote,
                       term=currentTerm - 1,
                       candidateId=candidateId,
                       lastLogIndex=lastLogIndex,
                       lastLogTerm=lastLogTerm))

        results.addCallback(self.assertEquals, (currentTerm, False))

        currentTerm += 1

        # Test for success
        results.addCallback(
            dropResult(self.state.requestVote,
                       term=currentTerm,
                       candidateId=candidateId,
                       lastLogIndex=lastLogIndex,
                       lastLogTerm=lastLogTerm))
        results.addCallback(self.assertEquals, (currentTerm, True))
        results.addCallback(dropResult(self.assertTrue,
                                       isinstance(self.server.state,
                                                  raft.Follower)))

        # Test for failure (voted before, but fell behind)
        results.addCallback(
            dropResult(self.state.requestVote,
                       term=currentTerm,
                       candidateId=candidateId,
                       lastLogIndex=lastLogIndex,
                       lastLogTerm=lastLogTerm - 1))

        results.addCallback(self.assertEquals, (currentTerm, False))

        # Test for failure (already became follower for this term)
        results.addCallback(
            dropResult(self.state.requestVote,
                       term=currentTerm,
                       candidateId=candidateId,
                       lastLogIndex=lastLogIndex,
                       lastLogTerm=lastLogTerm))

        results.addCallback(self.assertEquals, (currentTerm, False))

        return results