@Test
  public void testExpireMetaRegionServer() throws Exception {
    SingleProcessHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
    HMaster master = cluster.getMaster();
    RegionStates regionStates = master.getAssignmentManager().getRegionStates();
    ServerName metaServerName =
      regionStates.getRegionServerOfRegion(RegionInfoBuilder.FIRST_META_REGIONINFO);
    if (
      master.getServerName().equals(metaServerName) || metaServerName == null
        || !metaServerName.equals(cluster.getServerHoldingMeta())
    ) {
      // Move meta off master
      metaServerName =
        cluster.getLiveRegionServerThreads().get(0).getRegionServer().getServerName();
      master.move(RegionInfoBuilder.FIRST_META_REGIONINFO.getEncodedNameAsBytes(),
        Bytes.toBytes(metaServerName.getServerName()));
      TEST_UTIL.waitUntilNoRegionsInTransition(60000);
      metaServerName =
        regionStates.getRegionServerOfRegion(RegionInfoBuilder.FIRST_META_REGIONINFO);
    }
    RegionState metaState = MetaTableLocator.getMetaRegionState(master.getZooKeeper());
    assertEquals("Wrong state for meta!", RegionState.State.OPEN, metaState.getState());
    assertNotEquals("Meta is on master!", metaServerName, master.getServerName());
    HRegionServer metaRegionServer = cluster.getRegionServer(metaServerName);

    // Delete the ephemeral node of the meta-carrying region server.
    // This is trigger the expire of this region server on the master.
    String rsEphemeralNodePath = ZNodePaths.joinZNode(master.getZooKeeper().getZNodePaths().rsZNode,
      metaServerName.toString());
    ZKUtil.deleteNode(master.getZooKeeper(), rsEphemeralNodePath);
    LOG.info("Deleted the znode for the RegionServer hosting hbase:meta; waiting on SSH");
    // Wait for SSH to finish
    final ServerManager serverManager = master.getServerManager();
    final ServerName priorMetaServerName = metaServerName;
    TEST_UTIL.waitFor(60000, 100, () -> metaRegionServer.isStopped());
    TEST_UTIL.waitFor(120000, 200, new Waiter.Predicate<Exception>() {
      @Override
      public boolean evaluate() throws Exception {
        return !serverManager.isServerOnline(priorMetaServerName)
          && !serverManager.areDeadServersInProgress();
      }
    });
    LOG.info("Past wait on RIT");
    TEST_UTIL.waitUntilNoRegionsInTransition(60000);
    // Now, make sure meta is assigned
    assertTrue("Meta should be assigned",
      regionStates.isRegionOnline(RegionInfoBuilder.FIRST_META_REGIONINFO));
    // Now, make sure meta is registered in zk
    metaState = MetaTableLocator.getMetaRegionState(master.getZooKeeper());
    assertEquals("Meta should not be in transition", RegionState.State.OPEN, metaState.getState());
    assertEquals("Meta should be assigned", metaState.getServerName(),
      regionStates.getRegionServerOfRegion(RegionInfoBuilder.FIRST_META_REGIONINFO));
    assertNotEquals("Meta should be assigned on a different server", metaState.getServerName(),
      metaServerName);
  }
This test will test the expire handling of a meta-carrying region server. After
HBaseMiniCluster is up, we will delete the ephemeral node of the meta-carrying region server,
which will trigger the expire of this region server on the master. On the other hand, we will
slow down the abort process on the region server so that it is still up during the master SSH.
We will check that the master SSH is still successfully done.
hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMetaShutdownHandler.java