@Test
  public void routingTableProviderChangeTest() throws Exception {
    assumeTrue(!useComposite && !overrideEnabled && !listenCrossColo);

    HelixClusterManager helixClusterManager = (HelixClusterManager) clusterManager;
    Map<String, RoutingTableSnapshot> snapshotsByDc = helixClusterManager.getRoutingTableSnapshots();

    // This contains aggregated view snapshot if aggregated view is enabled
    RoutingTableSnapshot localDcSnapshot = snapshotsByDc.get(localDc);

    Set<InstanceConfig> instanceConfigsInSnapshot = new HashSet<>(localDcSnapshot.getInstanceConfigs());
    Set<InstanceConfig> instanceConfigsInCluster =
        useAggregatedView ? new HashSet<>(helixCluster.getInstanceConfigsFromDcs(helixDcs))
            : new HashSet<>(helixCluster.getInstanceConfigsFromDcs(new String[]{localDc}));
    assertEquals("Mismatch in instance configs", instanceConfigsInCluster, instanceConfigsInSnapshot);
    // verify leader replica of each partition is correct in local dc
    verifyLeaderReplicasInDc(helixClusterManager, localDc);
    // verify leader replicas of each partition is correct in remote dc
    verifyLeaderReplicasInDc(helixClusterManager, remoteDc);

    // test live instance triggered routing table change
    // we purposely bring down one instance and wait for expected number of live instance unless times out.
    int initialLiveCnt = localDcSnapshot.getLiveInstances().size();
    MockHelixAdmin localHelixAdmin = helixCluster.getHelixAdminFromDc(localDc);
    String instance = instanceConfigsInCluster.stream()
        .filter(insConfig -> !insConfig.getInstanceName().equals(selfInstanceName))
        .findFirst()
        .get()
        .getInstanceName();
    localHelixAdmin.bringInstanceDown(instance);
    localHelixAdmin.triggerRoutingTableNotification();
    int sleepCnt = 0;
    while (helixClusterManager.getRoutingTableSnapshots().get(localDc).getLiveInstances().size()
        != initialLiveCnt - 1) {
      assertTrue("Routing table change (triggered by bringing down node) didn't come within 1 sec", sleepCnt < 5);
      Thread.sleep(200);
      sleepCnt++;
    }
    // then bring up the same instance, the number of live instances should equal to initial count
    localHelixAdmin.bringInstanceUp(instance);
    localHelixAdmin.triggerLiveInstanceChangeNotification();
    localHelixAdmin.triggerRoutingTableNotification();
    sleepCnt = 0;
    while (helixClusterManager.getRoutingTableSnapshots().get(localDc).getLiveInstances().size() != initialLiveCnt) {
      assertTrue("Routing table change (triggered by bringing up node) didn't come within 1 sec", sleepCnt < 5);
      Thread.sleep(200);
      sleepCnt++;
    }

    // randomly choose a partition and change the leader replica of it in cluster
    List<? extends PartitionId> defaultPartitionIds = helixClusterManager.getAllPartitionIds(DEFAULT_PARTITION_CLASS);
    PartitionId partitionToChange = defaultPartitionIds.get((new Random()).nextInt(defaultPartitionIds.size()));
    String currentLeaderInstance = localHelixAdmin.getPartitionToLeaderReplica().get(partitionToChange.toPathString());
    int currentLeaderPort = Integer.parseInt(currentLeaderInstance.split("_")[1]);
    String newLeaderInstance = localHelixAdmin.getInstancesForPartition(partitionToChange.toPathString())
        .stream()
        .filter(k -> !k.equals(currentLeaderInstance))
        .findFirst()
        .get();
    localHelixAdmin.changeLeaderReplicaForPartition(partitionToChange.toPathString(), newLeaderInstance);
    localHelixAdmin.triggerRoutingTableNotification();
    sleepCnt = 0;
    while (partitionToChange.getReplicaIdsByState(ReplicaState.LEADER, localDc).get(0).getDataNodeId().getPort()
        == currentLeaderPort) {
      assertTrue("Routing table change (triggered by leadership change) didn't come within 1 sec", sleepCnt < 5);
      Thread.sleep(200);
      sleepCnt++;
    }
    verifyLeaderReplicasInDc(helixClusterManager, localDc);
  }
Test that routing table change reflects correct state of each replica and {@link HelixClusterManager} is able to get
replica in required state.
ambry-clustermap/src/test/java/com/github/ambry/clustermap/HelixClusterManagerTest.java