Exemplo n.º 1
0
        public void ShouldBecomeFollowerIfAppendEntriesReceivedFromNewLeader()
        {
            var electionTimeoutInMilliseconds = 1000;

            var initialTerm = 0;
            var outbox      = new ConcurrentBag <object>();
            var eventLog    = new ConcurrentBag <object>();
            var nodeId      = Guid.NewGuid();

            var numberOfOtherActors = 2;

            IEnumerable <Guid> getOtherActors()
            {
                return(Enumerable.Range(0, numberOfOtherActors).Select(_ => Guid.NewGuid()));
            }

            _raftNode = new RaftNode(nodeId, outbox.Add, eventLog.Add, getOtherActors, initialTerm,
                                     electionTimeoutInMilliseconds);

            void BlockUntilTrue(Func <bool> condition)
            {
                while (!condition())
                {
                }
            }

            // Start the node and let it timeout to trigger an election
            _raftNode.Tell(new Initialize());
            eventLog.BlockUntilAny(msg => msg is RoleStateChanged rsc && rsc.Term == initialTerm);

            // Look for the change in state to a candidate node
            Assert.True(eventLog.Count(msg => msg is RoleStateChanged rsc &&
                                       rsc.NewState == RoleState.Candidate &&
                                       rsc.Term == initialTerm) == 1);

            // Send a single heartbeat with a higher term so that the node reverts to
            // a follower state
            var leaderId    = Guid.NewGuid();
            var requesterId = Guid.NewGuid();

            _raftNode.Tell(new Request <AppendEntries>(requesterId,
                                                       new AppendEntries(42, leaderId, 0, 0, new object[0], 0)));

            // Wait for a response
            outbox.BlockUntilAny(msg =>
                                 msg is Response <AppendEntries> response && response.ResponseMessage is AppendEntriesResult ae &&
                                 ae.Term == 42);

            var result = outbox.CastAs <Response <AppendEntries> >().First();

            Assert.IsType <AppendEntriesResult>(result.ResponseMessage);

            var responseMessage = (AppendEntriesResult)result.ResponseMessage;

            Assert.True(responseMessage.Success);

            // There should also be a state change that shows
            // that the candidate node reverted back to a follower state
            eventLog.ShouldHaveAtLeastOne(msg => msg is RoleStateChanged rsc && rsc.NewState == RoleState.Follower && rsc.Term > 42);
        }