@Test
  public void testRemoveMemberExceptions() {
    createGroup(2);
    ReplicatedEnvironment master = repEnvInfo[0].getEnv();
    assertTrue(master.getState().isMaster());

    RepNode masterRep = repEnvInfo[0].getRepNode();
    try {
      masterRep.removeMember(master.getNodeName());
      fail("Exception expected.");
    } catch (MasterStateException e) {
      // Expected
    }

    try {
      masterRep.removeMember("unknown node foobar");
      fail("Exception expected.");
    } catch (MemberNotFoundException e) {
      // Expected
    }

    masterRep.removeMember(repEnvInfo[1].getRepNode().getNodeName());
    try {
      masterRep.removeMember(repEnvInfo[1].getRepNode().getNodeName());
      fail("Exception expected.");
    } catch (MemberNotFoundException e) {
      // Expected
    }
    repEnvInfo[1].closeEnv();
  }
    @Override
    protected void preLogCommitHook() {
      super.preLogCommitHook();
      RepNode rmMasterNode = repEnvInfo[0].getRepNode();
      int size = rmMasterNode.getGroup().getAllElectableMembers().size();
      int delNodes = ((size & 1) == 1) ? 2 : 1;
      int closeNodeIndex = (size - delNodes) - 1;

      /*
       * The loop below simulates the concurrent removal of a node while
       * a transaction is in progress. It deletes a sufficient number of
       * nodes so as to get a lower simple nodes to get to a new lower
       * simple majority.
       */
      for (int i = repEnvInfo.length - 1; delNodes-- > 0; i--) {
        repEnvInfo[i].closeEnv();
        rmMasterNode.removeMember(repEnvInfo[i].getRepConfig().getNodeName(), delete);
      }

      /*
       * Shut down an additional undeleted Replica to provoke a
       * lack of acks based on the old simple majority.
       */
      repEnvInfo[closeNodeIndex].closeEnv();
    }
  /*
   * Tests internal node removal APIs.
   */
  @Test
  public void testRemoveMember() {
    createGroup(groupSize);
    ReplicatedEnvironment master = repEnvInfo[0].getEnv();
    assertTrue(master.getState().isMaster());

    RepNode masterRep = repEnvInfo[0].getRepNode();

    /* Reduce the group size all the way down to one. */
    for (int i = 1; i < groupSize; i++) {
      assertTrue(!RepInternal.isClosed(repEnvInfo[i].getEnv()));
      masterRep.removeMember(repEnvInfo[i].getEnv().getNodeName());
      assertEquals((groupSize - i), masterRep.getGroup().getElectableGroupSize());
    }

    /* Close the replica handles*/
    for (int i = groupSize - 1; i > 0; i--) {
      repEnvInfo[i].closeEnv();
    }

    /* Attempting to re-open them with the same node names should fail. */
    for (int i = 1; i < groupSize; i++) {
      try {
        repEnvInfo[i].openEnv();
        fail("Exception expected");
      } catch (EnvironmentFailureException e) {
        /* Expected, the master should reject the attempt. */
        assertEquals(EnvironmentFailureReason.HANDSHAKE_ERROR, e.getReason());
      }
    }

    /* Doing the same but with different node names should be ok. */
    for (int i = 1; i < groupSize; i++) {
      final RepEnvInfo ri = repEnvInfo[i];
      final ReplicationConfig repConfig = ri.getRepConfig();
      TestUtils.removeLogFiles("RemoveRepEnvironments", ri.getEnvHome(), false);

      repConfig.setNodeName("ReplaceNode_" + i);
      ri.openEnv();
      assertEquals(i + 1, masterRep.getGroup().getElectableGroupSize());
    }
    master.close();
  }
  /*
   * Tests internal node deletion APIs.
   */
  @Test
  public void testDeleteMember() {
    createGroup(groupSize);
    ReplicatedEnvironment master = repEnvInfo[0].getEnv();
    assertTrue(master.getState().isMaster());

    RepNode masterRep = repEnvInfo[0].getRepNode();

    /* Reduce the group size all the way down to one. */
    for (int i = 1; i < groupSize; i++) {
      assertTrue(!RepInternal.isClosed(repEnvInfo[i].getEnv()));
      final String delName = repEnvInfo[i].getEnv().getNodeName();
      repEnvInfo[i].closeEnv();
      masterRep.removeMember(delName, true);
      assertEquals((groupSize - i), masterRep.getGroup().getElectableGroupSize());
    }

    /*
     * Attempting to re-open them with the same node names should succeed
     */
    for (int i = 1; i < groupSize; i++) {
      repEnvInfo[i].openEnv();
    }
  }