private void compaction(final String tableName, final int flushes,
    final CompactionState expectedState, boolean singleFamily, StateSource stateSource)
    throws IOException, InterruptedException {
    // Create a table with regions
    TableName table = TableName.valueOf(tableName);
    byte[] family = Bytes.toBytes("family");
    byte[][] families =
      { family, Bytes.add(family, Bytes.toBytes("2")), Bytes.add(family, Bytes.toBytes("3")) };
    Table ht = null;
    try {
      ht = TEST_UTIL.createTable(table, families);
      loadData(ht, families, 3000, flushes);
      HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
      HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster();
      List<HRegion> regions = rs.getRegions(table);
      int countBefore = countStoreFilesInFamilies(regions, families);
      int countBeforeSingleFamily = countStoreFilesInFamily(regions, family);
      assertTrue(countBefore > 0); // there should be some data files
      Admin admin = TEST_UTIL.getAdmin();
      if (expectedState == CompactionState.MINOR) {
        if (singleFamily) {
          admin.compact(table, family);
        } else {
          admin.compact(table);
        }
      } else {
        if (singleFamily) {
          admin.majorCompact(table, family);
        } else {
          admin.majorCompact(table);
        }
      }
      long curt = EnvironmentEdgeManager.currentTime();
      long waitTime = 5000;
      long endt = curt + waitTime;
      CompactionState state = getCompactionState(stateSource, master, admin, table);
      while (state == CompactionState.NONE && curt < endt) {
        Thread.sleep(10);
        state = getCompactionState(stateSource, master, admin, table);
        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 = getCompactionState(stateSource, master, admin, table);
        while (state != CompactionState.NONE && curt < endt) {
          Thread.sleep(10);
          state = getCompactionState(stateSource, master, admin, table);
        }
        // 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) assertTrue(families.length == countAfter);
        else assertTrue(families.length < countAfter);
      } else {
        int singleFamDiff = countBeforeSingleFamily - countAfterSingleFamily;
        // assert only change was to single column family
        assertTrue(singleFamDiff == (countBefore - countAfter));
        if (expectedState == CompactionState.MAJOR) {
          assertTrue(1 == countAfterSingleFamily);
        } else {
          assertTrue(1 < countAfterSingleFamily);
        }
      }
    } finally {
      if (ht != null) {
        TEST_UTIL.deleteTable(table);
      }
    }
  }
Load data to a table, flush it to disk, trigger compaction, confirm the compaction state is
right and wait till it is done.
@param singleFamily otherwise, run compaction on all cfs
@param stateSource  get the state by Admin or Master
hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestCompactionState.java