private void executeOpAndVerify(Collection<String> ids, RouterErrorCode expectedErrorCode, boolean advanceTime,
      boolean ignoreUnrecognizedRequests, boolean verifyNoNotificationsOnFailure, boolean verifyTtlAfterUpdate,
      boolean isQuotaRejected) throws Exception {
    FutureResult<Void> future = new FutureResult<>();
    TestCallback<Void> callback = new TestCallback<>();
    notificationSystem.reset();
    List<String> chunkIds = new ArrayList<>(ids);
    router.currentOperationsCount.addAndGet(ids.size() == 1 ? 1 : ids.size() - 1);
    ttlUpdateManager.close();
    ttlUpdateManager.submitTtlUpdateOperation(chunkIds.get(0), chunkIds.subList(1, chunkIds.size()), UPDATE_SERVICE_ID,
        Utils.Infinite_Time, future, callback, quotaChargeCallback);
    sendRequestsGetResponses(future, ttlUpdateManager, advanceTime, ignoreUnrecognizedRequests, isQuotaRejected);
    long expectedTtlSecs = TTL_SECS;
    if (expectedErrorCode == null) {
      assertTrue("Future should be complete", future.isDone());
      assertEquals("Callback should be done", 0, callback.getLatch().getCount());
      if (future.error() != null) {
        throw future.error();
      }
      if (callback.getException() != null) {
        throw callback.getException();
      }
      notificationSystem.checkNotifications(ids.size(), UPDATE_SERVICE_ID, Utils.Infinite_Time);
      expectedTtlSecs = Utils.Infinite_Time;
    } else {
      assertFailureAndCheckErrorCode(future, callback, expectedErrorCode);
      if (verifyNoNotificationsOnFailure) {
        notificationSystem.checkNotifications(0, null, null);
      }
    }
    if (verifyTtlAfterUpdate) {
      assertTtl(router, chunkIds, expectedTtlSecs);
    }
  }
Executes a ttl update operations and verifies results
@param ids the collection of ids to ttl update
@param expectedErrorCode the expected {@link RouterErrorCode} if failure is expected. {@code null} if expected to
                         succeed
@param advanceTime if {@code true}, advances time after each poll and handleResponse iteration
@param ignoreUnrecognizedRequests if {@code true}, doesn't throw an exception if a response is received for a
                                  request not sent in this execution of the function
@param verifyNoNotificationsOnFailure if {@code true}, verifies that there are no notifications on failure.
@param verifyTtlAfterUpdate if {@code true}, verify the TTL after the update succeeds/fails
@param isQuotaRejected if {@code true}, return quota rejected ResponseInfo back to op.
@throws Exception
ambry-router/src/test/java/com/github/ambry/router/TtlUpdateManagerTest.java