예제 #1
0
  public void testCandidateVotesForSelfOnRequest() throws Throwable {
    runOnServer(
        () -> {
          int self = serverState.getAddress().hashCode();
          serverState.setTerm(2);

          state.startElection();

          assertEquals(serverState.getTerm(), 3L);

          VoteRequest request =
              VoteRequest.builder()
                  .withTerm(3)
                  .withCandidate(self)
                  .withLogIndex(0)
                  .withLogTerm(0)
                  .build();

          VoteResponse response = state.vote(request).get();

          assertEquals(response.status(), Response.Status.OK);
          assertTrue(response.voted());
          assertEquals(serverState.getTerm(), 3L);
          assertEquals(serverState.getLastVotedFor(), self);
          assertEquals(response.term(), 3L);
        });
  }
예제 #2
0
  public void testCandidateRejectsVoteAndTransitionsOnTerm() throws Throwable {
    runOnServer(
        () -> {
          int candidate =
              serverState.getCluster().getActiveMembers().iterator().next().getAddress().hashCode();
          serverState.setTerm(1);

          append(2, 1);

          state.startElection();

          assertEquals(serverState.getTerm(), 2L);

          VoteRequest request =
              VoteRequest.builder()
                  .withTerm(3)
                  .withCandidate(candidate)
                  .withLogTerm(0)
                  .withLogIndex(0)
                  .build();

          VoteResponse response = state.vote(request).get();

          assertEquals(response.status(), Response.Status.OK);
          assertFalse(response.voted());
          assertEquals(serverState.getTerm(), 3L);
          assertEquals(serverState.getLastVotedFor(), 0);
          assertEquals(response.term(), 3L);
          assertEquals(serverState.getState(), RaftServer.State.FOLLOWER);
        });
  }
예제 #3
0
  @SuppressWarnings("unchecked")
  public void testAppendUpdatesLeaderAndTerm() throws Throwable {
    runOnServer(
        () -> {
          serverContext.setTerm(1);
          AppendRequest request =
              AppendRequest.builder()
                  .withTerm(2)
                  .withLeader(members.get(1).hashCode())
                  .withEntries(Collections.EMPTY_LIST)
                  .withLogIndex(0)
                  .withLogTerm(0)
                  .withCommitIndex(0)
                  .withGlobalIndex(0)
                  .build();

          AppendResponse response = state.append(request).get();

          threadAssertEquals(serverContext.getTerm(), 2L);
          threadAssertEquals(
              serverContext.getLeader().serverAddress(), members.get(1).serverAddress());
          threadAssertEquals(serverContext.getLastVotedFor(), 0);
          threadAssertEquals(response.term(), 2L);
          threadAssertTrue(response.succeeded());
        });
  }
예제 #4
0
  @SuppressWarnings("unchecked")
  public void testAppendTermAndLeaderUpdated() throws Throwable {
    runOnServer(
        () -> {
          int leader =
              serverContext
                  .getClusterState()
                  .getActiveMemberStates()
                  .iterator()
                  .next()
                  .getMember()
                  .id();
          serverContext.setTerm(1);
          AppendRequest request =
              AppendRequest.builder()
                  .withTerm(2)
                  .withLeader(leader)
                  .withEntries(Collections.EMPTY_LIST)
                  .withCommitIndex(0)
                  .withGlobalIndex(0)
                  .build();

          AppendResponse response = state.append(request).get();

          assertEquals(response.status(), Status.OK);
          assertTrue(response.succeeded());
          assertEquals(serverContext.getTerm(), 2L);
          assertEquals(serverContext.getLeader().hashCode(), leader);
          assertEquals(response.term(), 2L);
        });
  }
예제 #5
0
  public void testAppendOnNonEmptyLog() throws Throwable {
    runOnServer(
        () -> {
          serverContext.setTerm(1);
          append(1, 1);

          AppendRequest request =
              AppendRequest.builder()
                  .withTerm(1)
                  .withLeader(
                      serverContext
                          .getClusterState()
                          .getActiveMemberStates()
                          .iterator()
                          .next()
                          .getMember()
                          .id())
                  .withLogIndex(0)
                  .withLogTerm(0)
                  .withCommitIndex(2)
                  .withGlobalIndex(0)
                  .withEntries(new TestEntry().setIndex(2).setTerm(1))
                  .build();

          AppendResponse response = state.append(request).get();

          assertEquals(response.status(), Status.OK);
          assertTrue(response.succeeded());
          assertEquals(response.term(), 1L);
          assertEquals(response.logIndex(), 2L);

          assertEquals(serverContext.getLog().length(), 2L);
          assertNotNull(get(2));
        });
  }
