/**
   * Unit test for the protocol up to a service join, which triggers a leader election. Since the
   * singleton quorum has only one member our client will be elected the leader.
   *
   * @throws InterruptedException
   */
  public void test_serviceJoin() throws InterruptedException {

    final AbstractQuorum<?, ?> quorum = quorums[0];
    final MockQuorumMember<?> client = clients[0];
    final QuorumActor<?, ?> actor = actors[0];
    final UUID serviceId = client.getServiceId();

    final long lastCommitTime = 0L;
    final long lastCommitTime2 = 2L;

    // declare the service as a quorum member.
    actor.memberAdd();
    fixture.awaitDeque();

    assertTrue(client.isMember());
    assertEquals(new UUID[] {serviceId}, quorum.getMembers());

    // add to the pipeline.
    actor.pipelineAdd();
    fixture.awaitDeque();

    assertTrue(client.isPipelineMember());
    assertEquals(new UUID[] {serviceId}, quorum.getPipeline());

    // cast a vote for a lastCommitTime.
    actor.castVote(lastCommitTime);
    fixture.awaitDeque();

    assertEquals(1, quorum.getVotes().size());
    assertEquals(new UUID[] {serviceId}, quorum.getVotes().get(lastCommitTime));

    // verify the consensus was updated.
    assertEquals(lastCommitTime, client.lastConsensusValue);

    // wait for quorum meet.
    final long token1 = quorum.awaitQuorum();

    // verify service was joined.
    assertTrue(client.isJoinedMember(quorum.token()));
    assertEquals(new UUID[] {serviceId}, quorum.getJoined());

    // validate the token was assigned.
    fixture.awaitDeque();
    assertEquals(Quorum.NO_QUORUM + 1, quorum.lastValidToken());
    assertEquals(Quorum.NO_QUORUM + 1, quorum.token());
    assertTrue(quorum.isQuorumMet());

    /*
     * Do service leave, quorum should break.
     */

    actor.serviceLeave();
    fixture.awaitDeque();

    quorum.awaitBreak();

    // vote was withdrawn.
    assertEquals(0, quorum.getVotes().size());
    assertEquals(null, quorum.getVotes().get(lastCommitTime));

    // verify the consensus was updated.
    assertEquals(-1L, client.lastConsensusValue);

    assertFalse(quorum.isQuorumMet());
    assertEquals(Quorum.NO_QUORUM, quorum.token());
    assertEquals(token1, quorum.lastValidToken());
    assertFalse(client.isJoinedMember(quorum.token()));
    assertEquals(new UUID[] {}, quorum.getJoined());
    assertFalse(client.isPipelineMember());
    assertEquals(new UUID[] {}, quorum.getPipeline());

    /*
     * Cast another vote, the quorum should meet again.
     */

    actor.pipelineAdd();
    fixture.awaitDeque();

    actor.castVote(lastCommitTime2);
    fixture.awaitDeque();

    assertEquals(1, quorum.getVotes().size());
    assertEquals(null, quorum.getVotes().get(lastCommitTime));
    assertEquals(new UUID[] {serviceId}, quorum.getVotes().get(lastCommitTime2));

    // verify the consensus was updated.
    assertEquals(lastCommitTime2, client.lastConsensusValue);

    // await meet.
    final long token2 = quorum.awaitQuorum();

    // verify the joined services.
    assertEquals(new UUID[] {serviceId}, quorum.getJoined());

    // validate the token was assigned by the leader.
    assertTrue(quorum.isQuorumMet());
    assertEquals(token1 + 1, token2);
    assertEquals(token1 + 1, quorum.lastValidToken());
    assertTrue(client.isJoinedMember(token2));
    assertTrue(client.isLeader(token2));
    assertFalse(client.isFollower(token2));

    /*
     * Do service leave, quorum should break again.
     */

    actor.serviceLeave();
    fixture.awaitDeque();

    quorum.awaitBreak();

    // vote was withdrawn.
    assertEquals(0, quorum.getVotes().size());
    assertEquals(null, quorum.getVotes().get(lastCommitTime));
    assertEquals(null, quorum.getVotes().get(lastCommitTime2));

    // verify the consensus was updated.
    assertEquals(-1L, client.lastConsensusValue);

    assertFalse(quorum.isQuorumMet());
    assertEquals(Quorum.NO_QUORUM, quorum.token());
    assertEquals(token2, quorum.lastValidToken());
    assertFalse(client.isJoinedMember(quorum.token()));
    assertEquals(new UUID[] {}, quorum.getJoined());
    assertFalse(client.isPipelineMember());
    assertEquals(new UUID[] {}, quorum.getPipeline());
  }