@Test
  public void testMetaMigration() throws Exception {
    LOG.info("Starting testMetaMigration");
    final byte[] FAMILY = Bytes.toBytes("family");
    HTableDescriptor htd = new HTableDescriptor("testMetaMigration");
    HColumnDescriptor hcd = new HColumnDescriptor(FAMILY);
    htd.addFamily(hcd);
    Configuration conf = TEST_UTIL.getConfiguration();
    byte[][] regionNames =
        new byte[][] {
          HConstants.EMPTY_START_ROW, Bytes.toBytes("region_a"), Bytes.toBytes("region_b")
        };
    createMultiRegionsWithWritableSerialization(conf, htd.getName(), regionNames);
    CatalogTracker ct = TEST_UTIL.getMiniHBaseCluster().getMaster().getCatalogTracker();
    // Erase the current version of root meta for this test.
    undoVersionInRoot(ct);
    MetaReader.fullScanMetaAndPrint(ct);
    LOG.info("Meta Print completed.testMetaMigration");

    long numMigratedRows =
        MetaMigrationConvertingToPB.updateMeta(TEST_UTIL.getHBaseCluster().getMaster());
    MetaReader.fullScanMetaAndPrint(ct);

    // Should be one entry only and it should be for the table we just added.
    assertEquals(regionNames.length, numMigratedRows);

    // Assert that the flag in ROOT is updated to reflect the correct status
    boolean metaUpdated =
        MetaMigrationConvertingToPB.isMetaTableUpdated(
            TEST_UTIL.getMiniHBaseCluster().getMaster().getCatalogTracker());
    assertEquals(true, metaUpdated);
    verifyMetaRowsAreUpdated(ct);
  }
  /**
   * This test assumes a master crash/failure during the meta migration process and attempts to
   * continue the meta migration process when a new master takes over. When a master dies during the
   * meta migration we will have some rows of META.CatalogFamily updated with PB serialization and
   * some still hanging with writable serialization. When the backup master/ or fresh start of
   * master attempts the migration it will encounter some rows of META already updated with new HRI
   * and some still legacy. This test will simulate this scenario and validates that the migration
   * process can safely skip the updated rows and migrate any pending rows at startup.
   *
   * @throws Exception
   */
  @Test
  public void testMasterCrashDuringMetaMigration() throws Exception {
    final byte[] FAMILY = Bytes.toBytes("family");
    HTableDescriptor htd = new HTableDescriptor("testMasterCrashDuringMetaMigration");
    HColumnDescriptor hcd = new HColumnDescriptor(FAMILY);
    htd.addFamily(hcd);
    Configuration conf = TEST_UTIL.getConfiguration();
    // Create 10 New regions.
    createMultiRegionsWithPBSerialization(conf, htd.getName(), 10);
    // Create 10 Legacy regions.
    createMultiRegionsWithWritableSerialization(conf, htd.getName(), 10);
    CatalogTracker ct = TEST_UTIL.getMiniHBaseCluster().getMaster().getCatalogTracker();
    // Erase the current version of root meta for this test.
    undoVersionInRoot(ct);

    MetaReader.fullScanMetaAndPrint(ct);
    LOG.info("Meta Print completed.testUpdatesOnMetaWithLegacyHRI");

    long numMigratedRows =
        MetaMigrationConvertingToPB.updateMetaIfNecessary(TEST_UTIL.getHBaseCluster().getMaster());
    assertEquals(numMigratedRows, 10);

    // Assert that the flag in ROOT is updated to reflect the correct status
    boolean metaUpdated =
        MetaMigrationConvertingToPB.isMetaTableUpdated(
            TEST_UTIL.getMiniHBaseCluster().getMaster().getCatalogTracker());
    assertEquals(true, metaUpdated);

    verifyMetaRowsAreUpdated(ct);

    LOG.info("END testMasterCrashDuringMetaMigration");
  }
 @Test
 public void testMetaUpdatedFlagInROOT() throws Exception {
   HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster();
   boolean metaUpdated =
       MetaMigrationConvertingToPB.isMetaTableUpdated(master.getCatalogTracker());
   assertEquals(true, metaUpdated);
   verifyMetaRowsAreUpdated(master.getCatalogTracker());
 }
  /** Verify that every META row is updated */
  void verifyMetaRowsAreUpdated(CatalogTracker catalogTracker) throws IOException {
    List<Result> results = MetaReader.fullScan(catalogTracker);
    assertTrue(results.size() >= REGION_COUNT);

    for (Result result : results) {
      byte[] hriBytes = result.getValue(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER);
      assertTrue(hriBytes != null && hriBytes.length > 0);
      assertTrue(MetaMigrationConvertingToPB.isMigrated(hriBytes));

      byte[] splitA = result.getValue(HConstants.CATALOG_FAMILY, HConstants.SPLITA_QUALIFIER);
      if (splitA != null && splitA.length > 0) {
        assertTrue(MetaMigrationConvertingToPB.isMigrated(splitA));
      }

      byte[] splitB = result.getValue(HConstants.CATALOG_FAMILY, HConstants.SPLITB_QUALIFIER);
      if (splitB != null && splitB.length > 0) {
        assertTrue(MetaMigrationConvertingToPB.isMigrated(splitB));
      }
    }
  }