public void failedDueToOfflineReplicaTest(RouterOperation routerOperation) {
    assumeTrue(operationTrackerType.equals(SIMPLE_OP_TRACKER));
    assumeTrue(replicasStateEnabled);
    int replicaCount = 9;
    int successTarget = 2;
    int requestParallelism = 2;
    List<Boolean> includeDownReplicaValues = Arrays.asList(true, false);
    for (boolean includeDownReplicas : includeDownReplicaValues) {
      for (int notFoundCount = 9; notFoundCount >= 0; notFoundCount--) {
        int remainingReplicas = replicaCount - notFoundCount;
        for (int foundCount = remainingReplicas; foundCount >= 0; foundCount--) {
          int offlineCount = remainingReplicas - foundCount;
          if (replicaCount - offlineCount < successTarget) {
            // if there are not enough online replicas, then creation operation tracker will fail.
            continue;
          }
          List<Port> portList = Collections.singletonList(new Port(PORT, PortType.PLAINTEXT));
          List<String> mountPaths = Collections.singletonList("mockMountPath");
          datanodes = new ArrayList<>(Arrays.asList(new MockDataNodeId(portList, mountPaths, "dc-0"),
              new MockDataNodeId(portList, mountPaths, "dc-1"), new MockDataNodeId(portList, mountPaths, "dc-2"),
              new MockDataNodeId(portList, mountPaths, "dc-3")));
          mockPartition = new MockPartitionId();
          List<Pair<Integer, ReplicaState>> replicaStateCountPairList = new ArrayList<>();
          replicaStateCountPairList.add(new Pair<Integer, ReplicaState>(offlineCount, ReplicaState.OFFLINE));
          replicaStateCountPairList.add(
              new Pair<Integer, ReplicaState>(replicaCount - offlineCount, ReplicaState.STANDBY));
          populateReplicaList(replicaStateCountPairList);
          localDcName = datanodes.get(0).getDatacenterName();
          mockClusterMap =
              new MockClusterMap(false, datanodes, 1, Collections.singletonList(mockPartition), localDcName);
          OperationTracker ot;
          switch (routerOperation) {
            case DeleteOperation:
              ot =
                  getOperationTrackerForDelete(true, successTarget, requestParallelism, RouterOperation.DeleteOperation,
                      true, false);
              break;
            case TtlUpdateOperation:
              ot =
                  getOperationTrackerForTtl(true, successTarget, requestParallelism, RouterOperation.TtlUpdateOperation,
                      true);
              break;
            default:
              fail(String.format("Operation %s not supported", routerOperation.name()));
              return;
          }
          int sentRequestCount = 0;
          int notFoundCounter = 0;
          int foundCounter = 0;
          while (sentRequestCount < replicaCount - offlineCount) {
            int requestsToSend = Math.min((replicaCount - offlineCount - sentRequestCount), requestParallelism);
            sentRequestCount += requestsToSend;
            sendRequests(ot, requestsToSend, false);
            while (requestsToSend > 0) {
              if (notFoundCounter < notFoundCount) {
                ot.onResponse(inflightReplicas.poll(), TrackedRequestFinalState.NOT_FOUND);
                notFoundCounter++;
              } else if (foundCounter < foundCount) {
                ot.onResponse(inflightReplicas.poll(), TrackedRequestFinalState.SUCCESS);
                foundCounter++;
              }
              requestsToSend--;
            }
          }
          assertTrue(String.format("Operation should be done for notfoundcount: %d, offlinecount: %d, foundcount: %s",
              notFoundCount, offlineCount, foundCount), ot.isDone());
          if (foundCount >= successTarget) {
            assertTrue(
                String.format("Operation should be successful for notfoundcount: %d, offlinecount: %d, foundcount: %s",
                    notFoundCount, offlineCount, foundCount), ot.hasSucceeded());
            assertFalse(String.format(
                "Operation should not have failed on not found for notfoundcount: %d, offlinecount: %d, foundcount: %s",
                notFoundCount, offlineCount, foundCount), ot.hasFailedOnNotFound());
          } else {
            assertFalse(
                String.format("Operation should have failed for notfoundcount: %d, offlinecount: %d, foundcount: %s",
                    notFoundCount, offlineCount, foundCount), ot.hasSucceeded());
            assertTrue(String.format(
                "Operation should have failed on not found for notfoundcount: %d, offlinecount: %d, foundcount: %s",
                notFoundCount, offlineCount, foundCount), ot.hasFailedOnNotFound());
          }
        }
      }
    }
  }
Test {@link OperationTracker} fail logic for the specified {@link RouterOperation}.
@param routerOperation {@link RouterOperation} to test.
ambry-router/src/test/java/com/github/ambry/router/OperationTrackerTest.java