private void runDropPartitions(int partCount, int batchSize, int maxRetries, int exceptionStatus)
    throws Exception {
    IMetaStoreClient spyDb = spy(db);

    // create partCount dummy partitions
    Set<PartitionResult> partsNotInFs = dropPartsNotInFs(partCount);

    // Expected number of dropPartitions call
    int expectedCallCount = maxRetries;

    // Expected number of partitions dropped in each of those calls
    int[] expectedBatchSizes;

    // Last batch can sometimes have less number of elements
    int lastBatchSize = batchSize;

    // Actual Batch size that will be used
    int actualBatchSize = batchSize;

    if (exceptionStatus == oneException) {
      // After one exception everything is expected to run
      actualBatchSize = batchSize / 2;
    }

    if (exceptionStatus != allException) {
      expectedCallCount = partCount / actualBatchSize;

      if (expectedCallCount * actualBatchSize < partCount) {
        // partCount not equally divided into batches.  last batch size will be less than batch size
        lastBatchSize = partCount - (expectedCallCount * actualBatchSize);

        // Add 1 to counter default rounding
        expectedCallCount++;
      }

      if (exceptionStatus == oneException) {
        // first one will fail - count it in
        expectedCallCount++;

        // only first call throws exception
        doThrow(MetaException.class).doCallRealMethod().doCallRealMethod().when(spyDb)
            .dropPartitions(eq(table.getCatName()), eq(table.getDbName()),
            eq(table.getTableName()), anyList(), any(PartitionDropOptions.class));
      }

      expectedBatchSizes = new int[expectedCallCount];

      // first batch is always based on batch size
      expectedBatchSizes[0] = Integer.min(partCount, batchSize);

      // second batch to last but one batch will be actualBatchSize
      // actualBatchSize is same as batchSize when no exceptions are expected
      // actualBatchSize is half of batchSize when 1 exception is expected
      for (int i = 1; i < expectedCallCount - 1; i++) {
        expectedBatchSizes[i] = Integer.min(partCount, actualBatchSize);
      }

      expectedBatchSizes[expectedCallCount - 1] = lastBatchSize;

      // batch size from input and decaying factor of 2
      msck.dropPartitionsInBatches(spyDb, repairOutput, partsNotInFs, null, table, batchSize, 2,
        maxRetries);
    } else {
      if (maxRetries == 0) {
        // Retries will be done till decaying factor reduces to 0.  Decaying Factor is 2.
        // So, log to base 2 of batchSize plus 1 or Most Significant Bit
        // of batchsize plus 1 will give the number of expected calls
        expectedCallCount = findMSB(batchSize) + 1;
      }
      expectedBatchSizes = new int[expectedCallCount];

      // decaying where the batchSize keeps reducing by half
      for (int i = 0; i < expectedCallCount; i++) {
        actualBatchSize = batchSize / (int) Math.pow(2, i);
        expectedBatchSizes[i] = Integer.min(partCount, actualBatchSize);
      }
      // all calls fail
      doThrow(MetaException.class).when(spyDb)
          .dropPartitions(eq(table.getCatName()), eq(table.getDbName()), eq(table.getTableName()),
            anyList(), any(PartitionDropOptions.class));

      Exception ex = null;
      try {
        msck.dropPartitionsInBatches(spyDb, repairOutput, partsNotInFs, null, table, batchSize, 2,
          maxRetries);
      } catch (Exception retryEx) {
        ex = retryEx;
      }
      Assert.assertFalse("Exception was expected but was not thrown", ex == null);
      Assert.assertTrue("Unexpected class of exception thrown", ex instanceof RetryUtilities.RetryException);
    }

    // there should be expectedCallCount calls to drop partitions with each batch size of
    // actualBatchSize
    ArgumentCaptor<List> argument = ArgumentCaptor.forClass(List.class);
    verify(spyDb, times(expectedCallCount))
        .dropPartitions(eq(table.getCatName()), eq(table.getDbName()), eq(table.getTableName()),
        argument.capture(), any(PartitionDropOptions.class));

    // confirm the batch sizes were as expected
    List<List> droppedParts = argument.getAllValues();

    assertEquals(expectedCallCount, droppedParts.size());
    for (int i = 0; i < expectedCallCount; i++) {
      List<Pair<Integer, byte[]>> actualArgs = droppedParts.get(i);
      int actualPartitionSize = actualArgs.get(0).getLeft();
      Assert.assertEquals(
        String.format("Unexpected batch size in attempt %d.  Expected: %d.  Found: %d", i + 1,
          expectedBatchSizes[i], actualPartitionSize),
        expectedBatchSizes[i], actualPartitionSize);
    }
  }
Unit test for function dropPartitionsInBatches in DDLTask.
ql/src/test/org/apache/hadoop/hive/ql/exec/TestMsckDropPartitionsInBatches.java