@Test
  public void testMasterShutdownBeforeStartingAnyRegionServer() throws Exception {
    LocalHBaseCluster hbaseCluster = null;
    try {
      htu = new HBaseTestingUtil(createMasterShutdownBeforeStartingAnyRegionServerConfiguration());

      // configure a cluster with
      final StartTestingClusterOption options = StartTestingClusterOption.builder().numDataNodes(1)
        .numMasters(1).numRegionServers(0).masterClass(HMaster.class)
        .rsClass(SingleProcessHBaseCluster.MiniHBaseClusterRegionServer.class).createRootDir(true)
        .build();

      // Can't simply `htu.startMiniCluster(options)` because that method waits for the master to
      // start completely. However, this test's premise is that a partially started master should
      // still respond to a shutdown RPC. So instead, we manage each component lifecycle
      // independently.
      // I think it's not worth refactoring HTU's helper methods just for this class.
      htu.startMiniDFSCluster(options.getNumDataNodes());
      htu.startMiniZKCluster(options.getNumZkServers());
      htu.createRootDir();
      hbaseCluster = new LocalHBaseCluster(htu.getConfiguration(), options.getNumMasters(),
        options.getNumRegionServers(), options.getMasterClass(), options.getRsClass());
      final MasterThread masterThread = hbaseCluster.getMasters().get(0);

      masterThread.start();
      // Switching to master registry exacerbated a race in the master bootstrap that can result
      // in a lost shutdown command (HBASE-8422, HBASE-23836). The race is essentially because
      // the server manager in HMaster is not initialized by the time shutdown() RPC (below) is
      // made to the master. The suspected reason as to why it was uncommon before HBASE-18095
      // is because the connection creation with ZK registry is so slow that by then the server
      // manager is usually init'ed in time for the RPC to be made. For now, adding an explicit
      // wait() in the test, waiting for the server manager to become available.
      final long timeout = TimeUnit.MINUTES.toMillis(10);
      assertNotEquals("timeout waiting for server manager to become available.", -1,
        htu.waitFor(timeout, () -> masterThread.getMaster().getServerManager() != null));

      // Master has come up far enough that we can terminate it without creating a zombie.
      try {
        // HBASE-24327 : (Resolve Flaky connection issues)
        // shutdown() RPC can have flaky ZK connection issues.
        // e.g
        // ERROR [RpcServer.priority.RWQ.Fifo.read.handler=1,queue=1,port=53033]
        // master.HMaster(2878): ZooKeeper exception trying to set cluster as down in ZK
        // org.apache.zookeeper.KeeperException$SystemErrorException:
        // KeeperErrorCode = SystemError
        //
        // However, even when above flakes happen, shutdown call does get completed even if
        // RPC call has failure. Hence, subsequent retries will never succeed as HMaster is
        // already shutdown. Hence, it can fail. To resolve it, after making one shutdown()
        // call, we are ignoring IOException.
        htu.getConnection().getAdmin().shutdown();
      } catch (RetriesExhaustedException e) {
        if (e.getCause() instanceof ConnectionClosedException) {
          LOG.info("Connection is Closed to the cluster. The cluster is already down.", e);
        } else {
          throw e;
        }
      }
      LOG.info("Shutdown RPC sent.");
      masterThread.join();
    } finally {
      if (hbaseCluster != null) {
        hbaseCluster.shutdown();
      }
      if (htu != null) {
        htu.shutdownMiniCluster();
        htu = null;
      }
    }
  }
This test appears to be an intentional race between a thread that issues a shutdown RPC to the
master, while the master is concurrently realizing it cannot initialize because there are no
region servers available to it. The expected behavior is that master initialization is
interruptable via said shutdown RPC.
hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterShutdown.java