예제 #6
0
  @SuppressWarnings("unchecked")
  public void testRejectAppendOnTerm() throws Throwable {
    runOnServer(
        () -> {
          serverContext.setTerm(2);
          append(2, 2);

          AppendRequest request =
              AppendRequest.builder()
                  .withTerm(1)
                  .withLeader(
                      serverContext
                          .getClusterState()
                          .getActiveMemberStates()
                          .iterator()
                          .next()
                          .getMember()
                          .id())
                  .withEntries(Collections.EMPTY_LIST)
                  .withLogIndex(2)
                  .withLogTerm(2)
                  .withCommitIndex(0)
                  .withGlobalIndex(0)
                  .build();

          AppendResponse response = state.append(request).get();

          assertEquals(response.status(), Status.OK);
          assertFalse(response.succeeded());
          assertEquals(response.term(), 2L);
          assertEquals(response.logIndex(), 2L);
        });
  }
예제 #7
0
 public void testLeaveWithoutLeader() throws Throwable {
   runOnServer(
       () -> {
         LeaveRequest request = LeaveRequest.builder().withMember(members.get(0)).build();
         LeaveResponse response = state.leave(request).get();
         assertNoLeaderError(response);
       });
 }
예제 #8
0
 public void testJoinWithoutLeader() throws Throwable {
   runOnServer(
       () -> {
         JoinRequest request = JoinRequest.builder().withMember(members.get(0)).build();
         JoinResponse response = state.join(request).get();
         assertNoLeaderError(response);
       });
 }
예제 #9
0
 public void testQueryWithoutLeader() throws Throwable {
   runOnServer(
       () -> {
         QueryRequest request =
             QueryRequest.builder().withSession(1).withQuery(new TestQuery()).build();
         QueryResponse response = state.query(request).get();
         assertNoLeaderError(response);
       });
 }
예제 #10
0
 public void testCommandWithoutLeader() throws Throwable {
   runOnServer(
       () -> {
         CommandRequest request =
             CommandRequest.builder().withSession(1).withCommand(new TestCommand("test")).build();
         CommandResponse response = state.command(request).get();
         assertNoLeaderError(response);
       });
 }
예제 #11
0
  public void testCandidateIncrementsTermVotesForSelfOnElection() throws Throwable {
    runOnServer(
        () -> {
          int self = serverState.getAddress().hashCode();
          serverState.setTerm(2);

          state.startElection();

          assertEquals(serverState.getTerm(), 3L);
          assertEquals(serverState.getLastVotedFor(), self);
        });
  }
예제 #12
0
  public void testCandidateTransitionsToFollowerOnRejection() throws Throwable {
    serverState.onStateChange(
        state -> {
          if (state == RaftServer.State.FOLLOWER) resume();
        });

    runOnServer(
        () -> {
          for (MemberState member : serverState.getCluster().getActiveMembers()) {
            Server server = transport.server();
            server
                .listen(
                    member.getAddress(),
                    c -> {
                      c.handler(
                          VoteRequest.class,
                          request ->
                              CompletableFuture.completedFuture(
                                  VoteResponse.builder().withTerm(2).withVoted(false).build()));
                    })
                .thenRunAsync(this::resume);
          }
        });

    await(1000, serverState.getCluster().getActiveMembers().size());

    runOnServer(
        () -> {
          int self = serverState.getAddress().hashCode();
          serverState.setTerm(1);

          state.startElection();

          assertEquals(serverState.getTerm(), 2L);
          assertEquals(serverState.getLastVotedFor(), self);
        });
    await(1000);
  }
예제 #13
0
 public void testVote() throws Throwable {
   runOnServer(
       () -> {
         VoteRequest request =
             VoteRequest.builder()
                 .withCandidate(1)
                 .withLogIndex(1)
                 .withLogTerm(1)
                 .withTerm(1)
                 .build();
         VoteResponse response = state.vote(request).get();
         assertIllegalMemberStateError(response);
       });
 }
예제 #14
0
  public void testCandidateAppendAndTransitionOnTerm() throws Throwable {
    runOnServer(
        () -> {
          int leader =
              serverState.getCluster().getActiveMembers().iterator().next().getAddress().hashCode();
          serverState.setTerm(1);
          AppendRequest request =
              AppendRequest.builder()
                  .withTerm(2)
                  .withLeader(leader)
                  .withCommitIndex(0)
                  .withGlobalIndex(0)
                  .build();

          AppendResponse response = state.append(request).get();

          assertEquals(response.status(), Response.Status.OK);
          assertTrue(response.succeeded());
          assertEquals(serverState.getTerm(), 2L);
          assertEquals(serverState.getLeader().hashCode(), leader);
          assertEquals(response.term(), 2L);
          assertEquals(serverState.getState(), RaftServer.State.FOLLOWER);
        });
  }