@Test
  public void moveReplicaTest() throws Exception {
    // create a HelixClusterManager with DynamicClusterChangeHandler
    Properties properties = new Properties();
    properties.putAll(props);
    ClusterMapConfig clusterMapConfig = new ClusterMapConfig(new VerifiableProperties(properties));
    HelixClusterManager helixClusterManager =
        new HelixClusterManager(clusterMapConfig, selfInstanceName, helixManagerFactory, new MetricRegistry());
    // pick a partition and move one of its replicas
    Partition testPartition =
        (Partition) testPartitionLayout.getPartitionLayout().getRandomWritablePartition(null, null);
    int previousReplicaCnt = testPartition.getReplicaIds().size();
    // 1. find out nodes in local dc that host this partition
    List<DataNodeId> localDcNodes = getPartitionDataNodesFromDc(testPartition, localDc);
    // 2. then find a node in local dc that doesn't host this partition (this is the node we will add replica to)
    Datacenter localDatacenter = testHardwareLayout.getHardwareLayout()
        .getDatacenters()
        .stream()
        .filter(dc -> dc.getName().equals(localDc))
        .findFirst()
        .get();
    // since we didn't populate bootstrap replica map, we have to avoid adding replica to currentNode
    DataNode nodeToAddReplica = localDatacenter.getDataNodes()
        .stream()
        .filter(node -> !localDcNodes.contains(node) && node != currentNode)
        .findFirst()
        .get();
    testPartitionLayout.addReplicaToPartition(nodeToAddReplica, testPartition);
    Utils.writeJsonObjectToFile(testPartitionLayout.getPartitionLayout().toJSONObject(), partitionLayoutPath);
    // 3. We upgrade helix by adding new replica to the chosen node in local dc. This is to mock "replica addition" on
    //    chosen node and chosen node updates its instanceConfig in Helix. There should be 7 (= 6+1) replicas in the
    //    intermediate state.
    helixCluster.upgradeWithNewPartitionLayout(partitionLayoutPath,
        HelixBootstrapUpgradeUtil.HelixAdminOperation.BootstrapCluster);
    PartitionId partitionInManager = helixClusterManager.getAllPartitionIds(null)
        .stream()
        .filter(p -> p.toPathString().equals(testPartition.toPathString()))
        .findFirst()
        .get();
    assertEquals("Replica count of testing partition is not correct", previousReplicaCnt + 1,
        partitionInManager.getReplicaIds().size());
    // 4. find a replica (from same partition) in local dc that is not just added one
    Replica oldReplica = (Replica) testPartition.getReplicaIds()
        .stream()
        .filter(r -> r.getDataNodeId().getDatacenterName().equals(localDc) && r.getDataNodeId() != nodeToAddReplica)
        .findFirst()
        .get();
    testPartitionLayout.removeReplicaFromPartition(oldReplica);
    Utils.writeJsonObjectToFile(testPartitionLayout.getPartitionLayout().toJSONObject(), partitionLayoutPath);
    // 5. disable the replica in Helix to mock replica decommission which will remove it from InstanceConfig but keep it
    //    in IdealState temporarily.
    helixCluster.upgradeWithNewPartitionLayout(partitionLayoutPath,
        HelixBootstrapUpgradeUtil.HelixAdminOperation.DisablePartition);
    Set<ReplicaId> replicasInDifferentStates = new HashSet<>();
    for (ReplicaState state : EnumSet.of(ReplicaState.STANDBY, ReplicaState.LEADER, ReplicaState.OFFLINE,
        ReplicaState.INACTIVE, ReplicaState.BOOTSTRAP)) {
      replicasInDifferentStates.addAll(partitionInManager.getReplicaIdsByState(state, null));
    }
    // verify there is no null replica
    replicasInDifferentStates.forEach(r -> assertNotNull("found null replica", r));
    // 6. updates the IdealState in Helix. The number of replicas should become 6 again.
    helixCluster.upgradeWithNewPartitionLayout(partitionLayoutPath,
        HelixBootstrapUpgradeUtil.HelixAdminOperation.UpdateIdealState);
    assertEquals("Replica count of testing partition is not correct", previousReplicaCnt,
        partitionInManager.getReplicaIds().size());

    helixClusterManager.close();
  }
Test the case where a current replica is moved between existing nodes.
ambry-clustermap/src/test/java/com/github/ambry/clustermap/ClusterChangeHandlerTest.java