Package org.robotninjas.barge.state

Source Code of org.robotninjas.barge.state.CandidateTest

package org.robotninjas.barge.state;

import com.google.common.base.Optional;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import org.jetlang.fibers.Fiber;
import org.jetlang.fibers.FiberStub;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.robotninjas.barge.ClusterConfig;
import org.robotninjas.barge.ClusterConfigStub;
import org.robotninjas.barge.Replica;
import org.robotninjas.barge.StateMachine;
import org.robotninjas.barge.api.AppendEntries;
import org.robotninjas.barge.api.RequestVote;
import org.robotninjas.barge.api.RequestVoteResponse;
import org.robotninjas.barge.log.RaftLog;
import org.robotninjas.barge.rpc.Client;

import java.util.concurrent.ScheduledFuture;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.*;
import static org.robotninjas.barge.state.Raft.StateType.CANDIDATE;
import static org.robotninjas.barge.state.Raft.StateType.LEADER;

public class CandidateTest {

  private final long term = 2L;

  private Fiber scheduler = new FiberStub();
  private @Mock Replica mockReplica;
  private final ClusterConfig config = ClusterConfigStub.getStub();
  private final Replica self = config.local();
  private @Mock Client mockRaftClient;
  private @Mock StateMachine mockStateMachine;
  private @Mock RaftLog mockRaftLog;
  private @Mock RaftStateContext mockRaftStateContext;

  @Before
  public void initMocks() {

    MockitoAnnotations.initMocks(this);

    when(mockRaftLog.self()).thenReturn(self);
    when(mockRaftLog.votedFor()).thenReturn(Optional.<Replica>absent());
    when(mockRaftLog.lastLogTerm()).thenReturn(0L);
    when(mockRaftLog.lastLogIndex()).thenReturn(0L);
    when(mockRaftLog.currentTerm()).thenReturn(term);
    when(mockRaftLog.config()).thenReturn(config);
    when(mockRaftLog.getReplica(anyString())).thenAnswer(new Answer<Replica>() {
      @Override
      public Replica answer(InvocationOnMock invocation) throws Throwable {
        String arg = (String) invocation.getArguments()[0];
        return config.getReplica(arg);
      }
    });

    ScheduledFuture mockScheduledFuture = mock(ScheduledFuture.class);

    when(mockRaftStateContext.type()).thenReturn(CANDIDATE);

    RequestVoteResponse response = RequestVoteResponse.newBuilder().setTerm(0).setVoteGranted(true).build();
    ListenableFuture<RequestVoteResponse> responseFuture = Futures.immediateFuture(response);
    when(mockRaftClient.requestVote(any(Replica.class), any(RequestVote.class))).thenReturn(responseFuture);
  }

  @Test
  public void testRequestVoteWithNewerTerm() throws Exception {

    Candidate candidate = new Candidate(mockRaftLog, scheduler, 150, mockRaftClient);
    candidate.init(mockRaftStateContext);

    Replica mockCandidate = config.getReplica("other");

    RequestVote request =
      RequestVote.newBuilder()
        .setCandidateId(mockCandidate.toString())
        .setLastLogIndex(1L)
        .setLastLogTerm(1L)
        .setTerm(4L)
        .build();

    candidate.requestVote(mockRaftStateContext, request);

    verify(mockRaftLog).currentTerm(3L);
    verify(mockRaftLog).currentTerm(4L);
    verify(mockRaftLog, times(2)).currentTerm(anyLong());

    verify(mockRaftLog).votedFor(Optional.of(self));
    verify(mockRaftLog).votedFor(Optional.of(mockCandidate));
    verify(mockRaftLog, times(2)).votedFor(any(Optional.class));

    verify(mockRaftLog, never()).commitIndex(anyLong());

    verify(mockRaftStateContext, times(1)).setState(any(Candidate.class), eq(Raft.StateType.FOLLOWER));
    verify(mockRaftStateContext, times(1)).setState(any(Candidate.class), eq(Raft.StateType.LEADER));

    verifyZeroInteractions(mockRaftClient);

  }

  @Test
  public void testRequestVoteWithOlderTerm() throws Exception {
    Candidate candidate = new Candidate(mockRaftLog, scheduler, 150, mockRaftClient);
    candidate.init(mockRaftStateContext);

    Replica mockCandidate = config.getReplica("other");

    RequestVote request =
      RequestVote.newBuilder()
        .setCandidateId(mockCandidate.toString())
        .setLastLogIndex(1L)
        .setLastLogTerm(1L)
        .setTerm(1L)
        .build();

    candidate.requestVote(mockRaftStateContext, request);

    verify(mockRaftLog).currentTerm(3L);
    verify(mockRaftLog, times(1)).currentTerm(anyLong());

    verify(mockRaftLog).votedFor(Optional.of(self));
    verify(mockRaftLog, never()).votedFor(Optional.of(mockCandidate));
    verify(mockRaftLog, times(1)).votedFor(any(Optional.class));

    verify(mockRaftLog, never()).commitIndex(anyLong());

    verify(mockRaftStateContext).setState(any(Candidate.class), eq(Raft.StateType.LEADER));

    verifyZeroInteractions(mockRaftClient);
  }

