@Test
  public void originatingDcNotFoundWithOneReplicaInBootstrap() {
    List<Port> portList = Collections.singletonList(new Port(PORT, PortType.PLAINTEXT));
    List<String> mountPaths = Collections.singletonList("mockMountPath");
    datanodes = Collections.singletonList(new MockDataNodeId(portList, mountPaths, "dc-0"));
    mockPartition = new MockPartitionId();
    populateReplicaList(1, ReplicaState.BOOTSTRAP);
    ReplicaId bootstrapReplica = mockPartition.getReplicaIds().get(0);
    populateReplicaList(2, ReplicaState.STANDBY);
    localDcName = datanodes.get(0).getDatacenterName();
    mockClusterMap = new MockClusterMap(false, datanodes, 1, Collections.singletonList(mockPartition), localDcName);
    originatingDcName = localDcName;
    Properties props = new Properties();
    props.setProperty(RouterConfig.ROUTER_GET_SUCCESS_TARGET, Integer.toString(1));
    props.setProperty(RouterConfig.ROUTER_GET_REQUEST_PARALLELISM, Integer.toString(3));

    // Case 1: When we are searching in all replicas
    OperationTracker ot = getOperationTracker(props, true, 3, RouterOperation.GetBlobOperation, true, true);
    sendRequests(ot, 3, false);
    ot.onResponse(inflightReplicas.poll(), TrackedRequestFinalState.NOT_FOUND);
    ot.onResponse(inflightReplicas.poll(), TrackedRequestFinalState.NOT_FOUND);
    ot.onResponse(inflightReplicas.poll(), TrackedRequestFinalState.NOT_FOUND);
    assertFalse("Operation should not succeed", ot.hasSucceeded());
    assertTrue("Operation should fail on NOT_FOUND since all replicas return NOT_FOUND", ot.hasFailedOnNotFound());
    assertTrue("Operation should have some unavailability", ot.hasSomeUnavailability());
    assertTrue("Operation should be done", ot.isDone());

    // Case 2.1: Search minimum needed replicas - first 2 not found responses are from standby replicas.
    repetitionTracker.clear();
    inflightReplicas.clear();
    props.setProperty(RouterConfig.ROUTER_OPERATION_TRACKER_CHECK_ALL_ORIGINATING_REPLICAS_FOR_NOT_FOUND,
        Boolean.toString(false));
    ot = getOperationTracker(props, true, 3, RouterOperation.GetBlobOperation, true, true);
    sendRequests(ot, 3, false);
    LinkedList<ReplicaId> bootStrapReplicaList = new LinkedList<>();
    LinkedList<ReplicaId> standbyReplicaList = new LinkedList<>();
    for (int i = 0; i < 3; i++) {
      ReplicaId replicaId = inflightReplicas.poll();
      if (replicaId.equals(bootstrapReplica)) {
        bootStrapReplicaList.add(replicaId);
      } else {
        standbyReplicaList.add(replicaId);
      }
    }
    ot.onResponse(standbyReplicaList.poll(), TrackedRequestFinalState.NOT_FOUND);
    ot.onResponse(standbyReplicaList.poll(), TrackedRequestFinalState.NOT_FOUND);
    assertFalse("Operation should not succeed", ot.hasSucceeded());
    assertTrue("Operation should fail with NOT_FOUND", ot.hasFailedOnNotFound());
    assertTrue("Operation should have been done", ot.isDone());

    // Case 2.2: Search minimum needed replicas - receive 1 response from bootstrap first and standby later.
    repetitionTracker.clear();
    inflightReplicas.clear();
    props.setProperty(RouterConfig.ROUTER_OPERATION_TRACKER_CHECK_ALL_ORIGINATING_REPLICAS_FOR_NOT_FOUND,
        Boolean.toString(false));
    ot = getOperationTracker(props, true, 3, RouterOperation.GetBlobOperation, true, true);
    sendRequests(ot, 3, false);
    for (int i = 0; i < 3; i++) {
      ReplicaId replicaId = inflightReplicas.poll();
      if (replicaId.equals(bootstrapReplica)) {
        bootStrapReplicaList.add(replicaId);
      } else {
        standbyReplicaList.add(replicaId);
      }
    }
    // Send 1 response from bootstrap replica and 1 from standby. Operation should not complete since first NOT_FOUND is
    // from a bootstrap replica
    ot.onResponse(bootStrapReplicaList.poll(), TrackedRequestFinalState.NOT_FOUND);
    ot.onResponse(standbyReplicaList.poll(), TrackedRequestFinalState.NOT_FOUND);
    assertFalse("Operation should not succeed", ot.hasSucceeded());
    assertFalse("Operation should not fail with NOT_FOUND", ot.hasFailedOnNotFound());
    assertFalse("Operation should not have been done", ot.isDone());
    // After receiving 3 response, operation would complete with 404.
    ot.onResponse(standbyReplicaList.poll(), TrackedRequestFinalState.NOT_FOUND);
    assertTrue("Operation should fail with NOT_FOUND", ot.hasFailedOnNotFound());
    assertTrue("Operation should be done", ot.isDone());
  }
Test hasFailedOnFound() when 1 originating replica is in bootstrap stage.
ambry-router/src/test/java/com/github/ambry/router/OperationTrackerTest.java