@Test
  public void TestIncBackupMergeRestore() throws Exception {
    int ADD_ROWS = 99;
    // #1 - create full backup for all tables
    LOG.info("create full backup image for all tables");

    List<TableName> tables = Lists.newArrayList(table1, table2);
    // Set custom Merge Job implementation
    conf1.setClass(BackupRestoreFactory.HBASE_BACKUP_MERGE_IMPL_CLASS,
      BackupMergeJobWithFailures.class, BackupMergeJob.class);

    Connection conn = ConnectionFactory.createConnection(conf1);

    Admin admin = conn.getAdmin();
    BackupAdminImpl client = new BackupAdminImpl(conn);

    BackupRequest request = createBackupRequest(BackupType.FULL, tables, BACKUP_ROOT_DIR);
    String backupIdFull = client.backupTables(request);

    assertTrue(checkSucceeded(backupIdFull));

    // #2 - insert some data to table1
    Table t1 = insertIntoTable(conn, table1, famName, 1, ADD_ROWS);
    LOG.debug("writing " + ADD_ROWS + " rows to " + table1);

    Assert.assertEquals(TEST_UTIL.countRows(t1), NB_ROWS_IN_BATCH + ADD_ROWS);
    t1.close();
    LOG.debug("written " + ADD_ROWS + " rows to " + table1);

    Table t2 = insertIntoTable(conn, table2, famName, 1, ADD_ROWS);

    Assert.assertEquals(TEST_UTIL.countRows(t2), NB_ROWS_IN_BATCH + ADD_ROWS);
    t2.close();
    LOG.debug("written " + ADD_ROWS + " rows to " + table2);

    // #3 - incremental backup for multiple tables
    tables = Lists.newArrayList(table1, table2);
    request = createBackupRequest(BackupType.INCREMENTAL, tables, BACKUP_ROOT_DIR);
    String backupIdIncMultiple = client.backupTables(request);

    assertTrue(checkSucceeded(backupIdIncMultiple));

    t1 = insertIntoTable(conn, table1, famName, 2, ADD_ROWS);
    t1.close();

    t2 = insertIntoTable(conn, table2, famName, 2, ADD_ROWS);
    t2.close();

    // #3 - incremental backup for multiple tables
    request = createBackupRequest(BackupType.INCREMENTAL, tables, BACKUP_ROOT_DIR);
    String backupIdIncMultiple2 = client.backupTables(request);
    assertTrue(checkSucceeded(backupIdIncMultiple2));
    // #4 Merge backup images with failures

    for (FailurePhase phase : FailurePhase.values()) {
      Configuration conf = conn.getConfiguration();

      conf.set(FAILURE_PHASE_KEY, phase.toString());

      try (BackupAdmin bAdmin = new BackupAdminImpl(conn)) {
        String[] backups = new String[] { backupIdIncMultiple, backupIdIncMultiple2 };
        bAdmin.mergeBackups(backups);
        Assert.fail("Expected IOException");
      } catch (IOException e) {
        BackupSystemTable table = new BackupSystemTable(conn);
        if (phase.ordinal() < FailurePhase.PHASE4.ordinal()) {
          // No need to repair:
          // Both Merge and backup exclusive operations are finished
          assertFalse(table.isMergeInProgress());
          try {
            table.finishBackupExclusiveOperation();
            Assert.fail("IOException is expected");
          } catch (IOException ee) {
            // Expected
          }
        } else {
          // Repair is required
          assertTrue(table.isMergeInProgress());
          try {
            table.startBackupExclusiveOperation();
            Assert.fail("IOException is expected");
          } catch (IOException ee) {
            // Expected - clean up before proceeding
            // table.finishMergeOperation();
            // table.finishBackupExclusiveOperation();
          }
        }
        table.close();
        LOG.debug("Expected :" + e.getMessage());
      }
    }
    // Now merge w/o failures
    Configuration conf = conn.getConfiguration();
    conf.unset(FAILURE_PHASE_KEY);
    conf.unset(BackupRestoreFactory.HBASE_BACKUP_MERGE_IMPL_CLASS);
    // Now run repair
    BackupSystemTable sysTable = new BackupSystemTable(conn);
    BackupCommands.RepairCommand.repairFailedBackupMergeIfAny(conn, sysTable);
    // Now repeat merge
    try (BackupAdmin bAdmin = new BackupAdminImpl(conn)) {
      String[] backups = new String[] { backupIdIncMultiple, backupIdIncMultiple2 };
      bAdmin.mergeBackups(backups);
    }

    // #6 - restore incremental backup for multiple tables, with overwrite
    TableName[] tablesRestoreIncMultiple = new TableName[] { table1, table2 };
    TableName[] tablesMapIncMultiple = new TableName[] { table1_restore, table2_restore };
    client.restore(BackupUtils.createRestoreRequest(BACKUP_ROOT_DIR, backupIdIncMultiple2, false,
      tablesRestoreIncMultiple, tablesMapIncMultiple, true));

    Table hTable = conn.getTable(table1_restore);
    LOG.debug("After incremental restore: " + hTable.getDescriptor());
    LOG.debug("f1 has " + TEST_UTIL.countRows(hTable, famName) + " rows");
    Assert.assertEquals(TEST_UTIL.countRows(hTable, famName), NB_ROWS_IN_BATCH + 2 * ADD_ROWS);

    hTable.close();

    hTable = conn.getTable(table2_restore);
    Assert.assertEquals(TEST_UTIL.countRows(hTable), NB_ROWS_IN_BATCH + 2 * ADD_ROWS);
    hTable.close();

    admin.close();
    conn.close();
  }
This is the exact copy of parent's run() with injections of different types of failures
hbase-backup/src/test/java/org/apache/hadoop/hbase/backup/TestIncrementalBackupMergeWithFailures.java