public async Task when_a_candidate_recieves_a_vote_response_from_a_node_with_a_higher_term_number_then_that_candidate_steps_down()
        {
            var peerObservable = new Subject <IEnumerable <Peer> >();
            var testScheduler  = new VirtualScheduler();
            var nodes          = TestNode.CreateCluster(peerObservable: peerObservable, scheduler: testScheduler);
            var leader         = nodes.First();

            testScheduler.AdvanceBy(TestNode.ElectionTimeout);
            await leader.StartElection();

            leader.StepDown(2, "none");
            testScheduler.AdvanceBy(TestNode.ElectionTimeout);
            nodes.LogStatus();
            await leader.StartElection();

            leader.State.Should().Be(State.Leader);
            nodes.ForEach(n => n.Term.Should().Be(3));

            var candidateThatsBehind = TestNode.CreateTestNode("candidateThatsBehind", peerObservable, testScheduler);

            nodes.Add(candidateThatsBehind);
            peerObservable.OnNext(nodes.Select(n => n.AsPeer()));
            testScheduler.AdvanceBy(TestNode.ElectionTimeout.Ticks * 2);
            await candidateThatsBehind.StartElection();

            leader.State.Should().Be(State.Leader);
            candidateThatsBehind.Term.Should().Be(3);
            candidateThatsBehind.State.Should().Be(State.Follower, "the node should have immediatly stepped down because it attempted to start an election for term 2 but the cluster was on term 3");
        }
        public async Task when_a_cluster_already_has_a_leader_if_an_usurper_node_attempts_an_election_it_fails()
        {
            var peerObservable = new Subject <IEnumerable <Peer> >();
            var nodes          = TestNode.CreateCluster(peerObservable: peerObservable);
            var leader         = nodes.First();
            await leader.StartElection();

            var usurper = TestNode.CreateTestNode("usurper", peerObservable);

            nodes.Add(usurper);
            peerObservable.OnNext(nodes.Select(n => n.AsPeer()));
            await usurper.StartElection();

            leader.State.Should().Be(State.Leader);
            usurper.State.Should().Be(State.Candidate, "the node should remain a candidate and continue trying elections until it is contacted by a leader");
        }
        public async Task when_a_candidate_recieves_an_AppendEntries_from_a_leader_that_candidate_becomes_a_follower()
        {
            var peerObservable = new Subject <IEnumerable <Peer> >();
            var nodes          = TestNode.CreateCluster(peerObservable: peerObservable);
            var leader         = nodes.First();
            await leader.StartElection();

            var usurper = TestNode.CreateTestNode("usurper", peerObservable);

            nodes.Add(usurper);
            peerObservable.OnNext(nodes.Select(n => n.AsPeer()));
            await usurper.StartElection();

            leader.State.Should().Be(State.Leader);
            usurper.State.Should().Be(State.Candidate);

            await leader.SendHeartBeat();

            usurper.State.Should().Be(State.Follower);
        }