You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2019/12/05 01:04:45 UTC

[lucene-solr] branch jira/solr14003 created (now f51d7f3)

This is an automated email from the ASF dual-hosted git repository.

noble pushed a change to branch jira/solr14003
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git.


      at f51d7f3  added A ReplicaStateProvider interface and changed CollectionStatePredicate to use it

This branch includes the following new commits:

     new f51d7f3  added A ReplicaStateProvider interface and changed CollectionStatePredicate to use it

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[lucene-solr] 01/01: added A ReplicaStateProvider interface and changed CollectionStatePredicate to use it

Posted by no...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

noble pushed a commit to branch jira/solr14003
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit f51d7f3c87c46868c5139443d2e718b86ce90ceb
Author: noble <no...@apache.org>
AuthorDate: Thu Dec 5 12:04:20 2019 +1100

    added A ReplicaStateProvider interface and changed CollectionStatePredicate to use it
---
 .../src/java/org/apache/solr/cloud/CloudUtil.java  |  8 ++--
 .../autoscaling/sim/SimClusterStateProvider.java   |  2 +-
 .../solr/handler/admin/CollectionsHandler.java     |  4 +-
 .../apache/solr/handler/admin/PrepRecoveryOp.java  |  2 +-
 .../client/solrj/impl/ConnectionReuseTest.java     |  4 +-
 .../apache/solr/cloud/BasicDistributedZkTest.java  |  4 +-
 .../org/apache/solr/cloud/CleanupOldIndexTest.java |  2 +-
 .../cloud/CloudExitableDirectoryReaderTest.java    |  2 +-
 .../solr/cloud/CollectionStateFormat2Test.java     |  4 +-
 .../apache/solr/cloud/CollectionsAPISolrJTest.java | 43 +++++++++---------
 .../solr/cloud/DeleteInactiveReplicaTest.java      |  6 +--
 .../cloud/DeleteLastCustomShardedReplicaTest.java  |  2 +-
 .../org/apache/solr/cloud/DeleteReplicaTest.java   | 10 ++--
 .../org/apache/solr/cloud/DeleteShardTest.java     | 10 ++--
 .../DistribDocExpirationUpdateProcessorTest.java   |  2 +-
 .../solr/cloud/DistributedVersionInfoTest.java     |  2 +-
 .../solr/cloud/LeaderElectionIntegrationTest.java  |  2 +-
 .../apache/solr/cloud/LeaderTragicEventTest.java   | 11 +++--
 .../solr/cloud/LeaderVoteWaitTimeoutTest.java      |  6 +--
 .../org/apache/solr/cloud/MigrateRouteKeyTest.java |  2 +-
 .../test/org/apache/solr/cloud/OverseerTest.java   | 38 ++++++++--------
 .../apache/solr/cloud/ReindexCollectionTest.java   | 16 +++----
 .../apache/solr/cloud/TestCloudConsistency.java    | 10 ++--
 .../org/apache/solr/cloud/TestCloudRecovery2.java  |  8 ++--
 .../solr/cloud/TestCloudSearcherWarming.java       |  2 +-
 .../cloud/TestDeleteCollectionOnDownNodes.java     |  2 +-
 .../cloud/TestLeaderElectionWithEmptyReplica.java  |  2 +-
 .../org/apache/solr/cloud/TestPullReplica.java     |  7 ++-
 .../solr/cloud/TestPullReplicaErrorHandling.java   |  2 +-
 .../apache/solr/cloud/TestRebalanceLeaders.java    | 16 +++++--
 .../solr/cloud/TestSkipOverseerOperations.java     |  4 +-
 .../org/apache/solr/cloud/TestTlogReplica.java     |  6 +--
 .../cloud/TestWaitForStateWithJettyShutdowns.java  | 14 +++---
 .../api/collections/CollectionReloadTest.java      |  2 +-
 .../collections/CollectionTooManyReplicasTest.java |  4 +-
 .../CollectionsAPIAsyncDistributedZkTest.java      |  2 +-
 .../CollectionsAPIDistributedZkTest.java           | 18 ++++----
 .../api/collections/CustomCollectionTest.java      |  4 +-
 .../AutoAddReplicasIntegrationTest.java            | 15 +++---
 .../cloud/autoscaling/ComputePlanActionTest.java   |  8 ++--
 .../ScheduledMaintenanceTriggerTest.java           |  4 +-
 .../solr/cloud/autoscaling/TestPolicyCloud.java    |  6 +--
 .../autoscaling/sim/TestSimComputePlanAction.java  |  2 +-
 .../cloud/autoscaling/sim/TestSimPolicyCloud.java  |  4 +-
 .../solr/cloud/hdfs/HDFSCollectionsAPITest.java    |  2 +-
 .../solr/cloud/overseer/ZkStateReaderTest.java     |  8 ++--
 .../test/org/apache/solr/cloud/rule/RulesTest.java |  8 ++--
 .../DistributedQueryComponentOptimizationTest.java |  2 +-
 .../schema/ManagedSchemaRoundRobinCloudTest.java   |  2 +-
 .../PreAnalyzedFieldManagedSchemaCloudTest.java    |  2 +-
 .../apache/solr/schema/SchemaApiFailureTest.java   |  2 +-
 .../processor/RoutedAliasUpdateProcessorTest.java  |  2 +-
 .../client/solrj/cloud/DirectReplicaState.java     | 53 ++++++++++++++++++++++
 .../client/solrj/cloud/ReplicaStateProvider.java   | 33 ++++++++++++++
 .../client/solrj/impl/ClusterStateProvider.java    |  6 +++
 .../solrj/impl/ZkClientClusterStateProvider.java   |  6 +++
 .../common/cloud/CollectionStatePredicate.java     |  5 +-
 .../apache/solr/common/cloud/ZkStateReader.java    | 11 ++++-
 .../cloud/TestCloudCollectionsListeners.java       |  2 +-
 .../common/cloud/TestCollectionStateWatchers.java  | 26 +++++------
 .../common/cloud/TestDocCollectionWatcher.java     | 16 +++----
 .../solr/cloud/AbstractDistribZkTestBase.java      |  4 +-
 .../solr/cloud/AbstractFullDistribZkTestBase.java  |  8 ++--
 .../apache/solr/cloud/MiniSolrCloudCluster.java    | 14 +++---
 .../org/apache/solr/cloud/SolrCloudTestCase.java   |  8 ++--
 65 files changed, 326 insertions(+), 218 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/cloud/CloudUtil.java b/solr/core/src/java/org/apache/solr/cloud/CloudUtil.java
