private void compactionTest(final TableName tableName, final int flushes,
    final CompactionState expectedState, boolean singleFamily) throws Exception {
    // Create a table with regions
    byte[] family = Bytes.toBytes("family");
    byte[][] families =
      { family, Bytes.add(family, Bytes.toBytes("2")), Bytes.add(family, Bytes.toBytes("3")) };
    createTableWithDefaultConf(tableName, null, families);

    byte[][] singleFamilyArray = { family };

    // When singleFamily is true, only load data for the family being tested. This is to avoid
    // the case that while major compaction is going on for the family, minor compaction could
    // happen for other families at the same time (Two compaction threads long/short), thus
    // pollute the compaction and store file numbers for the region.
    if (singleFamily) {
      loadData(tableName, singleFamilyArray, 3000, flushes);
    } else {
      loadData(tableName, families, 3000, flushes);
    }

    List<Region> regions = new ArrayList<>();
    TEST_UTIL.getHBaseCluster().getLiveRegionServerThreads()
      .forEach(rsThread -> regions.addAll(rsThread.getRegionServer().getRegions(tableName)));
    assertEquals(1, regions.size());

    int countBefore = countStoreFilesInFamilies(regions, families);
    int countBeforeSingleFamily = countStoreFilesInFamily(regions, family);
    assertTrue(countBefore > 0); // there should be some data files
    if (expectedState == CompactionState.MINOR) {
      if (singleFamily) {
        admin.compact(tableName, family).get();
      } else {
        admin.compact(tableName).get();
      }
    } else {
      if (singleFamily) {
        admin.majorCompact(tableName, family).get();
      } else {
        admin.majorCompact(tableName).get();
      }
    }

    long curt = EnvironmentEdgeManager.currentTime();
    long waitTime = 10000;
    long endt = curt + waitTime;
    CompactionState state = admin.getCompactionState(tableName).get();
    while (state == CompactionState.NONE && curt < endt) {
      Thread.sleep(1);
      state = admin.getCompactionState(tableName).get();
      curt = EnvironmentEdgeManager.currentTime();
    }
    // Now, should have the right compaction state,
    // otherwise, the compaction should have already been done
    if (expectedState != state) {
      for (Region region : regions) {
        state = CompactionState.valueOf(region.getCompactionState().toString());
        assertEquals(CompactionState.NONE, state);
      }
    } else {
      // Wait until the compaction is done
      state = admin.getCompactionState(tableName).get();
      while (state != CompactionState.NONE && curt < endt) {
        Thread.sleep(10);
        state = admin.getCompactionState(tableName).get();
      }
      // Now, compaction should be done.
      assertEquals(CompactionState.NONE, state);
    }

    int countAfter = countStoreFilesInFamilies(regions, families);
    int countAfterSingleFamily = countStoreFilesInFamily(regions, family);
    assertTrue(countAfter < countBefore);
    if (!singleFamily) {
      if (expectedState == CompactionState.MAJOR) {
        assertEquals(families.length, countAfter);
      } else {
        assertTrue(families.length <= countAfter);
      }
    } else {
      int singleFamDiff = countBeforeSingleFamily - countAfterSingleFamily;
      // assert only change was to single column family
      assertEquals(singleFamDiff, (countBefore - countAfter));
      if (expectedState == CompactionState.MAJOR) {
        assertEquals(1, countAfterSingleFamily);
      } else {
        assertTrue("" + countAfterSingleFamily, 1 <= countAfterSingleFamily);
      }
    }
  }
Class to test asynchronous region admin operations.
@see TestAsyncRegionAdminApi2 This test and it used to be joined it was taking longer than our
     ten minute timeout so they were split.
hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncRegionAdminApi.java