  @Test
  public void testRequestVoteWithSameTerm() throws Exception {
    Candidate candidate = new Candidate(mockRaftLog, scheduler, 150, mockRaftClient);
    candidate.init(mockRaftStateContext);

    Replica mockCandidate = config.getReplica("other");

    RequestVote request =
      RequestVote.newBuilder()
        .setCandidateId(mockCandidate.toString())
        .setLastLogIndex(1L)
        .setLastLogTerm(1L)
        .setTerm(2L)
        .build();

    candidate.requestVote(mockRaftStateContext, request);

    verify(mockRaftLog).currentTerm(3L);
    verify(mockRaftLog, times(1)).currentTerm(anyLong());

    verify(mockRaftLog).votedFor(Optional.of(self));
    verify(mockRaftLog, times(1)).votedFor(Optional.of(mockCandidate));
    verify(mockRaftLog, times(2)).votedFor(any(Optional.class));

    verify(mockRaftLog, never()).commitIndex(anyLong());

    verify(mockRaftStateContext).setState(any(State.class), any(RaftStateContext.StateType.class));

    verifyZeroInteractions(mockRaftStateContext);

    verifyZeroInteractions(mockRaftClient);
  }

  @Test
  public void testAppendEntriesWithNewerTerm() throws Exception {

    Candidate candidate = new Candidate(mockRaftLog, scheduler, 1, mockRaftClient);
    candidate.init(mockRaftStateContext);

    Replica mockLeader = config.getReplica("other");

    AppendEntries request =
      AppendEntries.newBuilder()
        .setTerm(4L)
        .setLeaderId(mockLeader.toString())
        .setPrevLogIndex(1L)
        .setPrevLogTerm(1L)
        .setCommitIndex(1L)
        .build();

    candidate.appendEntries(mockRaftStateContext, request);

    verify(mockRaftLog).currentTerm(3L);
    verify(mockRaftLog).currentTerm(4L);
    verify(mockRaftLog, times(2)).currentTerm(anyLong());

    verify(mockRaftLog).votedFor(Optional.of(self));
    verify(mockRaftLog, times(1)).votedFor(any(Optional.class));

    verify(mockRaftLog, times(1)).commitIndex(anyLong());

    verify(mockRaftStateContext).setState(any(Candidate.class), eq(Raft.StateType.FOLLOWER));
    verify(mockRaftStateContext).setState(any(Candidate.class), eq(Raft.StateType.LEADER));

    verifyZeroInteractions(mockRaftClient);

  }

  @Test
  public void testAppendEntriesWithOlderTerm() throws Exception {

    Candidate candidate = new Candidate(mockRaftLog, scheduler, 1, mockRaftClient);
    candidate.init(mockRaftStateContext);

    Replica mockLeader = config.getReplica("other");

    AppendEntries request =
      AppendEntries.newBuilder()
        .setTerm(1L)
        .setLeaderId(mockLeader.toString())
        .setPrevLogIndex(1L)
        .setPrevLogTerm(1L)
        .setCommitIndex(1L)
        .build();

    candidate.appendEntries(mockRaftStateContext, request);

    verify(mockRaftLog).currentTerm(3L);
    verify(mockRaftLog, times(1)).currentTerm(anyLong());

    verify(mockRaftLog).votedFor(Optional.of(self));
    verify(mockRaftLog, times(1)).votedFor(any(Optional.class));

    verify(mockRaftLog, never()).commitIndex(anyLong());

    verify(mockRaftStateContext).setState(any(Candidate.class), eq(Raft.StateType.LEADER));

    verifyZeroInteractions(mockRaftClient);

  }

  @Test
  public void testAppendEntriesWithSameTerm() throws Exception {

    Candidate candidate = new Candidate(mockRaftLog, scheduler, 1, mockRaftClient);
    candidate.init(mockRaftStateContext);

    AppendEntries request =
      AppendEntries.newBuilder()
        .setTerm(2L)
        .setLeaderId("leader:1000")
        .setPrevLogIndex(1L)
        .setPrevLogTerm(1L)
        .setCommitIndex(1L)
        .build();

    candidate.appendEntries(mockRaftStateContext, request);

    verify(mockRaftLog).currentTerm(3L);
    verify(mockRaftLog, times(1)).currentTerm(anyLong());

    verify(mockRaftLog).votedFor(Optional.of(self));
    verify(mockRaftLog, times(1)).votedFor(any(Optional.class));

    verify(mockRaftLog, times(1)).commitIndex(anyLong());

    verify(mockRaftStateContext).setState(any(Candidate.class), eq(LEADER));

    verifyZeroInteractions(mockRaftClient);

  }

}
TOP

Related Classes of org.robotninjas.barge.state.CandidateTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.