index 1558389..7008bf9 100644
--- a/solr/core/src/java/org/apache/solr/cloud/CloudUtil.java
+++ b/solr/core/src/java/org/apache/solr/cloud/CloudUtil.java
@@ -169,10 +169,10 @@ public class CloudUtil {
     AtomicReference<DocCollection> state = new AtomicReference<>();
     AtomicReference<Set<String>> liveNodesLastSeen = new AtomicReference<>();
     try {
-      return waitForState(cloudManager, collection, DEFAULT_TIMEOUT, TimeUnit.SECONDS, (n, c) -> {
+      return waitForState(cloudManager, collection, DEFAULT_TIMEOUT, TimeUnit.SECONDS, (n, c, rsp) -> {
         state.set(c);
         liveNodesLastSeen.set(n);
-        return predicate.matches(n, c);
+        return predicate.matches(n, c, rsp);
       });
     } catch (Exception e) {
       throw new AssertionError(message + "\n" + "Live Nodes: " + liveNodesLastSeen.get() + "\nLast available state: " + state.get(), e);
@@ -208,7 +208,7 @@ public class CloudUtil {
         timeout.sleep(100);
         continue;
       }
-      if (predicate.matches(state.getLiveNodes(), coll)) {
+      if (predicate.matches(state.getLiveNodes(), coll, cloudManager.getClusterStateProvider().getReplicaStateProvider(collection))) {
         log.trace("-- predicate matched with state {}", state);
         return timeout.timeElapsed(TimeUnit.MILLISECONDS);
       }
@@ -242,7 +242,7 @@ public class CloudUtil {
    */
   public static CollectionStatePredicate clusterShape(int expectedShards, int expectedReplicas, boolean withInactive,
                                                       boolean requireLeaders) {
-    return (liveNodes, collectionState) -> {
+    return (liveNodes, collectionState, rsp) -> {
       if (collectionState == null) {
         log.debug("-- null collection");
         return false;
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/sim/SimClusterStateProvider.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/sim/SimClusterStateProvider.java
index bb8c654..99dbfc0 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/sim/SimClusterStateProvider.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/sim/SimClusterStateProvider.java
@@ -1377,7 +1377,7 @@ public class SimClusterStateProvider implements ClusterStateProvider {
 
     boolean success = false;
     try {
-      CloudUtil.waitForState(cloudManager, collectionName, 30, TimeUnit.SECONDS, (liveNodes, state) -> {
+      CloudUtil.waitForState(cloudManager, collectionName, 30, TimeUnit.SECONDS, (liveNodes, state, rsp) -> {
         for (String subSlice : subSlices) {
           Slice s = state.getSlice(subSlice);
           if (s.getLeader() == null) {
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
index 5843a94..cda1353 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
@@ -149,10 +149,10 @@ import static org.apache.solr.common.params.CollectionParams.CollectionAction.*;
 import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
 import static org.apache.solr.common.params.CommonAdminParams.IN_PLACE_MOVE;
 import static org.apache.solr.common.params.CommonAdminParams.NUM_SUB_SHARDS;
+import static org.apache.solr.common.params.CommonAdminParams.SPLIT_BY_PREFIX;
 import static org.apache.solr.common.params.CommonAdminParams.SPLIT_FUZZ;
 import static org.apache.solr.common.params.CommonAdminParams.SPLIT_METHOD;
 import static org.apache.solr.common.params.CommonAdminParams.WAIT_FOR_FINAL_STATE;
-import static org.apache.solr.common.params.CommonAdminParams.SPLIT_BY_PREFIX;
 import static org.apache.solr.common.params.CommonParams.NAME;
 import static org.apache.solr.common.params.CommonParams.TIMING;
 import static org.apache.solr.common.params.CommonParams.VALUE_LONG;
@@ -1412,7 +1412,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
         + (checkLeaderOnly ? "leaders" : "replicas"));
 
     try {
-      cc.getZkController().getZkStateReader().waitForState(collectionName, seconds, TimeUnit.SECONDS, (n, c) -> {
+      cc.getZkController().getZkStateReader().waitForState(collectionName, seconds, TimeUnit.SECONDS, (n, c, rsp) -> {
 
         if (c == null) {
           // the collection was not created, don't wait
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/PrepRecoveryOp.java b/solr/core/src/java/org/apache/solr/handler/admin/PrepRecoveryOp.java
index 7109944..60f7d09 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/PrepRecoveryOp.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/PrepRecoveryOp.java
@@ -75,7 +75,7 @@ class PrepRecoveryOp implements CoreAdminHandler.CoreAdminOp {
     }
     AtomicReference<String> errorMessage = new AtomicReference<>();
     try {
-      coreContainer.getZkController().getZkStateReader().waitForState(collectionName, conflictWaitMs, TimeUnit.MILLISECONDS, (n, c) -> {
+      coreContainer.getZkController().getZkStateReader().waitForState(collectionName, conflictWaitMs, TimeUnit.MILLISECONDS, (n, c, rsp) -> {
         if (c == null)
           return false;
 
diff --git a/solr/core/src/test/org/apache/solr/client/solrj/impl/ConnectionReuseTest.java b/solr/core/src/test/org/apache/solr/client/solrj/impl/ConnectionReuseTest.java
index f0ae126..61a3d98 100644
--- a/solr/core/src/test/org/apache/solr/client/solrj/impl/ConnectionReuseTest.java
+++ b/solr/core/src/test/org/apache/solr/client/solrj/impl/ConnectionReuseTest.java
@@ -36,10 +36,10 @@ import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.http.message.BasicHttpRequest;
+import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.cloud.SolrCloudTestCase;
-import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
 import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.update.AddUpdateCommand;
 import org.apache.solr.util.TestInjection;
@@ -65,7 +65,7 @@ public class ConnectionReuseTest extends SolrCloudTestCase {
         .processAndWait(cluster.getSolrClient(), DEFAULT_TIMEOUT);
 
     cluster.getSolrClient().waitForState(COLLECTION, DEFAULT_TIMEOUT, TimeUnit.SECONDS,
-        (n, c) -> DocCollection.isFullyActive(n, c, 1, 1));
+        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 1));
   }
 
   private SolrClient buildClient(CloseableHttpClient httpClient, URL url) {
diff --git a/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java b/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
index 98b5a8a..11187e6 100644
--- a/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
@@ -548,7 +548,7 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
       throws Exception {
     AtomicLong total = new AtomicLong(-1);
     try {
-      getCommonCloudSolrClient().getZkStateReader().waitForState(DEFAULT_COLLECTION, waitMillis, TimeUnit.MILLISECONDS, (n, c) -> {
+      getCommonCloudSolrClient().getZkStateReader().waitForState(DEFAULT_COLLECTION, waitMillis, TimeUnit.MILLISECONDS, (n, c, rsp) -> {
         long docTotal;
         try {
           docTotal = checkSlicesSameCounts(c);
@@ -1044,7 +1044,7 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
       });
 
       try {
-        getCommonCloudSolrClient().getZkStateReader().waitForState(oneInstanceCollection2, 20000, TimeUnit.MILLISECONDS, (n, c) -> {
+        getCommonCloudSolrClient().getZkStateReader().waitForState(oneInstanceCollection2, 20000, TimeUnit.MILLISECONDS, (n, c, rsp) -> {
           
  
           try {
diff --git a/solr/core/src/test/org/apache/solr/cloud/CleanupOldIndexTest.java b/solr/core/src/test/org/apache/solr/cloud/CleanupOldIndexTest.java
index ff1660f..0906049 100644
--- a/solr/core/src/test/org/apache/solr/cloud/CleanupOldIndexTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/CleanupOldIndexTest.java
@@ -112,7 +112,7 @@ public class CleanupOldIndexTest extends SolrCloudTestCase {
     indexThread.join();
 
     cluster.getSolrClient().waitForState(COLLECTION, DEFAULT_TIMEOUT, TimeUnit.SECONDS,
-        (n, c) -> DocCollection.isFullyActive(n, c, 1, 2));
+        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 2));
 
     assertTrue(!oldIndexDir1.isDirectory());
     assertTrue(!oldIndexDir2.isDirectory());
diff --git a/solr/core/src/test/org/apache/solr/cloud/CloudExitableDirectoryReaderTest.java b/solr/core/src/test/org/apache/solr/cloud/CloudExitableDirectoryReaderTest.java
index 3c757ad..985303c 100644
--- a/solr/core/src/test/org/apache/solr/cloud/CloudExitableDirectoryReaderTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/CloudExitableDirectoryReaderTest.java
@@ -93,7 +93,7 @@ public class CloudExitableDirectoryReaderTest extends SolrCloudTestCase {
     CollectionAdminRequest.createCollection(COLLECTION, "conf", 2, 1)
         .processAndWait(cluster.getSolrClient(), DEFAULT_TIMEOUT);
     cluster.getSolrClient().waitForState(COLLECTION, DEFAULT_TIMEOUT, TimeUnit.SECONDS,
-        (n, c) -> DocCollection.isFullyActive(n, c, 2, 1));
+        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 2, 1));
 
     fiveHundredsByNode = new LinkedHashMap<>();
     int httpOk = 0;
diff --git a/solr/core/src/test/org/apache/solr/cloud/CollectionStateFormat2Test.java b/solr/core/src/test/org/apache/solr/cloud/CollectionStateFormat2Test.java
index 04da1f5..8fe3df1 100644
--- a/solr/core/src/test/org/apache/solr/cloud/CollectionStateFormat2Test.java
+++ b/solr/core/src/test/org/apache/solr/cloud/CollectionStateFormat2Test.java
@@ -47,7 +47,7 @@ public class CollectionStateFormat2Test extends SolrCloudTestCase {
 
     cluster.waitForActiveCollection(collectionName, 2, 4);
     
-    waitForState("Collection not created", collectionName, (n, c) -> DocCollection.isFullyActive(n, c, 2, 2));
+    waitForState("Collection not created", collectionName, (n, c, rsp) -> DocCollection.isFullyActive(n, c, 2, 2));
     assertTrue("State Format 2 collection path does not exist",
         zkClient().exists(ZkStateReader.getCollectionPath(collectionName), true));
 
@@ -61,7 +61,7 @@ public class CollectionStateFormat2Test extends SolrCloudTestCase {
 
     // remove collection
     CollectionAdminRequest.deleteCollection(collectionName).process(cluster.getSolrClient());
-    waitForState("Collection not deleted", collectionName, (n, coll) -> coll == null);
+    waitForState("Collection not deleted", collectionName, (n, coll, rsp) -> coll == null);
 
     assertFalse("collection state should not exist externally",
         zkClient().exists(ZkStateReader.getCollectionPath(collectionName), true));
diff --git a/solr/core/src/test/org/apache/solr/cloud/CollectionsAPISolrJTest.java b/solr/core/src/test/org/apache/solr/cloud/CollectionsAPISolrJTest.java
index 4db1152..4d069b1 100644
--- a/solr/core/src/test/org/apache/solr/cloud/CollectionsAPISolrJTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/CollectionsAPISolrJTest.java
@@ -16,14 +16,6 @@
  */
 package org.apache.solr.cloud;
 
-import static java.util.Arrays.asList;
-import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_DEF;
-import static org.apache.solr.common.cloud.ZkStateReader.NRT_REPLICAS;
-import static org.apache.solr.common.cloud.ZkStateReader.NUM_SHARDS_PROP;
-import static org.apache.solr.common.cloud.ZkStateReader.SOLR_AUTOSCALING_CONF_PATH;
-import static org.apache.solr.common.params.CollectionAdminParams.COLLECTION;
-import static org.apache.solr.common.params.CollectionAdminParams.DEFAULTS;
-
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.nio.file.Path;
@@ -38,6 +30,7 @@ import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
+import com.google.common.collect.ImmutableList;
 import org.apache.lucene.util.LuceneTestCase;
 import org.apache.lucene.util.TestUtil;
 import org.apache.solr.client.solrj.SolrClient;
@@ -75,11 +68,17 @@ import org.apache.zookeeper.KeeperException;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static java.util.Arrays.asList;
+import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_DEF;
+import static org.apache.solr.common.cloud.ZkStateReader.NRT_REPLICAS;
+import static org.apache.solr.common.cloud.ZkStateReader.NUM_SHARDS_PROP;
+import static org.apache.solr.common.cloud.ZkStateReader.SOLR_AUTOSCALING_CONF_PATH;
+import static org.apache.solr.common.params.CollectionAdminParams.COLLECTION;
+import static org.apache.solr.common.params.CollectionAdminParams.DEFAULTS;
+
 @LuceneTestCase.Slow
 public class CollectionsAPISolrJTest extends SolrCloudTestCase {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -134,7 +133,7 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase {
     Map<String,NamedList<Integer>> nodesStatus = response.getCollectionNodesStatus();
     assertEquals(4, nodesStatus.size());
 
-    waitForState("Expected " + collectionName + " to disappear from cluster state", collectionName, (n, c) -> c == null);
+    waitForState("Expected " + collectionName + " to disappear from cluster state", collectionName, (n, c, rsp) -> c == null);
   }
 
   @Test
@@ -326,7 +325,7 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase {
     Map<String,NamedList<Integer>> nodesStatus = response.getCollectionNodesStatus();
     assertEquals(4, nodesStatus.size());
 
-    waitForState("Expected " + collectionName + " to disappear from cluster state", collectionName, (n, c) -> c == null);
+    waitForState("Expected " + collectionName + " to disappear from cluster state", collectionName, (n, c, rsp) -> c == null);
 
     // Test Creating a collection with new stateformat.
     collectionName = "solrj_newstateformat";
@@ -337,7 +336,7 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase {
     assertEquals(0, response.getStatus());
     assertTrue(response.isSuccess());
 
-    waitForState("Expected " + collectionName + " to appear in cluster state", collectionName, (n, c) -> c != null);
+    waitForState("Expected " + collectionName + " to appear in cluster state", collectionName, (n, c, rsp) -> c != null);
 
   }
 
@@ -388,7 +387,7 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase {
     assertEquals(0, response.getStatus());
     assertTrue(response.isSuccess());
     
-    cluster.getSolrClient().waitForState(collectionName, 30, TimeUnit.SECONDS, (l,c) -> c != null && c.getSlice("shardC") != null); 
+    cluster.getSolrClient().waitForState(collectionName, 30, TimeUnit.SECONDS, (l,c, rsp) -> c != null && c.getSlice("shardC") != null);
     
     coresStatus = response.getCollectionCoresStatus();
     assertEquals(3, coresStatus.size());
@@ -453,7 +452,7 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase {
     assertEquals(1, shard10);
     assertEquals(1, shard11);
 
-    waitForState("Expected all shards to be active and parent shard to be removed", collectionName, (n, c) -> {
+    waitForState("Expected all shards to be active and parent shard to be removed", collectionName, (n, c, rsp) -> {
       if (c.getSlice("shard1").getState() == Slice.State.ACTIVE)
         return false;
       for (Replica r : c.getReplicas()) {
@@ -471,7 +470,7 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase {
     assertEquals(0, response.getStatus());
     assertTrue(response.isSuccess());
 
-    waitForState("Expected 5 slices to be active", collectionName, (n, c) -> c.getActiveSlices().size() == 5);
+    waitForState("Expected 5 slices to be active", collectionName, (n, c, rsp) -> c.getActiveSlices().size() == 5);
 
   }
 
@@ -537,7 +536,7 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase {
     assertEquals(0, response.getStatus());
 
     waitForState("Expected replica " + newReplica.getName() + " to vanish from cluster state", collectionName,
-        (n, c) -> c.getSlice("shard1").getReplica(newReplica.getName()) == null);
+        (n, c, rsp) -> c.getSlice("shard1").getReplica(newReplica.getName()) == null);
 
   }
 
@@ -1021,14 +1020,14 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase {
     assertEquals(0, response.getStatus());
 
     waitForState("Expecting property 'preferredleader' to appear on replica " + replica.getName(), collection,
-        (n, c) -> "true".equals(c.getReplica(replica.getName()).getProperty("preferredleader")));
+        (n, c, rsp) -> "true".equals(c.getReplica(replica.getName()).getProperty("preferredleader")));
 
     response = CollectionAdminRequest.deleteReplicaProperty(collection, "shard1", replica.getName(), "property.preferredleader")
         .process(cluster.getSolrClient());
     assertEquals(0, response.getStatus());
 
     waitForState("Expecting property 'preferredleader' to be removed from replica " + replica.getName(), collection,
-        (n, c) -> c.getReplica(replica.getName()).getProperty("preferredleader") == null);
+        (n, c, rsp) -> c.getReplica(replica.getName()).getProperty("preferredleader") == null);
 
   }
 
@@ -1046,7 +1045,7 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase {
         .process(cluster.getSolrClient());
     assertEquals(0, response.getStatus());
 
-    waitForState("Expecting 'preferredleader' property to be balanced across all shards", collection, (n, c) -> {
+    waitForState("Expecting 'preferredleader' property to be balanced across all shards", collection, (n, c, rsp) -> {
       for (Slice slice : c) {
         int count = 0;
         for (Replica replica : slice) {
@@ -1074,14 +1073,14 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase {
         .process(cluster.getSolrClient());
 
     waitForState("Expecting attribute 'replicationFactor' to be 25", collection,
-        (n, c) -> 25 == c.getReplicationFactor());
+        (n, c, rsp) -> 25 == c.getReplicationFactor());
 
     CollectionAdminRequest.modifyCollection(collection, null)
         .unsetAttribute("maxShardsPerNode")
         .process(cluster.getSolrClient());
 
     waitForState("Expecting attribute 'maxShardsPerNode' to be deleted", collection,
-        (n, c) -> null == c.get("maxShardsPerNode"));
+        (n, c, rsp) -> null == c.get("maxShardsPerNode"));
 
     expectThrows(IllegalArgumentException.class,
         "An attempt to set unknown collection attribute should have failed",
diff --git a/solr/core/src/test/org/apache/solr/cloud/DeleteInactiveReplicaTest.java b/solr/core/src/test/org/apache/solr/cloud/DeleteInactiveReplicaTest.java
index 33a1a55..3e91d3f 100644
--- a/solr/core/src/test/org/apache/solr/cloud/DeleteInactiveReplicaTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/DeleteInactiveReplicaTest.java
@@ -61,7 +61,7 @@ public class DeleteInactiveReplicaTest extends SolrCloudTestCase {
     CollectionAdminRequest.createCollection(collectionName, "conf", numShards, replicationFactor)
         .setMaxShardsPerNode(maxShardsPerNode)
         .process(cluster.getSolrClient());
-    waitForState("Expected a cluster of 2 shards and 2 replicas", collectionName, (n, c) -> {
+    waitForState("Expected a cluster of 2 shards and 2 replicas", collectionName, (n, c, rsp) -> {
       return DocCollection.isFullyActive(n, c, numShards, replicationFactor);
     });
 
@@ -76,7 +76,7 @@ public class DeleteInactiveReplicaTest extends SolrCloudTestCase {
     }
     cluster.stopJettySolrRunner(jetty);
 
-    waitForState("Expected replica " + replica.getName() + " on down node to be removed from cluster state", collectionName, (n, c) -> {
+    waitForState("Expected replica " + replica.getName() + " on down node to be removed from cluster state", collectionName, (n, c, rsp) -> {
       Replica r = c.getReplica(replica.getCoreName());
       return r == null || r.getState() != Replica.State.ACTIVE;
     });
@@ -84,7 +84,7 @@ public class DeleteInactiveReplicaTest extends SolrCloudTestCase {
     log.info("Removing replica {}/{} ", shard.getName(), replica.getName());
     CollectionAdminRequest.deleteReplica(collectionName, shard.getName(), replica.getName())
         .process(cluster.getSolrClient());
-    waitForState("Expected deleted replica " + replica.getName() + " to be removed from cluster state", collectionName, (n, c) -> {
+    waitForState("Expected deleted replica " + replica.getName() + " to be removed from cluster state", collectionName, (n, c, rsp) -> {
       return c.getReplica(replica.getCoreName()) == null;
     });
 
diff --git a/solr/core/src/test/org/apache/solr/cloud/DeleteLastCustomShardedReplicaTest.java b/solr/core/src/test/org/apache/solr/cloud/DeleteLastCustomShardedReplicaTest.java
index c46362e..c9e4c23 100644
--- a/solr/core/src/test/org/apache/solr/cloud/DeleteLastCustomShardedReplicaTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/DeleteLastCustomShardedReplicaTest.java
@@ -46,7 +46,7 @@ public class DeleteLastCustomShardedReplicaTest extends SolrCloudTestCase {
     CollectionAdminRequest.deleteReplica(collectionName, "a", replica.getName())
         .process(cluster.getSolrClient());
 
-    waitForState("Expected shard 'a' to have no replicas", collectionName, (n, c) -> {
+    waitForState("Expected shard 'a' to have no replicas", collectionName, (n, c, rsp) -> {
       return c.getSlice("a") == null || c.getSlice("a").getReplicas().size() == 0;
     });
 
diff --git a/solr/core/src/test/org/apache/solr/cloud/DeleteReplicaTest.java b/solr/core/src/test/org/apache/solr/cloud/DeleteReplicaTest.java
index 253f2ba..160a572 100644
--- a/solr/core/src/test/org/apache/solr/cloud/DeleteReplicaTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/DeleteReplicaTest.java
@@ -125,7 +125,7 @@ public class DeleteReplicaTest extends SolrCloudTestCase {
     
     CollectionAdminRequest.deleteReplica(collectionName, shard.getName(), replica.getName())
         .process(cluster.getSolrClient());
-    waitForState("Expected replica " + replica.getName() + " to have been removed", collectionName, (n, c) -> {
+    waitForState("Expected replica " + replica.getName() + " to have been removed", collectionName, (n, c, rsp) -> {
       Slice testShard = c.getSlice(shard.getName());
       return testShard.getReplica(replica.getName()) == null;
     });
@@ -259,7 +259,7 @@ public class DeleteReplicaTest extends SolrCloudTestCase {
     cluster.getOpenOverseer().getStateUpdateQueue().offer(Utils.toJSON(m));
 
     waitForState("Timeout waiting for replica get deleted", collectionName,
-        (liveNodes, collectionState) -> collectionState.getSlice("shard1").getReplicas().size() == 2);
+        (liveNodes, collectionState, rsp) -> collectionState.getSlice("shard1").getReplicas().size() == 2);
 
     TimeOut timeOut = new TimeOut(60, TimeUnit.SECONDS, TimeSource.NANO_TIME);
     timeOut.waitFor("Waiting for replica get unloaded", () ->
@@ -375,7 +375,7 @@ public class DeleteReplicaTest extends SolrCloudTestCase {
     try {
       replica1Jetty.stop();
       waitForNodeLeave(replica1JettyNodeName);
-      waitForState("Expected replica:"+replica1+" get down", collectionName, (liveNodes, collectionState)
+      waitForState("Expected replica:"+replica1+" get down", collectionName, (liveNodes, collectionState, rsp)
           -> collectionState.getSlice("shard1").getReplica(replica1.getName()).getState() == DOWN);
       replica1Jetty.start();
       waitingForReplicaGetDeleted.acquire();
@@ -403,7 +403,7 @@ public class DeleteReplicaTest extends SolrCloudTestCase {
     leaderJetty.stop();
     waitForNodeLeave(leaderJettyNodeName);
 
-    waitForState("Expected new active leader", collectionName, (liveNodes, collectionState) -> {
+    waitForState("Expected new active leader", collectionName, (liveNodes, collectionState, rsp) -> {
       Slice shard = collectionState.getSlice("shard1");
       Replica newLeader = shard.getLeader();
       return newLeader != null && newLeader.getState() == Replica.State.ACTIVE && !newLeader.getName().equals(latestLeader.getName());
@@ -465,7 +465,7 @@ public class DeleteReplicaTest extends SolrCloudTestCase {
     }
 
     try {
-      cluster.getSolrClient().waitForState(collectionName, 20, TimeUnit.SECONDS, (liveNodes, collectionState) -> collectionState.getReplicas().size() == 1);
+      cluster.getSolrClient().waitForState(collectionName, 20, TimeUnit.SECONDS, (liveNodes, collectionState, rsp) -> collectionState.getReplicas().size() == 1);
     } catch (TimeoutException e) {
       log.info("Timeout wait for state {}", getCollectionState(collectionName));
       throw e;
diff --git a/solr/core/src/test/org/apache/solr/cloud/DeleteShardTest.java b/solr/core/src/test/org/apache/solr/cloud/DeleteShardTest.java
index 6f384fb..da99e6e 100644
--- a/solr/core/src/test/org/apache/solr/cloud/DeleteShardTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/DeleteShardTest.java
@@ -76,14 +76,14 @@ public class DeleteShardTest extends SolrCloudTestCase {
 
     // Can delete an INATIVE shard
     CollectionAdminRequest.deleteShard(collection, "shard1").process(cluster.getSolrClient());
-    waitForState("Expected 'shard1' to be removed", collection, (n, c) -> {
+    waitForState("Expected 'shard1' to be removed", collection, (n, c, rsp) -> {
       return c.getSlice("shard1") == null;
     });
 
     // Can delete a shard under construction
     setSliceState(collection, "shard2", Slice.State.CONSTRUCTION);
     CollectionAdminRequest.deleteShard(collection, "shard2").process(cluster.getSolrClient());
-    waitForState("Expected 'shard2' to be removed", collection, (n, c) -> {
+    waitForState("Expected 'shard2' to be removed", collection, (n, c, rsp) -> {
       return c.getSlice("shard2") == null;
     });
 
@@ -102,7 +102,7 @@ public class DeleteShardTest extends SolrCloudTestCase {
     ZkNodeProps m = new ZkNodeProps(propMap);
     inQueue.offer(Utils.toJSON(m));
 
-    waitForState("Expected shard " + slice + " to be in state " + state.toString(), collection, (n, c) -> {
+    waitForState("Expected shard " + slice + " to be in state " + state.toString(), collection, (n, c, rsp) -> {
       return c.getSlice(slice).getState() == state;
     });
 
@@ -131,7 +131,7 @@ public class DeleteShardTest extends SolrCloudTestCase {
     // Delete shard 'a'
     CollectionAdminRequest.deleteShard(collection, "a").process(cluster.getSolrClient());
     
-    waitForState("Expected 'a' to be removed", collection, (n, c) -> {
+    waitForState("Expected 'a' to be removed", collection, (n, c, rsp) -> {
       return c.getSlice("a") == null;
     });
 
@@ -148,7 +148,7 @@ public class DeleteShardTest extends SolrCloudTestCase {
         .setDeleteInstanceDir(false)
         .process(cluster.getSolrClient());
 
-    waitForState("Expected 'b' to be removed", collection, (n, c) -> {
+    waitForState("Expected 'b' to be removed", collection, (n, c, rsp) -> {
       return c.getSlice("b") == null;
     });
     
diff --git a/solr/core/src/test/org/apache/solr/cloud/DistribDocExpirationUpdateProcessorTest.java b/solr/core/src/test/org/apache/solr/cloud/DistribDocExpirationUpdateProcessorTest.java
index 8847cec..4575500 100644
--- a/solr/core/src/test/org/apache/solr/cloud/DistribDocExpirationUpdateProcessorTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/DistribDocExpirationUpdateProcessorTest.java
@@ -61,7 +61,7 @@ public class DistribDocExpirationUpdateProcessorTest extends SolrCloudTestCase {
     CollectionAdminRequest.createCollection(COLLECTION, "conf", 2, 1)
         .processAndWait(cluster.getSolrClient(), DEFAULT_TIMEOUT);
     cluster.getSolrClient().waitForState(COLLECTION, DEFAULT_TIMEOUT, TimeUnit.SECONDS,
-        (n, c) -> DocCollection.isFullyActive(n, c, 2, 1));
+        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 2, 1));
   }
 
   @Test
diff --git a/solr/core/src/test/org/apache/solr/cloud/DistributedVersionInfoTest.java b/solr/core/src/test/org/apache/solr/cloud/DistributedVersionInfoTest.java
index 0394152..60f2b65 100644
--- a/solr/core/src/test/org/apache/solr/cloud/DistributedVersionInfoTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/DistributedVersionInfoTest.java
@@ -84,7 +84,7 @@ public class DistributedVersionInfoTest extends SolrCloudTestCase {
 
     final ZkStateReader stateReader = cluster.getSolrClient().getZkStateReader();
     stateReader.waitForState(COLLECTION, DEFAULT_TIMEOUT, TimeUnit.SECONDS,
-        (n, c) -> DocCollection.isFullyActive(n, c, 1, 3));
+        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 3));
 
     final Replica leader = stateReader.getLeaderRetry(COLLECTION, shardId);
 
diff --git a/solr/core/src/test/org/apache/solr/cloud/LeaderElectionIntegrationTest.java b/solr/core/src/test/org/apache/solr/cloud/LeaderElectionIntegrationTest.java
index c20a450..7863ff3 100644
--- a/solr/core/src/test/org/apache/solr/cloud/LeaderElectionIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/LeaderElectionIntegrationTest.java
@@ -108,7 +108,7 @@ public class LeaderElectionIntegrationTest extends SolrCloudTestCase {
       runner.start();
     }
     waitForState("Expected to see nodes come back " + collection, collection,
-        (n, c) -> {
+        (n, c, rsp) -> {
           return n.size() == 6;
         });
     CollectionAdminRequest.deleteCollection(collection).process(cluster.getSolrClient());
diff --git a/solr/core/src/test/org/apache/solr/cloud/LeaderTragicEventTest.java b/solr/core/src/test/org/apache/solr/cloud/LeaderTragicEventTest.java
index 2cdd6eb..3504cc6 100644
--- a/solr/core/src/test/org/apache/solr/cloud/LeaderTragicEventTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/LeaderTragicEventTest.java
@@ -17,9 +17,6 @@
 
 package org.apache.solr.cloud;
 
-import static org.hamcrest.CoreMatchers.anyOf;
-import static org.hamcrest.CoreMatchers.is;
-
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
@@ -27,6 +24,7 @@ import java.nio.file.NoSuchFileException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+
 import org.apache.lucene.store.AlreadyClosedException;
 import org.apache.lucene.store.MockDirectoryWrapper;
 import org.apache.lucene.util.LuceneTestCase.AwaitsFix;
@@ -50,6 +48,9 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.hamcrest.CoreMatchers.anyOf;
+import static org.hamcrest.CoreMatchers.is;
+
 @AwaitsFix(bugUrl="https://issues.apache.org/jira/browse/SOLR-13237")
 public class LeaderTragicEventTest extends SolrCloudTestCase {
 
@@ -84,7 +85,7 @@ public class LeaderTragicEventTest extends SolrCloudTestCase {
       List<String> addedIds = new ArrayList<>();
       Replica oldLeader = corruptLeader(collection, addedIds);
 
-      waitForState("Timeout waiting for new replica become leader", collection, (liveNodes, collectionState) -> {
+      waitForState("Timeout waiting for new replica become leader", collection, (liveNodes, collectionState, rsp) -> {
         Slice slice = collectionState.getSlice("shard1");
 
         if (slice.getReplicas().size() != 2) return false;
@@ -180,7 +181,7 @@ public class LeaderTragicEventTest extends SolrCloudTestCase {
         log.info("Stop jetty node : {} state:{}", otherReplicaJetty.getBaseUrl(), getCollectionState(collection));
         otherReplicaJetty.stop();
         cluster.waitForJettyToStop(otherReplicaJetty);
-        waitForState("Timeout waiting for replica get down", collection, (liveNodes, collectionState) -> getNonLeader(collectionState.getSlice("shard1")).getState() != Replica.State.ACTIVE);
+        waitForState("Timeout waiting for replica get down", collection, (liveNodes, collectionState, rsp) -> getNonLeader(collectionState.getSlice("shard1")).getState() != Replica.State.ACTIVE);
       }
 
       Replica oldLeader = corruptLeader(collection, new ArrayList<>());
diff --git a/solr/core/src/test/org/apache/solr/cloud/LeaderVoteWaitTimeoutTest.java b/solr/core/src/test/org/apache/solr/cloud/LeaderVoteWaitTimeoutTest.java
index 3dfb521..295889c 100644
--- a/solr/core/src/test/org/apache/solr/cloud/LeaderVoteWaitTimeoutTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/LeaderVoteWaitTimeoutTest.java
@@ -131,13 +131,13 @@ public class LeaderVoteWaitTimeoutTest extends SolrCloudTestCase {
     j.stop();
     cluster.waitForJettyToStop(j);
     
-    cluster.getSolrClient().getZkStateReader().waitForState(collectionName, 10, TimeUnit.SECONDS, (liveNodes, collectionState) -> !liveNodes.contains(nodeName));
+    cluster.getSolrClient().getZkStateReader().waitForState(collectionName, 10, TimeUnit.SECONDS, (liveNodes, collectionState, rsp) -> !liveNodes.contains(nodeName));
 
     CollectionAdminRequest.addReplicaToShard(collectionName, "shard1")
         .setNode(cluster.getJettySolrRunner(1).getNodeName())
         .process(cluster.getSolrClient());
 
-    waitForState("Timeout waiting for replica win the election", collectionName, (liveNodes, collectionState) -> {
+    waitForState("Timeout waiting for replica win the election", collectionName, (liveNodes, collectionState, rsp) -> {
       Replica newLeader = collectionState.getSlice("shard1").getLeader();
       if (newLeader == null) {
         return false;
@@ -232,7 +232,7 @@ public class LeaderVoteWaitTimeoutTest extends SolrCloudTestCase {
 
     try {
       // even replica2 joined election at the end of the queue, but it is the one with highest term
-      waitForState("Timeout waiting for new leader", collectionName, (liveNodes, collectionState) -> {
+      waitForState("Timeout waiting for new leader", collectionName, (liveNodes, collectionState, rsp) -> {
         Replica newLeader = collectionState.getSlice("shard1").getLeader();
         if (newLeader == null) {
           return false;
diff --git a/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java b/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java
index 5e17706..e069175 100644
--- a/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java
@@ -162,7 +162,7 @@ public class MigrateRouteKeyTest extends SolrCloudTestCase {
       log.info("Response from target collection: " + response);
       assertEquals("DocCount on target collection does not match", splitKeyCount[0], response.getResults().getNumFound());
 
-      waitForState("Expected to find routing rule for split key " + splitKey, "sourceCollection", (n, c) -> {
+      waitForState("Expected to find routing rule for split key " + splitKey, "sourceCollection", (n, c, rsp) -> {
         if (c == null)
           return false;
         Slice shard = c.getSlice("shard2");
diff --git a/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java b/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java
index 175806d..c35b52e 100644
--- a/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java
@@ -16,15 +16,7 @@
  */
 package org.apache.solr.cloud;
 
-import static org.apache.solr.cloud.AbstractDistribZkTestBase.verifyReplicaStatus;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
+import javax.xml.parsers.ParserConfigurationException;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.nio.file.Path;
@@ -44,8 +36,8 @@ import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import javax.xml.parsers.ParserConfigurationException;
-
+import com.codahale.metrics.Snapshot;
+import com.codahale.metrics.Timer;
 import org.apache.lucene.util.LuceneTestCase.Slow;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrClient;
@@ -103,8 +95,14 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.xml.sax.SAXException;
 
-import com.codahale.metrics.Snapshot;
-import com.codahale.metrics.Timer;
+import static org.apache.solr.cloud.AbstractDistribZkTestBase.verifyReplicaStatus;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 @Slow
 public class OverseerTest extends SolrTestCaseJ4 {
@@ -223,7 +221,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
 
       if (startElection && collection.length() > 0) {
         zkStateReader.waitForState(collection, 45000, TimeUnit.MILLISECONDS,
-            (liveNodes, collectionState) -> getShardId(collectionState, coreNodeName) != null);
+            (liveNodes, collectionState, rsp) -> getShardId(collectionState, coreNodeName) != null);
         String shardId = getShardId(collection, coreNodeName);
         if (shardId != null) {
           ElectionContext prevContext = electionContext.get(coreName);
@@ -547,7 +545,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       Set<String> availableCollections = state.getCollectionsMap().keySet();
       int availableCount = 0;
       for(String requiredCollection: collections) {
-        stateReader.waitForState(requiredCollection, 30000, TimeUnit.MILLISECONDS, (liveNodes, collectionState) ->  collectionState != null);
+        stateReader.waitForState(requiredCollection, 30000, TimeUnit.MILLISECONDS, (liveNodes, collectionState, rsp) ->  collectionState != null);
         if(availableCollections.contains(requiredCollection)) {
           availableCount++;
         }
@@ -623,7 +621,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       throws InterruptedException, KeeperException, TimeoutException {
 
     reader.waitForState(collection, 15000, TimeUnit.MILLISECONDS,
-        (liveNodes, collectionState) -> collectionState != null
+        (liveNodes, collectionState, rsp) -> collectionState != null
             && expectedCore.equals((collectionState.getLeader(shard) != null)
                 ? collectionState.getLeader(shard).getStr(ZkStateReader.CORE_NAME_PROP) : null));
 
@@ -691,7 +689,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       mockController.publishState(COLLECTION, core, core_node, "shard1", null, numShards, true, overseers.get(1));
 
       reader.waitForState(COLLECTION, 5000,
-            TimeUnit.MILLISECONDS, (liveNodes, collectionState) -> collectionState != null && collectionState.getReplica(core_node) == null);
+            TimeUnit.MILLISECONDS, (liveNodes, collectionState, rsp) -> collectionState != null && collectionState.getReplica(core_node) == null);
 
       reader.forceUpdateCollection(COLLECTION);
       // as of SOLR-5209 core removal does not cascade to remove the slice and collection
@@ -1140,7 +1138,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
         overseerClient = electNewOverseer(server.getZkAddress());
         assertTrue(overseers.size() > 0);
 
-        reader.waitForState("perf_sentinel", 15000, TimeUnit.MILLISECONDS, (liveNodes, collectionState) -> collectionState != null);
+        reader.waitForState("perf_sentinel", 15000, TimeUnit.MILLISECONDS, (liveNodes, collectionState, rsp) -> collectionState != null);
 
       } finally {
         context.stop();
@@ -1250,7 +1248,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       queue.offer(Utils.toJSON(m));
 
       reader.waitForState(COLLECTION, 1000, TimeUnit.MILLISECONDS,
-          (liveNodes, collectionState) -> collectionState != null && collectionState.getSlice("shard1") != null
+          (liveNodes, collectionState, rsp) -> collectionState != null && collectionState.getSlice("shard1") != null
               && collectionState.getSlice("shard1").getReplicas().size() == 3);
 
       assertNotNull(reader.getClusterState().getCollection(COLLECTION).getSlice("shard1"));
@@ -1544,7 +1542,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
 
           {
             String shard = "shard"+ss;
-            zkStateReader.waitForState(COLLECTION, 15000, TimeUnit.MILLISECONDS, (liveNodes, collectionState) -> collectionState != null && (collectionState.getSlice(shard) == null || collectionState.getSlice(shard).getReplicasMap().get("core_node"+N) == null));
+            zkStateReader.waitForState(COLLECTION, 15000, TimeUnit.MILLISECONDS, (liveNodes, collectionState, rsp) -> collectionState != null && (collectionState.getSlice(shard) == null || collectionState.getSlice(shard).getReplicasMap().get("core_node"+N) == null));
           }
 
           final DocCollection docCollection = zkStateReader.getClusterState().getCollection(COLLECTION);
diff --git a/solr/core/src/test/org/apache/solr/cloud/ReindexCollectionTest.java b/solr/core/src/test/org/apache/solr/cloud/ReindexCollectionTest.java
index f03e4f8..db3354c 100644
--- a/solr/core/src/test/org/apache/solr/cloud/ReindexCollectionTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/ReindexCollectionTest.java
@@ -137,7 +137,7 @@ public class ReindexCollectionTest extends SolrCloudTestCase {
     assertEquals(status.toString(), (long)NUM_DOCS, ((Number)status.get("inputDocs")).longValue());
     assertEquals(status.toString(), (long)NUM_DOCS, ((Number)status.get("processedDocs")).longValue());
 
-    CloudUtil.waitForState(cloudManager, "did not finish copying in time", targetCollection, (liveNodes, coll) -> {
+    CloudUtil.waitForState(cloudManager, "did not finish copying in time", targetCollection, (liveNodes, coll, replicaStateProvider) -> {
       ReindexCollectionCmd.State state = ReindexCollectionCmd.State.get(coll.getStr(ReindexCollectionCmd.REINDEXING_STATE));
       return ReindexCollectionCmd.State.FINISHED == state;
     });
@@ -189,7 +189,7 @@ public class ReindexCollectionTest extends SolrCloudTestCase {
     }
     assertNotNull("target collection not present after 30s", realTargetCollection);
 
-    CloudUtil.waitForState(cloudManager, "did not finish copying in time", realTargetCollection, (liveNodes, coll) -> {
+    CloudUtil.waitForState(cloudManager, "did not finish copying in time", realTargetCollection, (liveNodes, coll, rsp) -> {
       ReindexCollectionCmd.State state = ReindexCollectionCmd.State.get(coll.getStr(ReindexCollectionCmd.REINDEXING_STATE));
       return ReindexCollectionCmd.State.FINISHED == state;
     });
@@ -224,7 +224,7 @@ public class ReindexCollectionTest extends SolrCloudTestCase {
         .setConfigName("conf3");
     req.process(solrClient);
 
-    CloudUtil.waitForState(cloudManager, "did not finish copying in time", targetCollection, (liveNodes, coll) -> {
+    CloudUtil.waitForState(cloudManager, "did not finish copying in time", targetCollection, (liveNodes, coll, rsp) -> {
       ReindexCollectionCmd.State state = ReindexCollectionCmd.State.get(coll.getStr(ReindexCollectionCmd.REINDEXING_STATE));
       return ReindexCollectionCmd.State.FINISHED == state;
     });
@@ -261,7 +261,7 @@ public class ReindexCollectionTest extends SolrCloudTestCase {
         .setCollectionParam("q", "id:10*");
     req.process(solrClient);
 
-    CloudUtil.waitForState(cloudManager, "did not finish copying in time", targetCollection, (liveNodes, coll) -> {
+    CloudUtil.waitForState(cloudManager, "did not finish copying in time", targetCollection, (liveNodes, coll, rsp) -> {
       ReindexCollectionCmd.State state = ReindexCollectionCmd.State.get(coll.getStr(ReindexCollectionCmd.REINDEXING_STATE));
       return ReindexCollectionCmd.State.FINISHED == state;
     });
@@ -338,7 +338,7 @@ public class ReindexCollectionTest extends SolrCloudTestCase {
     });
     // verify that the source collection is read-write and has no reindexing flags
     CloudUtil.waitForState(cloudManager, "collection state is incorrect", sourceCollection,
-        ((liveNodes, collectionState) ->
+        ((liveNodes, collectionState, replicaStateProvider) ->
             !collectionState.isReadOnly() &&
             collectionState.getStr(ReindexCollectionCmd.REINDEXING_STATE) == null &&
             getState(sourceCollection) == null));
@@ -356,7 +356,7 @@ public class ReindexCollectionTest extends SolrCloudTestCase {
     String asyncId = req.processAsync(solrClient);
     // wait for the source collection to be put in readOnly mode
     CloudUtil.waitForState(cloudManager, "source collection didn't become readOnly",
-        sourceCollection, (liveNodes, coll) -> coll.isReadOnly());
+        sourceCollection, (liveNodes, coll, rsp) -> coll.isReadOnly());
 
     req = CollectionAdminRequest.reindexCollection(sourceCollection);
     req.setCommand("abort");
@@ -366,7 +366,7 @@ public class ReindexCollectionTest extends SolrCloudTestCase {
     assertEquals(status.toString(), "aborting", status.get("state"));
 
     CloudUtil.waitForState(cloudManager, "incorrect collection state", sourceCollection,
-        ((liveNodes, collectionState) ->
+        ((liveNodes, collectionState, replicaStateProvider) ->
             collectionState.isReadOnly() &&
             getState(sourceCollection) == ReindexCollectionCmd.State.ABORTED));
 
@@ -379,7 +379,7 @@ public class ReindexCollectionTest extends SolrCloudTestCase {
     // let the process continue
     TestInjection.reindexLatch.countDown();
     CloudUtil.waitForState(cloudManager, "source collection is in wrong state",
-        sourceCollection, (liveNodes, docCollection) -> !docCollection.isReadOnly() && getState(sourceCollection) == null);
+        sourceCollection, (liveNodes, docCollection, replicaStateProvider) -> !docCollection.isReadOnly() && getState(sourceCollection) == null);
     // verify the response
     rsp = CollectionAdminRequest.requestStatus(asyncId).process(solrClient);
     status = (Map<String, Object>)rsp.getResponse().get(ReindexCollectionCmd.REINDEX_STATUS);
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudConsistency.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudConsistency.java
index f3224ff..c27fb59 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestCloudConsistency.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudConsistency.java
@@ -156,7 +156,7 @@ public class TestCloudConsistency extends SolrCloudTestCase {
     cluster.waitForJettyToStop(j1);
     cluster.waitForJettyToStop(j2);
     
-    waitForState("", collection, (liveNodes, collectionState) ->
+    waitForState("", collection, (liveNodes, collectionState, rsp) ->
       collectionState.getSlice("shard1").getReplicas().stream()
           .filter(replica -> replica.getState() == Replica.State.DOWN).count() == 2);
 
@@ -164,7 +164,7 @@ public class TestCloudConsistency extends SolrCloudTestCase {
     JettySolrRunner j3 = cluster.getJettySolrRunner(0);
     j3.stop();
     cluster.waitForJettyToStop(j3);
-    waitForState("", collection, (liveNodes, collectionState) -> collectionState.getReplica(leader.getName()).getState() == Replica.State.DOWN);
+    waitForState("", collection, (liveNodes, collectionState, rsp) -> collectionState.getReplica(leader.getName()).getState() == Replica.State.DOWN);
 
     cluster.getJettySolrRunner(1).start();
     cluster.getJettySolrRunner(2).start();
@@ -187,7 +187,7 @@ public class TestCloudConsistency extends SolrCloudTestCase {
     // waitForNode not solid yet?
     cluster.waitForAllNodes(30);
     
-    waitForState("Timeout waiting for leader", collection, (liveNodes, collectionState) -> {
+    waitForState("Timeout waiting for leader", collection, (liveNodes, collectionState, rsp) -> {
       Replica newLeader = collectionState.getLeader("shard1");
       return newLeader != null && newLeader.getName().equals(leader.getName());
     });
@@ -211,7 +211,7 @@ public class TestCloudConsistency extends SolrCloudTestCase {
     for (int i = 1; i < 3; i++) {
       proxies.get(cluster.getJettySolrRunner(i)).reopen();
     }
-    waitForState("Timeout waiting for leader goes DOWN", collection, (liveNodes, collectionState)
+    waitForState("Timeout waiting for leader goes DOWN", collection, (liveNodes, collectionState, rsp)
         -> collectionState.getReplica(leader.getName()).getState() == Replica.State.DOWN);
 
     TimeOut timeOut = new TimeOut(10, TimeUnit.SECONDS, TimeSource.NANO_TIME);
@@ -225,7 +225,7 @@ public class TestCloudConsistency extends SolrCloudTestCase {
     proxies.get(cluster.getJettySolrRunner(0)).reopen();
     cluster.getJettySolrRunner(0).start();
     cluster.waitForAllNodes(30);;
-    waitForState("Timeout waiting for leader", collection, (liveNodes, collectionState) -> {
+    waitForState("Timeout waiting for leader", collection, (liveNodes, collectionState, rsp) -> {
       Replica newLeader = collectionState.getLeader("shard1");
       return newLeader != null && newLeader.getName().equals(leader.getName());
     });
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudRecovery2.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudRecovery2.java
index ae5e769..ff04dd1 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestCloudRecovery2.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudRecovery2.java
@@ -58,7 +58,7 @@ public class TestCloudRecovery2 extends SolrCloudTestCase {
     try (HttpSolrClient client1 = getHttpSolrClient(node1.getBaseUrl().toString())) {
 
       node2.stop();
-      waitForState("", COLLECTION, (liveNodes, collectionState) -> liveNodes.size() == 1);
+      waitForState("", COLLECTION, (liveNodes, collectionState, rsp) -> liveNodes.size() == 1);
 
       UpdateRequest req = new UpdateRequest();
       for (int i = 0; i < 100; i++) {
@@ -88,7 +88,7 @@ public class TestCloudRecovery2 extends SolrCloudTestCase {
 
       //
       node2.stop();
-      waitForState("", COLLECTION, (liveNodes, collectionState) -> liveNodes.size() == 1);
+      waitForState("", COLLECTION, (liveNodes, collectionState, rsp) -> liveNodes.size() == 1);
 
       new UpdateRequest().add("id", "1", "num", "20")
           .commit(client1, COLLECTION);
@@ -103,7 +103,7 @@ public class TestCloudRecovery2 extends SolrCloudTestCase {
       }
 
       node2.stop();
-      waitForState("", COLLECTION, (liveNodes, collectionState) -> liveNodes.size() == 1);
+      waitForState("", COLLECTION, (liveNodes, collectionState, rsp) -> liveNodes.size() == 1);
 
       new UpdateRequest().add("id", "1", "num", "30")
           .commit(client1, COLLECTION);
@@ -122,7 +122,7 @@ public class TestCloudRecovery2 extends SolrCloudTestCase {
     }
 
     node1.stop();
-    waitForState("", COLLECTION, (liveNodes, collectionState) -> {
+    waitForState("", COLLECTION, (liveNodes, collectionState, rsp) -> {
       Replica leader = collectionState.getLeader("shard1");
       return leader != null && leader.getNodeName().equals(node2.getNodeName());
     });
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudSearcherWarming.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudSearcherWarming.java
index 70680c2..4f5a2c7 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestCloudSearcherWarming.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudSearcherWarming.java
@@ -193,7 +193,7 @@ public class TestCloudSearcherWarming extends SolrCloudTestCase {
     waitForState("The collection should have 1 shard and 1 replica", collectionName, clusterShape(1, 1));
     // the above call is not enough because we want to assert that the down'ed replica is not active
     // but clusterShape will also return true if replica is not live -- which we don't want
-    CollectionStatePredicate collectionStatePredicate = (liveNodes, collectionState) -> {
+    CollectionStatePredicate collectionStatePredicate = (liveNodes, collectionState, rsp) -> {
       for (Replica r : collectionState.getReplicas()) {
         if (r.getNodeName().equals(oldNodeName.get())) {
           return r.getState() == Replica.State.DOWN;
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestDeleteCollectionOnDownNodes.java b/solr/core/src/test/org/apache/solr/cloud/TestDeleteCollectionOnDownNodes.java
index e6836a3..3d583cf 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestDeleteCollectionOnDownNodes.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestDeleteCollectionOnDownNodes.java
@@ -58,7 +58,7 @@ public class TestDeleteCollectionOnDownNodes extends SolrCloudTestCase {
 
     // delete the collection
     CollectionAdminRequest.deleteCollection("halfdeletedcollection2").process(cluster.getSolrClient());
-    waitForState("Timed out waiting for collection to be deleted", "halfdeletedcollection2", (n, c) -> c == null);
+    waitForState("Timed out waiting for collection to be deleted", "halfdeletedcollection2", (n, c, rsp) -> c == null);
 
     assertFalse("Still found collection that should be gone",
         cluster.getSolrClient().getZkStateReader().getClusterState().hasCollection("halfdeletedcollection2"));
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestLeaderElectionWithEmptyReplica.java b/solr/core/src/test/org/apache/solr/cloud/TestLeaderElectionWithEmptyReplica.java
index f0bb15a..90154ee 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestLeaderElectionWithEmptyReplica.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestLeaderElectionWithEmptyReplica.java
@@ -94,7 +94,7 @@ public class TestLeaderElectionWithEmptyReplica extends SolrCloudTestCase {
 
     // wait until everyone is active
     solrClient.waitForState(COLLECTION_NAME, DEFAULT_TIMEOUT, TimeUnit.SECONDS,
-        (n, c) -> DocCollection.isFullyActive(n, c, 1, 2));
+        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 2));
 
     // now query each replica and check for consistency
     assertConsistentReplicas(solrClient, solrClient.getZkStateReader().getClusterState().getCollection(COLLECTION_NAME).getSlice("shard1"));
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java b/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java
index 50404be..6541177 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java
@@ -28,6 +28,7 @@ import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
+import com.carrotsearch.randomizedtesting.annotations.Repeat;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.ClientProtocolException;
 import org.apache.http.client.HttpClient;
@@ -65,8 +66,6 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.carrotsearch.randomizedtesting.annotations.Repeat;
-
 @Slow
 @AwaitsFix(bugUrl="https://issues.apache.org/jira/browse/SOLR-12028")
 public class TestPullReplica extends SolrCloudTestCase {
@@ -598,7 +597,7 @@ public class TestPullReplica extends SolrCloudTestCase {
    * passes only if all replicas are active or down, and the "liveNodes" reflect the same status
    */
   private CollectionStatePredicate clusterStateReflectsActiveAndDownReplicas() {
-    return (liveNodes, collectionState) -> {
+    return (liveNodes, collectionState, rsp) -> {
       for (Replica r:collectionState.getReplicas()) {
         if (r.getState() != Replica.State.DOWN && r.getState() != Replica.State.ACTIVE) {
           return false;
@@ -616,7 +615,7 @@ public class TestPullReplica extends SolrCloudTestCase {
 
 
   private CollectionStatePredicate activeReplicaCount(int numNrtReplicas, int numTlogReplicas, int numPullReplicas) {
-    return (liveNodes, collectionState) -> {
+    return (liveNodes, collectionState, rsp) -> {
       int nrtFound = 0, tlogFound = 0, pullFound = 0;
       if (collectionState == null)
         return false;
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestPullReplicaErrorHandling.java b/solr/core/src/test/org/apache/solr/cloud/TestPullReplicaErrorHandling.java
index a449589..e33c533 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestPullReplicaErrorHandling.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestPullReplicaErrorHandling.java
@@ -325,7 +325,7 @@ public void testCantConnectToPullReplica() throws Exception {
   }
   
   private CollectionStatePredicate activeReplicaCount(int numWriter, int numActive, int numPassive) {
-    return (liveNodes, collectionState) -> {
+    return (liveNodes, collectionState, rsp) -> {
       int writersFound = 0, activesFound = 0, passivesFound = 0;
       if (collectionState == null)
         return false;
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestRebalanceLeaders.java b/solr/core/src/test/org/apache/solr/cloud/TestRebalanceLeaders.java
index b207fa3..f63ebce 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestRebalanceLeaders.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestRebalanceLeaders.java
@@ -18,7 +18,15 @@ package org.apache.solr.cloud;
 
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.lucene.util.LuceneTestCase;
@@ -452,7 +460,7 @@ public class TestRebalanceLeaders extends SolrCloudTestCase {
     cluster.getSolrClient().request(request);
     String propLC = prop.toLowerCase(Locale.ROOT);
     waitForState("Expecting property '" + prop + "'to appear on replica " + rep.getName(), COLLECTION_NAME,
-        (n, c) -> "true".equals(c.getReplica(rep.getName()).getProperty(propLC)));
+        (n, c, rsp) -> "true".equals(c.getReplica(rep.getName()).getProperty(propLC)));
 
   }
 
@@ -467,7 +475,7 @@ public class TestRebalanceLeaders extends SolrCloudTestCase {
     assertEquals(0, resp.getStatus());
     String propLC = prop.toLowerCase(Locale.ROOT);
     waitForState("Expecting property '" + prop + "'to appear on replica " + rep.getName(), COLLECTION_NAME,
-        (n, c) -> "true".equals(c.getReplica(rep.getName()).getProperty(propLC)));
+        (n, c, rsp) -> "true".equals(c.getReplica(rep.getName()).getProperty(propLC)));
 
   }
 
@@ -477,7 +485,7 @@ public class TestRebalanceLeaders extends SolrCloudTestCase {
         .process(cluster.getSolrClient());
     assertEquals("Admin request failed; ", 0, resp.getStatus());
     waitForState("Expecting property '" + prop + "' to be removed from replica " + rep.getName(), COLLECTION_NAME,
-        (n, c) -> c.getReplica(rep.getName()).getProperty(prop) == null);
+        (n, c, rsp) -> c.getReplica(rep.getName()).getProperty(prop) == null);
   }
 
   // Intentionally un-balance the property to insure that BALANCESHARDUNIQUE does its job. There was an odd case
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestSkipOverseerOperations.java b/solr/core/src/test/org/apache/solr/cloud/TestSkipOverseerOperations.java
index 73bf698..9f86de7 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestSkipOverseerOperations.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestSkipOverseerOperations.java
@@ -109,7 +109,7 @@ public class TestSkipOverseerOperations extends SolrCloudTestCase {
     });
     
     waitForState("Expected single liveNode", collection,
-        (liveNodes, collectionState) -> liveNodes.size() == 1);
+        (liveNodes, collectionState, rsp) -> liveNodes.size() == 1);
 
     CollectionAdminResponse resp = CollectionAdminRequest.getOverseerStatus().process(cluster.getSolrClient());
     for (JettySolrRunner solrRunner : notOverseerNodes) {
@@ -177,7 +177,7 @@ public class TestSkipOverseerOperations extends SolrCloudTestCase {
     });
     
     waitForState("Expected single liveNode", collection,
-        (liveNodes, collectionState) -> liveNodes.size() == 1);
+        (liveNodes, collectionState, rsp) -> liveNodes.size() == 1);
 
     CollectionAdminResponse resp = CollectionAdminRequest.getOverseerStatus().process(cluster.getSolrClient());
     for (JettySolrRunner solrRunner : notOverseerNodes) {
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java b/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java
index 58f3b7a..f40e788 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java
@@ -678,7 +678,7 @@ public class TestTlogReplica extends SolrCloudTestCase {
 
   private void waitForLeaderChange(JettySolrRunner oldLeaderJetty, String shardName) {
     waitForState("Expect new leader", collectionName,
-        (liveNodes, collectionState) -> {
+        (liveNodes, collectionState, rsp) -> {
           Replica leader = collectionState.getLeader(shardName);
           if (leader == null || !leader.isActive(cluster.getSolrClient().getZkStateReader().getClusterState().getLiveNodes())) {
             return false;
@@ -831,7 +831,7 @@ public class TestTlogReplica extends SolrCloudTestCase {
    * passes only if all replicas are active or down, and the "liveNodes" reflect the same status
    */
   private CollectionStatePredicate clusterStateReflectsActiveAndDownReplicas() {
-    return (liveNodes, collectionState) -> {
+    return (liveNodes, collectionState, rsp) -> {
       for (Replica r:collectionState.getReplicas()) {
         if (r.getState() != Replica.State.DOWN && r.getState() != Replica.State.ACTIVE) {
           return false;
@@ -849,7 +849,7 @@ public class TestTlogReplica extends SolrCloudTestCase {
 
 
   private CollectionStatePredicate activeReplicaCount(int numNrtReplicas, int numTlogReplicas, int numPullReplicas) {
-    return (liveNodes, collectionState) -> {
+    return (liveNodes, collectionState, rsp) -> {
       int nrtFound = 0, tlogFound = 0, pullFound = 0;
       if (collectionState == null)
         return false;
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestWaitForStateWithJettyShutdowns.java b/solr/core/src/test/org/apache/solr/cloud/TestWaitForStateWithJettyShutdowns.java
index f2d16a8..b25dd6d 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestWaitForStateWithJettyShutdowns.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestWaitForStateWithJettyShutdowns.java
@@ -18,9 +18,7 @@
 package org.apache.solr.cloud;
 
 import java.lang.invoke.MethodHandles;
-
 import java.util.Set;
-
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -28,18 +26,18 @@ import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.cloud.ReplicaStateProvider;
 import org.apache.solr.client.solrj.embedded.JettySolrRunner;
 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.common.cloud.CollectionStatePredicate;
 import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.util.ExecutorUtil;
 import org.apache.solr.util.DefaultSolrThreadFactory;
-
-import static org.apache.solr.cloud.SolrCloudTestCase.clusterShape;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.solr.cloud.SolrCloudTestCase.clusterShape;
+
 public class TestWaitForStateWithJettyShutdowns extends SolrTestCaseJ4 {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
@@ -143,8 +141,10 @@ public class TestWaitForStateWithJettyShutdowns extends SolrTestCaseJ4 {
       this.latch = latch;
       this.inner = inner;
     }
-    public boolean matches(Set<String> liveNodes, DocCollection collectionState) {
-      final boolean result = inner.matches(liveNodes, collectionState);
+
+    @Override
+    public boolean matches(Set<String> liveNodes, DocCollection collectionState, ReplicaStateProvider rsp) {
+      final boolean result = inner.matches(liveNodes, collectionState, rsp);
       log.info("Predicate called: result={}, (pre)latch={}, liveNodes={}, state={}",
                result, latch.getCount(), liveNodes, collectionState);
       latch.countDown();
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionReloadTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionReloadTest.java
index c084412..8480237 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionReloadTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionReloadTest.java
@@ -74,7 +74,7 @@ public class CollectionReloadTest extends SolrCloudTestCase {
 
     cluster.expireZkSession(cluster.getReplicaJetty(leader));
 
-    waitForState("Timed out waiting for core to re-register as ACTIVE after session expiry", testCollectionName, (n, c) -> {
+    waitForState("Timed out waiting for core to re-register as ACTIVE after session expiry", testCollectionName, (n, c, rsp) -> {
       log.info("Collection state: {}", c.toString());
       Replica expiredReplica = c.getReplica(leader.getName());
       return expiredReplica.getState() == Replica.State.ACTIVE && c.getZNodeVersion() > initialStateVersion;
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionTooManyReplicasTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionTooManyReplicasTest.java
index 25aaf4e..fbbdfb0 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionTooManyReplicasTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionTooManyReplicasTest.java
@@ -108,7 +108,7 @@ public class CollectionTooManyReplicasTest extends SolrCloudTestCase {
         e2.getMessage().contains("given the current number of eligible live nodes"));
 
     // wait for recoveries to finish, for a clean shutdown - see SOLR-9645
-    waitForState("Expected to see all replicas active", collectionName, (n, c) -> {
+    waitForState("Expected to see all replicas active", collectionName, (n, c, rsp) -> {
       for (Replica r : c.getReplicas()) {
         if (r.getState() != Replica.State.ACTIVE)
           return false;
@@ -159,7 +159,7 @@ public class CollectionTooManyReplicasTest extends SolrCloudTestCase {
 
     // And finally, ensure that there are all the replicas we expect. We should have shards 1, 2 and 4 and each
     // should have exactly two replicas
-    waitForState("Expected shards shardstart, 1, 2 and 4, each with two active replicas", collectionName, (n, c) -> {
+    waitForState("Expected shards shardstart, 1, 2 and 4, each with two active replicas", collectionName, (n, c, rsp) -> {
       return DocCollection.isFullyActive(n, c, 4, 2);
     });
     Map<String, Slice> slices = getCollectionState(collectionName).getSlicesMap();
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIAsyncDistributedZkTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIAsyncDistributedZkTest.java
index 953fad0..905793f 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIAsyncDistributedZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIAsyncDistributedZkTest.java
@@ -162,7 +162,7 @@ public class CollectionsAPIAsyncDistributedZkTest extends SolrCloudTestCase {
     assertSame("AddReplica did not complete", RequestStatusState.COMPLETED, state);
 
     //cloudClient watch might take a couple of seconds to reflect it
-    client.getZkStateReader().waitForState(collection, 20, TimeUnit.SECONDS, (n, c) -> {
+    client.getZkStateReader().waitForState(collection, 20, TimeUnit.SECONDS, (n, c, rsp) -> {
       if (c == null)
         return false;
       Slice slice = c.getSlice("shard1");
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistributedZkTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistributedZkTest.java
index 1899d8d..5b22d62 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistributedZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistributedZkTest.java
@@ -16,9 +16,9 @@
  */
 package org.apache.solr.cloud.api.collections;
 
-import static org.apache.solr.common.cloud.ZkStateReader.CORE_NAME_PROP;
-import static org.apache.solr.common.cloud.ZkStateReader.REPLICATION_FACTOR;
-
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.lang.management.ManagementFactory;
@@ -38,10 +38,7 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
-import javax.management.MBeanServer;
-import javax.management.MBeanServerFactory;
-import javax.management.ObjectName;
-
+import com.google.common.collect.ImmutableList;
 import org.apache.lucene.util.LuceneTestCase.Slow;
 import org.apache.lucene.util.TestUtil;
 import org.apache.solr.client.solrj.SolrQuery;
@@ -81,7 +78,8 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.ImmutableList;
+import static org.apache.solr.common.cloud.ZkStateReader.CORE_NAME_PROP;
+import static org.apache.solr.common.cloud.ZkStateReader.REPLICATION_FACTOR;
 
 /**
  * Tests the Cloud Collections API.
@@ -335,7 +333,7 @@ public class CollectionsAPIDistributedZkTest extends SolrCloudTestCase {
     CollectionAdminRequest.createCollection("acollectionafterbaddelete", "conf", 1, 2)
         .process(cluster.getSolrClient());
     waitForState("Collection creation after a bad delete failed", "acollectionafterbaddelete",
-        (n, c) -> DocCollection.isFullyActive(n, c, 1, 2));
+        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 2));
   }
 
   @Test
@@ -468,7 +466,7 @@ public class CollectionsAPIDistributedZkTest extends SolrCloudTestCase {
       String collectionName = "awhollynewcollection_" + i;
       final int j = i;
       waitForState("Expected to see collection " + collectionName, collectionName,
-          (n, c) -> {
+          (n, c, rsp) -> {
             CollectionAdminRequest.Create req = createRequests[j];
             return DocCollection.isFullyActive(n, c, req.getNumShards(), req.getReplicationFactor());
           });
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/CustomCollectionTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/CustomCollectionTest.java
index d556271..224148c 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/CustomCollectionTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/CustomCollectionTest.java
@@ -103,7 +103,7 @@ public class CustomCollectionTest extends SolrCloudTestCase {
     //Testing CREATESHARD
     CollectionAdminRequest.createShard(collection, "x")
         .process(cluster.getSolrClient());
-    waitForState("Expected shard 'x' to be active", collection, (n, c) -> {
+    waitForState("Expected shard 'x' to be active", collection, (n, c, rsp) -> {
       if (c.getSlice("x") == null)
         return false;
       for (Replica r : c.getSlice("x")) {
@@ -194,7 +194,7 @@ public class CustomCollectionTest extends SolrCloudTestCase {
     CollectionAdminRequest.createShard(collectionName, "x")
         .process(cluster.getSolrClient());
 
-    waitForState("Not enough active replicas in shard 'x'", collectionName, (n, c) -> {
+    waitForState("Not enough active replicas in shard 'x'", collectionName, (n, c, rsp) -> {
       return c.getSlice("x").getReplicas().size() == 1;
     });
 
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoAddReplicasIntegrationTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoAddReplicasIntegrationTest.java
index cd92ce6..b4f82ae 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoAddReplicasIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoAddReplicasIntegrationTest.java
@@ -16,10 +16,8 @@
  */
 package org.apache.solr.cloud.autoscaling;
 
-import static org.apache.solr.common.util.Utils.makeMap;
-
-import java.lang.invoke.MethodHandles;
 import java.io.IOException;
+import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -34,8 +32,8 @@ import org.apache.solr.client.solrj.request.QueryRequest;
 import org.apache.solr.client.solrj.request.V2Request;
 import org.apache.solr.cloud.MiniSolrCloudCluster;
 import org.apache.solr.cloud.SolrCloudTestCase;
-import org.apache.solr.common.cloud.CollectionStatePredicate;
 import org.apache.solr.common.cloud.ClusterStateUtil;
+import org.apache.solr.common.cloud.CollectionStatePredicate;
 import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.ZkStateReader;
@@ -48,10 +46,11 @@ import org.apache.solr.util.TimeOut;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.solr.common.util.Utils.makeMap;
+
 @org.apache.solr.util.LogLevel("org.apache.solr.cloud.autoscaling=DEBUG;org.apache.solr.cloud.autoscaling.NodeLostTrigger=TRACE;org.apache.solr.cloud.Overseer=DEBUG;org.apache.solr.cloud.overseer=DEBUG")
 public class AutoAddReplicasIntegrationTest extends SolrCloudTestCase {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -394,7 +393,7 @@ public class AutoAddReplicasIntegrationTest extends SolrCloudTestCase {
 
   /** 
    * {@link MiniSolrCloudCluster#waitForNode} Doesn't check isRunning first, and we don't want to 
-   * use {@link MiniSolrCloudCluster#waitForAllNodes} because we don't want to waste cycles checking 
+   * use {@link MiniSolrCloudCluster#waitForAllNodes(int)} because we don't want to waste cycles checking
    * nodes we aren't messing with  
    */
   private void waitForNodeLive(final JettySolrRunner jetty)
@@ -427,8 +426,8 @@ public class AutoAddReplicasIntegrationTest extends SolrCloudTestCase {
   
   private static CollectionStatePredicate clusterShapeNoDownReplicas(final int expectedShards,
                                                                      final int expectedReplicas) {
-    return (liveNodes, collectionState)
-      -> (clusterShape(expectedShards, expectedReplicas).matches(liveNodes, collectionState)
+    return (liveNodes, collectionState, rsp)
+      -> (clusterShape(expectedShards, expectedReplicas).matches(liveNodes, collectionState, rsp)
           && collectionState.getReplicas().size() == expectedReplicas);
   }
   
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/ComputePlanActionTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/ComputePlanActionTest.java
index 9b579ac..962c943 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/ComputePlanActionTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/ComputePlanActionTest.java
@@ -361,7 +361,7 @@ public class ComputePlanActionTest extends SolrCloudTestCase {
     create.process(solrClient);
 
     waitForState("Timed out waiting for replicas of new collection to be active",
-        "testNodeAdded", (liveNodes, collectionState) -> collectionState.getReplicas().stream().allMatch(replica -> replica.isActive(liveNodes)));
+        "testNodeAdded", (liveNodes, collectionState, rsp) -> collectionState.getReplicas().stream().allMatch(replica -> replica.isActive(liveNodes)));
 
     // reset to the original policy which has only 1 replica per shard per node
     setClusterPolicyCommand = "{" +
@@ -608,7 +608,7 @@ public class ComputePlanActionTest extends SolrCloudTestCase {
     create.process(solrClient);
 
     waitForState("Timed out waiting for replicas of new collection to be active",
-        collectionNamePrefix + "_0", (liveNodes, collectionState) ->
+        collectionNamePrefix + "_0", (liveNodes, collectionState, rsp) ->
             collectionState.getReplicas().stream().allMatch(replica -> replica.isActive(liveNodes)));
 
     JettySolrRunner newNode = cluster.startJettySolrRunner();
@@ -635,7 +635,7 @@ public class ComputePlanActionTest extends SolrCloudTestCase {
       create.process(solrClient);
 
       waitForState("Timed out waiting for replicas of new collection to be active",
-          collectionNamePrefix + "_" + i, (liveNodes, collectionState) ->
+          collectionNamePrefix + "_" + i, (liveNodes, collectionState,rsp) ->
               collectionState.getReplicas().stream().allMatch(replica -> replica.isActive(liveNodes)));
     }
 
@@ -706,7 +706,7 @@ public class ComputePlanActionTest extends SolrCloudTestCase {
     create.process(solrClient);
 
     waitForState("Timed out waiting for replicas of new collection to be active",
-        collectionNamePrefix + "_0", (liveNodes, collectionState) ->
+        collectionNamePrefix + "_0", (liveNodes, collectionState,rsp) ->
             collectionState.getReplicas().stream().allMatch(replica -> replica.isActive(liveNodes)));
 
     cluster.stopJettySolrRunner(newNode);
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledMaintenanceTriggerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledMaintenanceTriggerTest.java
index 2fb82cd..3c1be6b 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledMaintenanceTriggerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledMaintenanceTriggerTest.java
@@ -29,8 +29,8 @@ import java.util.concurrent.TimeUnit;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.cloud.DistribStateManager;
-import org.apache.solr.client.solrj.cloud.autoscaling.AutoScalingConfig;
 import org.apache.solr.client.solrj.cloud.SolrCloudManager;
+import org.apache.solr.client.solrj.cloud.autoscaling.AutoScalingConfig;
 import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventProcessorStage;
 import org.apache.solr.client.solrj.embedded.JettySolrRunner;
 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
@@ -309,7 +309,7 @@ public class ScheduledMaintenanceTriggerTest extends SolrCloudTestCase {
 
     ClusterState state = cloudManager.getClusterStateProvider().getClusterState();
 
-    CloudUtil.clusterShape(2, 1).matches(state.getLiveNodes(), state.getCollection(collection1));
+    CloudUtil.clusterShape(2, 1).matches(state.getLiveNodes(), state.getCollection(collection1), cloudManager.getClusterStateProvider().getReplicaStateProvider(collection1));
   }
 
   public static CountDownLatch getTriggerFired() {
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/TestPolicyCloud.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/TestPolicyCloud.java
index 5d7981f..f04a777 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/TestPolicyCloud.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/TestPolicyCloud.java
@@ -180,7 +180,7 @@ public class TestPolicyCloud extends SolrCloudTestCase {
      final int expectedSliceCount,
      final int expectedReplicaCount) {
 
-    return (liveNodes, collection) -> {
+    return (liveNodes, collection, rsp) -> {
       if (null == collection || expectedSliceCount != collection.getSlices().size()) {
         return false;
       }
@@ -263,7 +263,7 @@ public class TestPolicyCloud extends SolrCloudTestCase {
                    
     waitForState("Should have found exactly 1 slice w/2 live Replicas, one on each expected jetty: " +
                  firstNodeName + "/" + firstNodePort + " & " +  secondNodeName + "/" + secondNodePort,
-                 collectionName, (liveNodes, collection) -> {
+                 collectionName, (liveNodes, collection, rsp) -> {
                    // short circut if collection is deleted
                    // or we some how have the wrong number of slices
                    if (null == collection || 1 != collection.getSlices().size()) {
@@ -300,7 +300,7 @@ public class TestPolicyCloud extends SolrCloudTestCase {
     waitForState("Should have found exactly 3 shards (1 inactive) each w/two live Replicas, " +
                  "one on each expected jetty: " +
                  firstNodeName + "/" + firstNodePort + " & " +  secondNodeName + "/" + secondNodePort,
-                 collectionName, (liveNodes, collection) -> {
+                 collectionName, (liveNodes, collection, rsp) -> {
                    // short circut if collection is deleted
                    // or we some how have the wrong number of (active) slices
                    if (null == collection
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestSimComputePlanAction.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestSimComputePlanAction.java
index 4b7f4d3..9602ab9 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestSimComputePlanAction.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestSimComputePlanAction.java
@@ -302,7 +302,7 @@ public class TestSimComputePlanAction extends SimSolrCloudTestCase {
     create.process(solrClient);
 
     CloudUtil.waitForState(cluster, "Timed out waiting for replicas of new collection to be active",
-        "testNodeAdded", (liveNodes, collectionState) -> collectionState.getReplicas().stream().allMatch(replica -> replica.isActive(liveNodes)));
+        "testNodeAdded", (liveNodes, collectionState, rsp) -> collectionState.getReplicas().stream().allMatch(replica -> replica.isActive(liveNodes)));
 
     // reset to the original policy which has only 1 replica per shard per node
     setClusterPolicyCommand = "{" +
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestSimPolicyCloud.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestSimPolicyCloud.java
index 36c94a0..d8e6cce 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestSimPolicyCloud.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestSimPolicyCloud.java
@@ -134,7 +134,7 @@ public class TestSimPolicyCloud extends SimSolrCloudTestCase {
     CollectionAdminRequest.addReplicaToShard(collectionName, "shard1").process(solrClient);
     CloudUtil.waitForState(cluster,
         collectionName, 120l, TimeUnit.SECONDS,
-        (liveNodes, collectionState) -> collectionState.getReplicas().size() == 2);
+        (liveNodes, collectionState, rsp) -> collectionState.getReplicas().size() == 2);
 
     getCollectionState(collectionName).forEachReplica((s, replica) -> assertEquals(nodeId, replica.getNodeName()));
   }
@@ -175,7 +175,7 @@ public class TestSimPolicyCloud extends SimSolrCloudTestCase {
     CollectionAdminRequest.splitShard(collectionName).setShardName("shard1").process(solrClient);
 
     CloudUtil.waitForState(cluster, "Timed out waiting to see 6 replicas for collection: " + collectionName,
-        collectionName, (liveNodes, collectionState) -> collectionState.getReplicas().size() == 6);
+        collectionName, (liveNodes, collectionState, rsp) -> collectionState.getReplicas().size() == 6);
 
     docCollection = getCollectionState(collectionName);
     list = docCollection.getReplicas(firstNode);
diff --git a/solr/core/src/test/org/apache/solr/cloud/hdfs/HDFSCollectionsAPITest.java b/solr/core/src/test/org/apache/solr/cloud/hdfs/HDFSCollectionsAPITest.java
index 6a93042..a0f8a5d 100644
--- a/solr/core/src/test/org/apache/solr/cloud/hdfs/HDFSCollectionsAPITest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/hdfs/HDFSCollectionsAPITest.java
@@ -77,7 +77,7 @@ public class HDFSCollectionsAPITest extends SolrCloudTestCase {
     cluster.getSolrClient().add(new SolrInputDocument("id", "3"));
 
     jettySolrRunner.stop();
-    waitForState("", collection, (liveNodes, collectionState) -> {
+    waitForState("", collection, (liveNodes, collectionState, rsp) -> {
       Replica replica = collectionState.getSlice("shard1").getReplicas().iterator().next();
       return replica.getState() == Replica.State.DOWN;
     });
diff --git a/solr/core/src/test/org/apache/solr/cloud/overseer/ZkStateReaderTest.java b/solr/core/src/test/org/apache/solr/cloud/overseer/ZkStateReaderTest.java
index f4c5bb2..39f9d20 100644
--- a/solr/core/src/test/org/apache/solr/cloud/overseer/ZkStateReaderTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/overseer/ZkStateReaderTest.java
@@ -100,7 +100,7 @@ public class ZkStateReaderTest extends SolrTestCaseJ4 {
         if (explicitRefresh) {
           reader.forceUpdateCollection("c1");
         } else {
-          reader.waitForState("c1", TIMEOUT, TimeUnit.SECONDS, (n, c) -> c != null);
+          reader.waitForState("c1", TIMEOUT, TimeUnit.SECONDS, (n, c, rsp) -> c != null);
         }
 
         DocCollection collection = reader.getClusterState().getCollection("c1");
@@ -124,7 +124,7 @@ public class ZkStateReaderTest extends SolrTestCaseJ4 {
           reader.forceUpdateCollection("c1");
         } else {
           reader.waitForState("c1", TIMEOUT, TimeUnit.SECONDS,
-              (n, c) -> c != null && c.getStateFormat() == 2);
+              (n, c, rsp) -> c != null && c.getStateFormat() == 2);
         }
 
         DocCollection collection = reader.getClusterState().getCollection("c1");
@@ -200,7 +200,7 @@ public class ZkStateReaderTest extends SolrTestCaseJ4 {
       writer.enqueueUpdate(reader.getClusterState(), Collections.singletonList(wc), null);
       writer.writePendingUpdates();
       assertTrue(zkClient.exists(ZkStateReader.COLLECTIONS_ZKNODE + "/c1/state.json", true));
-      reader.waitForState("c1", 1, TimeUnit.SECONDS, (liveNodes, collectionState) -> collectionState != null);
+      reader.waitForState("c1", 1, TimeUnit.SECONDS, (liveNodes, collectionState, rsp) -> collectionState != null);
 
       state = new DocCollection("c1", new HashMap<>(), Collections.singletonMap("x", "y"), DocRouter.DEFAULT, 0, ZkStateReader.CLUSTER_STATE + "/c1/state.json");
       wc = new ZkWriteCommand("c1", state);
@@ -262,7 +262,7 @@ public class ZkStateReaderTest extends SolrTestCaseJ4 {
       assertTrue(zkClient.exists(ZkStateReader.COLLECTIONS_ZKNODE + "/c1/state.json", true));
 
       //reader.forceUpdateCollection("c1");
-      reader.waitForState("c1", TIMEOUT, TimeUnit.SECONDS, (n, c) -> c != null);
+      reader.waitForState("c1", TIMEOUT, TimeUnit.SECONDS, (n, c, rsp) -> c != null);
       ClusterState.CollectionRef ref = reader.getClusterState().getCollectionRef("c1");
       assertNotNull(ref);
       assertFalse(ref.isLazilyLoaded());
diff --git a/solr/core/src/test/org/apache/solr/cloud/rule/RulesTest.java b/solr/core/src/test/org/apache/solr/cloud/rule/RulesTest.java
index afe6acd..f95cb00 100644
--- a/solr/core/src/test/org/apache/solr/cloud/rule/RulesTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/rule/RulesTest.java
@@ -108,7 +108,7 @@ public class RulesTest extends SolrCloudTestCase {
     CollectionAdminRequest.addReplicaToShard(rulesColl, "shard2").process(cluster.getSolrClient());
 
     waitForState("Should have found shard1 w/2active replicas + shard2 w/1active replica",
-                 rulesColl, (liveNodes, collection) -> {
+                 rulesColl, (liveNodes, collection, rsp) -> {
                    // short circut if collection is deleted
                    // or we don't yet have the correct number of slices
                    if (null == collection || 2 != collection.getSlices().size()) {
@@ -179,7 +179,7 @@ public class RulesTest extends SolrCloudTestCase {
         .process(cluster.getSolrClient());
     
     waitForState("Collection should have followed port rule w/ImplicitSnitch, not cluster policy",
-                 rulesColl, (liveNodes, rulesCollection) -> {
+                 rulesColl, (liveNodes, rulesCollection, rsp) -> {
                    // first sanity check that the collection exists & the rules/snitch are listed
                    if (null == rulesCollection) {
                      return false;
@@ -223,7 +223,7 @@ public class RulesTest extends SolrCloudTestCase {
         .process(cluster.getSolrClient());
 
     waitForState("Collection should have followed port rule w/ImplicitSnitch, not cluster policy",
-                 rulesColl, (liveNodes, rulesCollection) -> {
+                 rulesColl, (liveNodes, rulesCollection, rsp) -> {
                    // first sanity check that the collection exists & the rules/snitch are listed
                    if (null == rulesCollection) {
                      return false;
@@ -351,7 +351,7 @@ public class RulesTest extends SolrCloudTestCase {
     cluster.getSolrClient().request(new GenericSolrRequest(POST, COLLECTIONS_HANDLER_PATH, p));
 
     waitForState("Should have found updated rules in DocCollection",
-                 rulesColl, (liveNodes, rulesCollection) -> {
+                 rulesColl, (liveNodes, rulesCollection, rsp) -> {
                    if (null == rulesCollection) {
                      return false;
                    } 
diff --git a/solr/core/src/test/org/apache/solr/handler/component/DistributedQueryComponentOptimizationTest.java b/solr/core/src/test/org/apache/solr/handler/component/DistributedQueryComponentOptimizationTest.java
index 6818676..6cfaedf 100644
--- a/solr/core/src/test/org/apache/solr/handler/component/DistributedQueryComponentOptimizationTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/component/DistributedQueryComponentOptimizationTest.java
@@ -65,7 +65,7 @@ public class DistributedQueryComponentOptimizationTest extends SolrCloudTestCase
         .setMaxShardsPerNode(1)
         .processAndWait(cluster.getSolrClient(), DEFAULT_TIMEOUT);
     cluster.getSolrClient().waitForState(COLLECTION, DEFAULT_TIMEOUT, TimeUnit.SECONDS,
-        (n, c) -> DocCollection.isFullyActive(n, c, sliceCount, 1));
+        (n, c, rsp) -> DocCollection.isFullyActive(n, c, sliceCount, 1));
 
     new UpdateRequest()
         .add(sdoc(id, "1", "text", "a", "test_sS", "21", "payload", ByteBuffer.wrap(new byte[]{0x12, 0x62, 0x15})))
diff --git a/solr/core/src/test/org/apache/solr/schema/ManagedSchemaRoundRobinCloudTest.java b/solr/core/src/test/org/apache/solr/schema/ManagedSchemaRoundRobinCloudTest.java
index 883ebfd..46b85c8 100644
--- a/solr/core/src/test/org/apache/solr/schema/ManagedSchemaRoundRobinCloudTest.java
+++ b/solr/core/src/test/org/apache/solr/schema/ManagedSchemaRoundRobinCloudTest.java
@@ -49,7 +49,7 @@ public class ManagedSchemaRoundRobinCloudTest extends SolrCloudTestCase {
         .setMaxShardsPerNode(1)
         .process(cluster.getSolrClient());
     cluster.getSolrClient().waitForState(COLLECTION, DEFAULT_TIMEOUT, TimeUnit.SECONDS,
-        (n, c) -> DocCollection.isFullyActive(n, c, NUM_SHARDS, 1));
+        (n, c, rsp) -> DocCollection.isFullyActive(n, c, NUM_SHARDS, 1));
   }
 
   @AfterClass
diff --git a/solr/core/src/test/org/apache/solr/schema/PreAnalyzedFieldManagedSchemaCloudTest.java b/solr/core/src/test/org/apache/solr/schema/PreAnalyzedFieldManagedSchemaCloudTest.java
index 04e1be0..25f066b 100644
--- a/solr/core/src/test/org/apache/solr/schema/PreAnalyzedFieldManagedSchemaCloudTest.java
+++ b/solr/core/src/test/org/apache/solr/schema/PreAnalyzedFieldManagedSchemaCloudTest.java
@@ -43,7 +43,7 @@ public class PreAnalyzedFieldManagedSchemaCloudTest extends SolrCloudTestCase {
         .setMaxShardsPerNode(1)
         .process(cluster.getSolrClient());
     cluster.getSolrClient().waitForState(COLLECTION, DEFAULT_TIMEOUT, TimeUnit.SECONDS,
-        (n, c) -> DocCollection.isFullyActive(n, c, 2, 1));
+        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 2, 1));
   }
 
   @Test
diff --git a/solr/core/src/test/org/apache/solr/schema/SchemaApiFailureTest.java b/solr/core/src/test/org/apache/solr/schema/SchemaApiFailureTest.java
index 95cd2a7..b395476 100644
--- a/solr/core/src/test/org/apache/solr/schema/SchemaApiFailureTest.java
+++ b/solr/core/src/test/org/apache/solr/schema/SchemaApiFailureTest.java
@@ -41,7 +41,7 @@ public class SchemaApiFailureTest extends SolrCloudTestCase {
         .setMaxShardsPerNode(2)
         .process(cluster.getSolrClient());
     cluster.getSolrClient().waitForState(COLLECTION, DEFAULT_TIMEOUT, TimeUnit.SECONDS,
-        (n, c) -> DocCollection.isFullyActive(n, c, 2, 1));
+        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 2, 1));
   }
 
   @Test
diff --git a/solr/core/src/test/org/apache/solr/update/processor/RoutedAliasUpdateProcessorTest.java b/solr/core/src/test/org/apache/solr/update/processor/RoutedAliasUpdateProcessorTest.java
index f751066..23e3d13 100644
--- a/solr/core/src/test/org/apache/solr/update/processor/RoutedAliasUpdateProcessorTest.java
+++ b/solr/core/src/test/org/apache/solr/update/processor/RoutedAliasUpdateProcessorTest.java
@@ -239,7 +239,7 @@ public abstract class RoutedAliasUpdateProcessorTest extends SolrCloudTestCase {
   @SuppressWarnings("WeakerAccess")
   void waitCol(int slices, String collection) {
     waitForState("waiting for collections to be created", collection,
-        (liveNodes, collectionState) -> {
+        (liveNodes, collectionState, rsp) -> {
           if (collectionState == null) {
             // per predicate javadoc, this is what we get if the collection doesn't exist at all.
             return false;
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/DirectReplicaState.java b/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/DirectReplicaState.java
new file mode 100644
index 0000000..cccd785
--- /dev/null
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/DirectReplicaState.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.client.solrj.cloud;
+
+import java.util.function.Predicate;
+
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.cloud.Slice;
+
+/**Reads the state from state.json
+ *
+ */
+public class DirectReplicaState implements ReplicaStateProvider {
+
+  private final Predicate<String> isNodeLive;
+
+  public DirectReplicaState(Predicate<String> isNodeLive) {
+    this.isNodeLive = isNodeLive;
+  }
+
+  @Override
+  public Replica.State getState(Replica replica) {
+    return replica.getState();
+  }
+
+  @Override
+  public Replica getLeader(Slice slice) {
+    return slice.getLeader();
+  }
+
+  @Override
+  public boolean isActive(Replica replica) {
+    return  replica.getNodeName() != null &&
+        replica.getState() == Replica.State.ACTIVE &&
+        isNodeLive.test(replica.getNodeName());
+  }
+
+}
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/ReplicaStateProvider.java b/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/ReplicaStateProvider.java
new file mode 100644
index 0000000..0a5e58e
--- /dev/null
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/ReplicaStateProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.client.solrj.cloud;
+
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.cloud.Slice;
+/**An implementation that fetches the state of each replica in a collection
+ * and it also provides the leader of shards
+ *
+ */
+public interface ReplicaStateProvider {
+
+  Replica.State getState(Replica replica);
+
+  Replica getLeader(Slice slice);
+
+  boolean isActive(Replica replica);
+}
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ClusterStateProvider.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ClusterStateProvider.java
index a7ce278..6746268 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ClusterStateProvider.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ClusterStateProvider.java
@@ -21,6 +21,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.solr.client.solrj.cloud.DirectReplicaState;
+import org.apache.solr.client.solrj.cloud.ReplicaStateProvider;
 import org.apache.solr.common.SolrCloseable;
 import org.apache.solr.common.cloud.ClusterState;
 import org.apache.solr.common.cloud.DocCollection;
@@ -107,5 +109,9 @@ public interface ClusterStateProvider extends SolrCloseable {
    */
   String getPolicyNameByCollection(String coll);
 
+  default ReplicaStateProvider getReplicaStateProvider(String coll) {
+    return new DirectReplicaState(s -> getLiveNodes().contains(s)) ;
+  }
+
   void connect();
 }
\ No newline at end of file
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ZkClientClusterStateProvider.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ZkClientClusterStateProvider.java
index cc4b045..82cd8ed 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ZkClientClusterStateProvider.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ZkClientClusterStateProvider.java
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.solr.client.solrj.cloud.ReplicaStateProvider;
 import org.apache.solr.common.AlreadyClosedException;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.ClusterState;
@@ -243,6 +244,11 @@ public class ZkClientClusterStateProvider implements ClusterStateProvider {
   }
 
   @Override
+  public ReplicaStateProvider getReplicaStateProvider(String coll) {
+    return zkStateReader.getReplicaStateProvider(coll);
+  }
+
+  @Override
   public String toString() {
     return zkHost;
   }
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/CollectionStatePredicate.java b/solr/solrj/src/java/org/apache/solr/common/cloud/CollectionStatePredicate.java
index a91a499..307efd3 100644
--- a/solr/solrj/src/java/org/apache/solr/common/cloud/CollectionStatePredicate.java
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/CollectionStatePredicate.java
@@ -21,6 +21,8 @@ import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
 
+import org.apache.solr.client.solrj.cloud.ReplicaStateProvider;
+
 /**
  * Interface to determine if a set of liveNodes and a collection's state matches some expecatations.
  *
@@ -41,6 +43,7 @@ public interface CollectionStatePredicate {
    *                        does not exist
    * @return true if the input matches the requirements of this predicate
    */
-  boolean matches(Set<String> liveNodes, DocCollection collectionState);
+  boolean matches(Set<String> liveNodes, DocCollection collectionState, ReplicaStateProvider rsp);
+
 
 }
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java
index a7d7e37..4cd3cfa 100644
--- a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java
@@ -45,6 +45,8 @@ import java.util.function.Predicate;
 import java.util.function.UnaryOperator;
 import java.util.stream.Collectors;
 
+import org.apache.solr.client.solrj.cloud.DirectReplicaState;
+import org.apache.solr.client.solrj.cloud.ReplicaStateProvider;
 import org.apache.solr.client.solrj.cloud.autoscaling.AutoScalingConfig;
 import org.apache.solr.common.AlreadyClosedException;
 import org.apache.solr.common.Callable;
@@ -217,6 +219,8 @@ public class ZkStateReader implements SolrCloseable {
 
   private Set<ClusterPropertiesListener> clusterPropertiesListeners = ConcurrentHashMap.newKeySet();
 
+  private final ReplicaStateProvider directReplicaState = new DirectReplicaState(s -> liveNodes.contains(s));
+
   /**
    * Used to submit notifications to Collection Properties watchers in order
    **/
@@ -963,7 +967,7 @@ public class ZkStateReader implements SolrCloseable {
 
     AtomicReference<Replica> leader = new AtomicReference<>();
     try {
-      waitForState(collection, timeout, TimeUnit.MILLISECONDS, (n, c) -> {
+      waitForState(collection, timeout, TimeUnit.MILLISECONDS, (n, c, rsp) -> {
         if (c == null)
           return false;
         Replica l = getLeader(n, c, shard);
@@ -1743,7 +1747,7 @@ public class ZkStateReader implements SolrCloseable {
     AtomicReference<DocCollection> docCollection = new AtomicReference<>();
     CollectionStateWatcher watcher = (n, c) -> {
       docCollection.set(c);
-      boolean matches = predicate.matches(n, c);
+      boolean matches = predicate.matches(n, c, getReplicaStateProvider(collection));
       if (matches)
         latch.countDown();
 
@@ -2330,4 +2334,7 @@ public class ZkStateReader implements SolrCloseable {
       return result;
     }
   }
+  public ReplicaStateProvider getReplicaStateProvider(String coll){
+    return directReplicaState;
+  }
 }
diff --git a/solr/solrj/src/test/org/apache/solr/common/cloud/TestCloudCollectionsListeners.java b/solr/solrj/src/test/org/apache/solr/common/cloud/TestCloudCollectionsListeners.java
index 1ef806e..b2ac8a3 100644
--- a/solr/solrj/src/test/org/apache/solr/common/cloud/TestCloudCollectionsListeners.java
+++ b/solr/solrj/src/test/org/apache/solr/common/cloud/TestCloudCollectionsListeners.java
@@ -99,7 +99,7 @@ public class TestCloudCollectionsListeners extends SolrCloudTestCase {
     CollectionAdminRequest.createCollection("testcollection1", "config", 4, 1)
         .processAndWait(client, MAX_WAIT_TIMEOUT);
     client.waitForState("testcollection1", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-        (n, c) -> DocCollection.isFullyActive(n, c, 4, 1));
+        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 4, 1));
 
     assertFalse("CloudCollectionsListener has new collection in old set of collections", oldResults.get(1).contains("testcollection1"));
     assertFalse("CloudCollectionsListener has new collection in old set of collections", oldResults.get(2).contains("testcollection1"));
diff --git a/solr/solrj/src/test/org/apache/solr/common/cloud/TestCollectionStateWatchers.java b/solr/solrj/src/test/org/apache/solr/common/cloud/TestCollectionStateWatchers.java
index ab3dc95..d0f837c 100644
--- a/solr/solrj/src/test/org/apache/solr/common/cloud/TestCollectionStateWatchers.java
+++ b/solr/solrj/src/test/org/apache/solr/common/cloud/TestCollectionStateWatchers.java
@@ -124,7 +124,7 @@ public class TestCollectionStateWatchers extends SolrCloudTestCase {
       .processAndWait(client, MAX_WAIT_TIMEOUT);
 
     client.waitForState("testcollection", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                        (n, c) -> DocCollection.isFullyActive(n, c, CLUSTER_SIZE, 1));
+                        (n, c, rsp) -> DocCollection.isFullyActive(n, c, CLUSTER_SIZE, 1));
 
     final JettySolrRunner extraJetty = cluster.startJettySolrRunner();
     final JettySolrRunner jettyToShutdown
@@ -202,13 +202,13 @@ public class TestCollectionStateWatchers extends SolrCloudTestCase {
       .processAndWait(client, MAX_WAIT_TIMEOUT);
 
     client.waitForState("waitforstate", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                        (n, c) -> DocCollection.isFullyActive(n, c, 1, 1));
+                        (n, c,rsp) -> DocCollection.isFullyActive(n, c, 1, 1));
 
     // several goes, to check that we're not getting delayed state changes
     for (int i = 0; i < 10; i++) {
       try {
         client.waitForState("waitforstate", 1, TimeUnit.SECONDS,
-                            (n, c) -> DocCollection.isFullyActive(n, c, 1, 1));
+                            (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 1));
       } catch (TimeoutException e) {
         fail("waitForState should return immediately if the predicate is already satisfied");
       }
@@ -220,7 +220,7 @@ public class TestCollectionStateWatchers extends SolrCloudTestCase {
   public void testCanWaitForNonexistantCollection() throws Exception {
 
     Future<Boolean> future = waitInBackground("delayed", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                                              (n, c) -> DocCollection.isFullyActive(n, c, 1, 1));
+                                              (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 1));
 
     CollectionAdminRequest.createCollection("delayed", "config", 1, 1)
       .processAndWait(cluster.getSolrClient(), MAX_WAIT_TIMEOUT);
@@ -234,7 +234,7 @@ public class TestCollectionStateWatchers extends SolrCloudTestCase {
     CloudSolrClient client = cluster.getSolrClient();
     expectThrows(TimeoutException.class, () -> {
       client.waitForState("nosuchcollection", 1, TimeUnit.SECONDS,
-                          ((liveNodes, collectionState) -> false));
+                          ((liveNodes, collectionState, rsp) -> false));
     });
     waitFor("Watchers for collection should be removed after timeout",
             MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
@@ -250,7 +250,7 @@ public class TestCollectionStateWatchers extends SolrCloudTestCase {
       .processAndWait(client, MAX_WAIT_TIMEOUT);
 
     client.waitForState("falsepredicate", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                        (n, c) -> DocCollection.isFullyActive(n, c, 4, 1));
+                        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 4, 1));
 
     final CountDownLatch firstCall = new CountDownLatch(1);
 
@@ -261,7 +261,7 @@ public class TestCollectionStateWatchers extends SolrCloudTestCase {
     cluster.waitForJettyToStop(node1);
 
     Future<Boolean> future = waitInBackground("falsepredicate", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                                              (liveNodes, collectionState) -> {
+                                              (liveNodes, collectionState, rsp) -> {
           firstCall.countDown();
           return DocCollection.isFullyActive(liveNodes, collectionState, 4, 1);
         });
@@ -289,7 +289,7 @@ public class TestCollectionStateWatchers extends SolrCloudTestCase {
 
     expectThrows(TimeoutException.class, () -> {
       client.waitForState("no-such-collection", 10, TimeUnit.MILLISECONDS,
-                          (n, c) -> DocCollection.isFullyActive(n, c, 1, 1));
+                          (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 1));
     });
 
     waitFor("Watchers for collection should be removed after timeout",
@@ -304,7 +304,7 @@ public class TestCollectionStateWatchers extends SolrCloudTestCase {
       .process(cluster.getSolrClient());
     
     Future<Boolean> future = waitInBackground("tobedeleted", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                                              (l, c) -> c == null);
+                                              (l, c, rsp) -> c == null);
 
     CollectionAdminRequest.deleteCollection("tobedeleted").process(cluster.getSolrClient());
 
@@ -318,7 +318,7 @@ public class TestCollectionStateWatchers extends SolrCloudTestCase {
     CollectionAdminRequest.createCollection("test_collection", "config", 1, 1).process(client);
 
     Future<Boolean> future = waitInBackground("test_collection", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                                              (l, c) -> (l.size() == 1 + CLUSTER_SIZE));
+                                              (l, c, rsp) -> (l.size() == 1 + CLUSTER_SIZE));
     
     JettySolrRunner unusedJetty = cluster.startJettySolrRunner();
     assertTrue("CollectionStateWatcher not notified of new node", future.get());
@@ -327,7 +327,7 @@ public class TestCollectionStateWatchers extends SolrCloudTestCase {
             () -> client.getZkStateReader().getStateWatchers("test_collection").size() == 0);
 
     future = waitInBackground("test_collection", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                              (l, c) -> (l.size() == CLUSTER_SIZE));
+                              (l, c, rsp) -> (l.size() == CLUSTER_SIZE));
 
     cluster.stopJettySolrRunner(unusedJetty);
     
@@ -344,7 +344,7 @@ public class TestCollectionStateWatchers extends SolrCloudTestCase {
     final CloudSolrClient client = cluster.getSolrClient();
 
     Future<Boolean> future = waitInBackground("stateformat1", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                                              (n, c) -> DocCollection.isFullyActive(n, c, 1, 1));
+                                              (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 1));
 
     CollectionAdminRequest.createCollection("stateformat1", "config", 1, 1).setStateFormat(1)
       .processAndWait(client, MAX_WAIT_TIMEOUT);
@@ -352,7 +352,7 @@ public class TestCollectionStateWatchers extends SolrCloudTestCase {
                future.get());
 
     Future<Boolean> migrated = waitInBackground("stateformat1", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                                                (n, c) -> c != null && c.getStateFormat() == 2);
+                                                (n, c, rsp) -> c != null && c.getStateFormat() == 2);
 
     CollectionAdminRequest.migrateCollectionFormat("stateformat1")
       .processAndWait(client, MAX_WAIT_TIMEOUT);
diff --git a/solr/solrj/src/test/org/apache/solr/common/cloud/TestDocCollectionWatcher.java b/solr/solrj/src/test/org/apache/solr/common/cloud/TestDocCollectionWatcher.java
index 22d687e..74000f1 100644
--- a/solr/solrj/src/test/org/apache/solr/common/cloud/TestDocCollectionWatcher.java
+++ b/solr/solrj/src/test/org/apache/solr/common/cloud/TestDocCollectionWatcher.java
@@ -18,7 +18,6 @@
 package org.apache.solr.common.cloud;
 
 import java.lang.invoke.MethodHandles;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
@@ -26,6 +25,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Predicate;
 
 import org.apache.solr.client.solrj.impl.CloudSolrClient;
@@ -143,13 +143,13 @@ public class TestDocCollectionWatcher extends SolrCloudTestCase {
       .processAndWait(client, MAX_WAIT_TIMEOUT);
 
     client.waitForState("waitforstate", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                        (n, c) -> DocCollection.isFullyActive(n, c, 1, 1));
+                        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 1));
 
     // several goes, to check that we're not getting delayed state changes
     for (int i = 0; i < 10; i++) {
       try {
         client.waitForState("waitforstate", 1, TimeUnit.SECONDS,
-                            (n, c) -> DocCollection.isFullyActive(n, c, 1, 1));
+                            (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 1));
       } catch (TimeoutException e) {
         fail("waitForState should return immediately if the predicate is already satisfied");
       }
@@ -175,7 +175,7 @@ public class TestDocCollectionWatcher extends SolrCloudTestCase {
     CloudSolrClient client = cluster.getSolrClient();
     expectThrows(TimeoutException.class, () -> {
       client.waitForState("nosuchcollection", 1, TimeUnit.SECONDS,
-                          ((liveNodes, collectionState) -> false));
+                          ((liveNodes, collectionState, rsp) -> false));
     });
     waitFor("Watchers for collection should be removed after timeout",
             MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
@@ -192,7 +192,7 @@ public class TestDocCollectionWatcher extends SolrCloudTestCase {
 
     // create collection with 1 shard 1 replica...
     client.waitForState("falsepredicate", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                        (n, c) -> DocCollection.isFullyActive(n, c, 1, 1));
+                        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 1));
 
     // set watcher waiting for at least 3 replicas (will fail initially)
     final AtomicInteger runCount = new AtomicInteger(0);
@@ -213,7 +213,7 @@ public class TestDocCollectionWatcher extends SolrCloudTestCase {
     CollectionAdminRequest.addReplicaToShard("falsepredicate", "shard1")
       .processAndWait(client, MAX_WAIT_TIMEOUT);
     client.waitForState("falsepredicate", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                        (n, c) -> DocCollection.isFullyActive(n, c, 1, 2));
+                        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 2));
 
     // confirm watcher has run at least once and has been retained...
     final int runCountSnapshot = runCount.get();
@@ -255,7 +255,7 @@ public class TestDocCollectionWatcher extends SolrCloudTestCase {
     CollectionAdminRequest.createCollection("tobedeleted", "config", 1, 1).process(client);
       
     client.waitForState("tobedeleted", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                        (n, c) -> DocCollection.isFullyActive(n, c, 1, 1));
+                        (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 1));
    
     Future<Boolean> future = waitInBackground("tobedeleted", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
                                               (c) -> c == null);
@@ -276,7 +276,7 @@ public class TestDocCollectionWatcher extends SolrCloudTestCase {
     CollectionAdminRequest.createCollection("stateformat1", "config", 1, 1).setStateFormat(1)
       .processAndWait(client, MAX_WAIT_TIMEOUT);
     client.waitForState("stateformat1", MAX_WAIT_TIMEOUT, TimeUnit.SECONDS,
-                         (n, c) -> DocCollection.isFullyActive(n, c, 1, 1));
+                         (n, c, rsp) -> DocCollection.isFullyActive(n, c, 1, 1));
     
     assertTrue("DocCollectionWatcher not notified of stateformat=1 collection creation",
                future.get());
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractDistribZkTestBase.java b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractDistribZkTestBase.java
index 194d387..6c34b11 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractDistribZkTestBase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractDistribZkTestBase.java
@@ -149,7 +149,7 @@ public abstract class AbstractDistribZkTestBase extends BaseDistributedSearchTes
       throws Exception {
     log.info("Wait for recoveries to finish - collection: " + collection + " failOnTimeout:" + failOnTimeout + " timeout (sec):" + timeoutSeconds);
     try {
-      zkStateReader.waitForState(collection, timeoutSeconds, TimeUnit.SECONDS, (liveNodes, docCollection) -> {
+      zkStateReader.waitForState(collection, timeoutSeconds, TimeUnit.SECONDS, (liveNodes, docCollection, rsp) -> {
         if (docCollection == null)
           return false;
         boolean sawLiveRecovering = false;
@@ -170,7 +170,7 @@ public abstract class AbstractDistribZkTestBase extends BaseDistributedSearchTes
                 + shard.getValue().getStr(ZkStateReader.STATE_PROP)
                 + " live:"
                 + liveNodes.contains(shard.getValue().getNodeName()));
-            final Replica.State state = shard.getValue().getState();
+            final Replica.State state = rsp.getState(shard.getValue());
             if ((state == Replica.State.RECOVERING || state == Replica.State.DOWN
                 || state == Replica.State.RECOVERY_FAILED)
                 && liveNodes.contains(shard.getValue().getStr(ZkStateReader.NODE_NAME_PROP))) {
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
index f2bd410..4423272 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
@@ -16,8 +16,6 @@
  */
 package org.apache.solr.cloud;
 
-import static org.apache.solr.common.util.Utils.makeMap;
-
 import java.io.File;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
@@ -108,6 +106,8 @@ import org.noggit.JSONWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.solr.common.util.Utils.makeMap;
+
 /**
  * TODO: we should still test this works as a custom update chain as well as
  * what we test now - the default update chain
@@ -596,14 +596,14 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
     log.info("Waiting to see {} active replicas in collection: {}", expectedNumReplicas, collection);
     AtomicInteger nReplicas = new AtomicInteger();
     try {
-      client.getZkStateReader().waitForState(collection, 30, TimeUnit.SECONDS, (liveNodes, collectionState) -> {
+      client.getZkStateReader().waitForState(collection, 30, TimeUnit.SECONDS, (liveNodes, collectionState, rsp) -> {
           if (collectionState == null) {
             return false;
           }
           int activeReplicas = 0;
           for (Slice slice : collectionState) {
             for (Replica replica : slice) {
-              if (replica.isActive(liveNodes)) {
+              if (rsp.isActive(replica)) {
                 activeReplicas++;
               }
             }
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java b/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
index fbb547c..9f80592 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
@@ -16,6 +16,7 @@
  */
 package org.apache.solr.cloud;
 
+import javax.servlet.Filter;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.nio.charset.Charset;
@@ -43,8 +44,7 @@ import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
-import javax.servlet.Filter;
-
+import com.codahale.metrics.MetricRegistry;
 import org.apache.lucene.util.LuceneTestCase;
 import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.embedded.JettyConfig;
@@ -77,8 +77,6 @@ import org.eclipse.jetty.servlet.ServletHolder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.codahale.metrics.MetricRegistry;
-
 /**
  * "Mini" SolrCloud cluster to be used for testing
  */
@@ -750,11 +748,11 @@ public class MiniSolrCloudCluster {
     AtomicReference<DocCollection> state = new AtomicReference<>();
     AtomicReference<Set<String>> liveNodesLastSeen = new AtomicReference<>();
     try {
-      getSolrClient().waitForState(collection, wait, unit, (n, c) -> {
+      getSolrClient().waitForState(collection, wait, unit, (n, c, rsp) -> {
         state.set(c);
         liveNodesLastSeen.set(n);
 
-        return predicate.matches(n, c);
+        return predicate.matches(n, c, rsp);
       });
     } catch (TimeoutException | InterruptedException e) {
       throw new RuntimeException("Failed while waiting for active collection" + "\n" + e.getMessage() + "\nLive Nodes: " + Arrays.toString(liveNodesLastSeen.get().toArray())
@@ -768,7 +766,7 @@ public class MiniSolrCloudCluster {
   }
   
   public static CollectionStatePredicate expectedShardsAndActiveReplicas(int expectedShards, int expectedReplicas) {
-    return (liveNodes, collectionState) -> {
+    return (liveNodes, collectionState, rsp) -> {
       if (collectionState == null)
         return false;
       if (collectionState.getSlices().size() != expectedShards) {
@@ -778,7 +776,7 @@ public class MiniSolrCloudCluster {
       int activeReplicas = 0;
       for (Slice slice : collectionState) {
         for (Replica replica : slice) {
-          if (replica.isActive(liveNodes)) {
+          if (rsp.isActive(replica)) {
             activeReplicas++;
           }
         }
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
index 4ce7a5e..3ddacd2 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
@@ -312,10 +312,10 @@ public class SolrCloudTestCase extends SolrTestCaseJ4 {
     AtomicReference<DocCollection> state = new AtomicReference<>();
     AtomicReference<Set<String>> liveNodesLastSeen = new AtomicReference<>();
     try {
-      cluster.getSolrClient().waitForState(collection, timeout, timeUnit, (n, c) -> {
+      cluster.getSolrClient().waitForState(collection, timeout, timeUnit, (n, c, rsp) -> {
         state.set(c);
         liveNodesLastSeen.set(n);
-        return predicate.matches(n, c);
+        return predicate.matches(n, c, rsp);
       });
     } catch (Exception e) {
       fail(message + "\n" + e.getMessage() + "\nLive Nodes: " + Arrays.toString(liveNodesLastSeen.get().toArray()) + "\nLast available state: " + state.get());
@@ -327,7 +327,7 @@ public class SolrCloudTestCase extends SolrTestCaseJ4 {
    * number of shards and active replicas
    */
   public static CollectionStatePredicate clusterShape(int expectedShards, int expectedReplicas) {
-    return (liveNodes, collectionState) -> {
+    return (liveNodes, collectionState, rsp) -> {
       if (collectionState == null)
         return false;
       if (collectionState.getSlices().size() != expectedShards)
@@ -341,7 +341,7 @@ public class SolrCloudTestCase extends SolrTestCaseJ4 {
    * number of active shards and active replicas
    */
   public static CollectionStatePredicate activeClusterShape(int expectedShards, int expectedReplicas) {
-    return (liveNodes, collectionState) -> {
+    return (liveNodes, collectionState, rsp) -> {
       if (collectionState == null)
         return false;
       log.info("active slice count: " + collectionState.getActiveSlices().size() + " expected:" + expectedShards);