You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ge...@apache.org on 2024/02/08 15:32:47 UTC

(solr) branch main updated: SOLR-17066: Switch HttpSolrClient away from coreURLs, pt 3 (#2240)

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

gerlowskija pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new aac01255dba SOLR-17066: Switch HttpSolrClient away from coreURLs, pt 3 (#2240)
aac01255dba is described below

commit aac01255dba559df6324ac9e294afe05169c0597
Author: Jason Gerlowski <ge...@apache.org>
AuthorDate: Thu Feb 8 10:32:41 2024 -0500

    SOLR-17066: Switch HttpSolrClient away from coreURLs, pt 3 (#2240)
    
    Providing a core URL as a SolrClient's "base URL" prevents it from
    communicating with other cores or making core-agnostic API requests
    (e.g. node healthcheck, list cores, etc.)
    
    This commit migrates all remaining HttpSolrClient usage away from
    core URLs, including those in the test framework and in solrj's tests.
---
 .../test/org/apache/solr/TestTolerantSearch.java   |   4 +-
 .../org/apache/solr/cli/TestSolrCLIRunExample.java |   2 +-
 .../apache/solr/cloud/AliasIntegrationTest.java    |   3 +-
 .../DistribDocExpirationUpdateProcessorTest.java   |   2 +-
 .../solr/cloud/DistributedVersionInfoTest.java     |   8 +-
 .../solr/cloud/FullSolrCloudDistribCmdsTest.java   |  17 ++-
 .../solr/cloud/HttpPartitionOnCommitTest.java      |   2 +-
 .../org/apache/solr/cloud/HttpPartitionTest.java   |   3 +-
 .../solr/cloud/LeaderVoteWaitTimeoutTest.java      |   3 +-
 .../org/apache/solr/cloud/MigrateRouteKeyTest.java |   2 +-
 .../solr/cloud/NestedShardedAtomicUpdateTest.java  |   2 +-
 .../apache/solr/cloud/ReplicationFactorTest.java   |   3 +-
 .../test/org/apache/solr/cloud/SplitShardTest.java |   3 +-
 .../apache/solr/cloud/TestCloudConsistency.java    |   3 +-
 .../apache/solr/cloud/TestCloudDeleteByQuery.java  |  11 +-
 .../TestCloudPhrasesIdentificationComponent.java   |   2 +-
 .../solr/cloud/TestCloudPseudoReturnFields.java    |   2 +-
 .../solr/cloud/TestMiniSolrCloudClusterSSL.java    |   2 +
 .../org/apache/solr/cloud/TestPullReplica.java     |  13 +-
 .../solr/cloud/TestPullReplicaErrorHandling.java   |  15 +--
 .../apache/solr/cloud/TestPullReplicaWithAuth.java |   4 +-
 .../cloud/TestStressCloudBlindAtomicUpdates.java   |   2 +-
 .../org/apache/solr/cloud/TestTlogReplica.java     |   8 +-
 .../cloud/TestTolerantUpdateProcessorCloud.java    |  11 +-
 .../TestTolerantUpdateProcessorRandomCloud.java    |   2 +-
 .../solr/cloud/api/collections/ShardSplitTest.java |  16 ++-
 .../solr/handler/TestReplicationHandler.java       |   4 +-
 .../solr/handler/TestStressIncrementalBackup.java  |   2 +-
 .../solr/handler/TestStressThreadBackup.java       |   2 +-
 .../component/DistributedDebugComponentTest.java   |   4 +-
 .../search/facet/TestCloudJSONFacetJoinDomain.java |   2 +-
 .../solr/search/facet/TestCloudJSONFacetSKG.java   |   2 +-
 .../search/facet/TestCloudJSONFacetSKGEquiv.java   |   2 +-
 .../solr/update/DeleteByIdWithRouterFieldTest.java |   4 +-
 .../solr/update/TestInPlaceUpdatesDistrib.java     |   4 +-
 .../solr/client/solrj/impl/LBHttpSolrClient.java   |  18 ++-
 .../solr/client/solrj/SolrExampleBinaryTest.java   |   3 +-
 .../solr/client/solrj/SolrExampleCborTest.java     |   3 +-
 .../solr/client/solrj/SolrExampleXMLTest.java      |  11 +-
 .../client/solrj/SolrSchemalessExampleTest.java    |   7 +-
 .../apache/solr/client/solrj/TestBatchUpdate.java  |  11 +-
 .../solr/client/solrj/TestLBHttp2SolrClient.java   |  11 +-
 .../solr/client/solrj/TestLBHttpSolrClient.java    |  13 +-
 .../solr/client/solrj/TestSolrJErrorHandling.java  |   9 +-
 .../client/solrj/impl/BasicHttpSolrClientTest.java | 141 ++++++++++++++-------
 .../solrj/impl/CloudHttp2SolrClientTest.java       |  23 ++--
 .../client/solrj/impl/CloudSolrClientTest.java     |  22 ++--
 .../solrj/impl/HttpSolrClientBadInputTest.java     |   2 +-
 .../solrj/impl/HttpSolrClientConPoolTest.java      |  18 ++-
 .../solrj/response/NoOpResponseParserTest.java     |   3 +-
 .../java/org/apache/solr/SolrJettyTestBase.java    |   4 +-
 .../src/java/org/apache/solr/SolrTestCaseHS.java   |   6 +-
 .../src/java/org/apache/solr/SolrTestCaseJ4.java   |  12 ++
 .../cloud/AbstractBasicDistributedZk2TestBase.java |   4 +-
 .../cloud/AbstractBasicDistributedZkTestBase.java  |  54 +++-----
 .../solr/cloud/AbstractFullDistribZkTestBase.java  |  32 +++--
 .../solr/cloud/AbstractRecoveryZkTestBase.java     |   3 +-
 .../solr/cloud/AbstractSyncSliceTestBase.java      |   7 +-
 .../cloud/AbstractUnloadDistributedZkTestBase.java |  15 ++-
 .../AbstractCloudBackupRestoreTestCase.java        |   3 +-
 .../org/apache/solr/util/SolrJettyTestRule.java    |   6 +-
 61 files changed, 363 insertions(+), 249 deletions(-)

diff --git a/solr/core/src/test/org/apache/solr/TestTolerantSearch.java b/solr/core/src/test/org/apache/solr/TestTolerantSearch.java
index fe4887aebea..4995ed378c2 100644
--- a/solr/core/src/test/org/apache/solr/TestTolerantSearch.java
+++ b/solr/core/src/test/org/apache/solr/TestTolerantSearch.java
@@ -63,8 +63,8 @@ public class TestTolerantSearch extends SolrJettyTestBase {
     File solrHome = createSolrHome();
     createAndStartJetty(solrHome.getAbsolutePath());
     String url = getBaseUrl();
-    collection1 = getHttpSolrClient(url + "/collection1");
-    collection2 = getHttpSolrClient(url + "/collection2");
+    collection1 = getHttpSolrClient(url, "collection1");
+    collection2 = getHttpSolrClient(url, "collection2");
 
     String urlCollection1 = getBaseUrl() + "/" + "collection1";
     String urlCollection2 = getBaseUrl() + "/" + "collection2";
diff --git a/solr/core/src/test/org/apache/solr/cli/TestSolrCLIRunExample.java b/solr/core/src/test/org/apache/solr/cli/TestSolrCLIRunExample.java
index 47577082428..5bdcb516935 100644
--- a/solr/core/src/test/org/apache/solr/cli/TestSolrCLIRunExample.java
+++ b/solr/core/src/test/org/apache/solr/cli/TestSolrCLIRunExample.java
@@ -408,7 +408,7 @@ public class TestSolrCLIRunExample extends SolrTestCaseJ4 {
 
       if ("techproducts".equals(exampleName)) {
         SolrClient solrClient =
-            getHttpSolrClient("http://localhost:" + bindPort + "/solr/" + exampleName);
+            getHttpSolrClient("http://localhost:" + bindPort + "/solr", exampleName);
         try {
           SolrQuery query = new SolrQuery("*:*");
           QueryResponse qr = solrClient.query(query);
diff --git a/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java b/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java
index 804cf724495..c3a9e77f55d 100644
--- a/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java
@@ -968,8 +968,7 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
       // HttpSolrClient
       JettySolrRunner jetty = cluster.getRandomJetty(random());
       if (random().nextBoolean()) {
-        try (SolrClient client =
-            getHttpSolrClient(jetty.getBaseUrl().toString() + "/" + collectionList)) {
+        try (SolrClient client = getHttpSolrClient(jetty.getBaseUrl().toString(), collectionList)) {
           responseConsumer.accept(client.query(null, solrQuery));
         }
       } else {
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 6f7d9ea959a..4780839e06f 100644
--- a/solr/core/src/test/org/apache/solr/cloud/DistribDocExpirationUpdateProcessorTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/DistribDocExpirationUpdateProcessorTest.java
@@ -315,7 +315,7 @@ public class DistribDocExpirationUpdateProcessorTest extends SolrCloudTestCase {
     for (Replica replica : collectionState.getReplicas()) {
 
       String coreName = replica.getCoreName();
-      try (SolrClient client = getHttpSolrClient(replica.getCoreUrl())) {
+      try (SolrClient client = getHttpSolrClient(replica)) {
 
         ModifiableSolrParams params = new ModifiableSolrParams();
         params.set("command", "indexversion");
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 c04c7939e64..38f7abeca0e 100644
--- a/solr/core/src/test/org/apache/solr/cloud/DistributedVersionInfoTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/DistributedVersionInfoTest.java
@@ -110,7 +110,7 @@ public class DistributedVersionInfoTest extends SolrCloudTestCase {
         maxOnReplica);
 
     // send the same doc but with a lower version than the max in the index
-    try (SolrClient client = getHttpSolrClient(replica.getCoreUrl())) {
+    try (SolrClient client = getHttpSolrClient(replica)) {
       String docId = String.valueOf(1);
       SolrInputDocument doc = new SolrInputDocument();
       doc.setField("id", docId);
@@ -301,7 +301,7 @@ public class DistributedVersionInfoTest extends SolrCloudTestCase {
     query.addSort(new SolrQuery.SortClause("_version_", SolrQuery.ORDER.desc));
     query.setParam("distrib", false);
 
-    try (SolrClient client = getHttpSolrClient(replica.getCoreUrl())) {
+    try (SolrClient client = getHttpSolrClient(replica)) {
       QueryResponse qr = client.query(query);
       SolrDocumentList hits = qr.getResults();
       if (hits.isEmpty()) fail("No results returned from query: " + query);
@@ -323,9 +323,9 @@ public class DistributedVersionInfoTest extends SolrCloudTestCase {
       int lastDocId,
       Set<Integer> deletedDocs)
       throws Exception {
-    SolrClient leaderSolr = getHttpSolrClient(leader.getCoreUrl());
+    SolrClient leaderSolr = getHttpSolrClient(leader);
     List<SolrClient> replicas = new ArrayList<SolrClient>(notLeaders.size());
-    for (Replica r : notLeaders) replicas.add(getHttpSolrClient(r.getCoreUrl()));
+    for (Replica r : notLeaders) replicas.add(getHttpSolrClient(r));
 
     try {
       for (int d = firstDocId; d <= lastDocId; d++) {
diff --git a/solr/core/src/test/org/apache/solr/cloud/FullSolrCloudDistribCmdsTest.java b/solr/core/src/test/org/apache/solr/cloud/FullSolrCloudDistribCmdsTest.java
index 0d5e05ded27..5f0a86b0822 100644
--- a/solr/core/src/test/org/apache/solr/cloud/FullSolrCloudDistribCmdsTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/FullSolrCloudDistribCmdsTest.java
@@ -170,8 +170,8 @@ public class FullSolrCloudDistribCmdsTest extends SolrCloudTestCase {
             (n, c1) -> DocCollection.isFullyActive(n, c1, 2, 2));
 
     final DocCollection docCol = cloudClient.getClusterState().getCollection(testCollectionName);
-    try (SolrClient shard1 = getHttpSolrClient(docCol.getSlice("shard1").getLeader().getCoreUrl());
-        SolrClient shard2 = getHttpSolrClient(docCol.getSlice("shard2").getLeader().getCoreUrl())) {
+    try (SolrClient shard1 = getHttpSolrClient(docCol.getSlice("shard1").getLeader());
+        SolrClient shard2 = getHttpSolrClient(docCol.getSlice("shard2").getLeader())) {
 
       // Add three documents to shard1
       shard1.add(sdoc("id", "1", "title", "s1 one"));
@@ -325,8 +325,8 @@ public class FullSolrCloudDistribCmdsTest extends SolrCloudTestCase {
             (n, c1) -> DocCollection.isFullyActive(n, c1, 2, 2));
 
     final DocCollection docCol = cloudClient.getClusterState().getCollection(testCollectionName);
-    try (SolrClient shard1 = getHttpSolrClient(docCol.getSlice("shard1").getLeader().getCoreUrl());
-        SolrClient shard2 = getHttpSolrClient(docCol.getSlice("shard2").getLeader().getCoreUrl())) {
+    try (SolrClient shard1 = getHttpSolrClient(docCol.getSlice("shard1").getLeader());
+        SolrClient shard2 = getHttpSolrClient(docCol.getSlice("shard2").getLeader())) {
 
       // Add six documents w/diff routes (all sent to shard1 leader's core)
       shard1.add(sdoc("id", "1", "routefield_s", "europe"));
@@ -432,8 +432,7 @@ public class FullSolrCloudDistribCmdsTest extends SolrCloudTestCase {
     // pick a (second) random node (which may be the same) for sending updates to
     // (if it's the same, we're testing routing from another shard, if diff we're testing routing
     // from a non-collection node)
-    final String indexingUrl =
-        cluster.getRandomJetty(random()).getProxyBaseUrl() + "/" + collectionName;
+    final String indexingBaseUrl = cluster.getRandomJetty(random()).getProxyBaseUrl().toString();
 
     // create a new node for the purpose of killing it...
     final JettySolrRunner leaderToPartition = cluster.startJettySolrRunner();
@@ -484,7 +483,7 @@ public class FullSolrCloudDistribCmdsTest extends SolrCloudTestCase {
         }
 
         // create client to send our updates to...
-        try (SolrClient indexClient = getHttpSolrClient(indexingUrl)) {
+        try (SolrClient indexClient = getHttpSolrClient(indexingBaseUrl, collectionName)) {
 
           // Sanity check: we should be able to send a bunch of updates that work right now...
           for (int i = 0; i < 100; i++) {
@@ -857,11 +856,11 @@ public class FullSolrCloudDistribCmdsTest extends SolrCloudTestCase {
       final Slice slice = entry.getValue();
       log.info("Checking: {} -> {}", shardName, slice);
       final Replica leader = entry.getValue().getLeader();
-      try (SolrClient leaderClient = getHttpSolrClient(leader.getCoreUrl())) {
+      try (SolrClient leaderClient = getHttpSolrClient(leader)) {
         final SolrDocumentList leaderResults = leaderClient.query(perReplicaParams).getResults();
         log.debug("Shard {}: Leader results: {}", shardName, leaderResults);
         for (Replica replica : slice) {
-          try (SolrClient replicaClient = getHttpSolrClient(replica.getCoreUrl())) {
+          try (SolrClient replicaClient = getHttpSolrClient(replica)) {
             final SolrDocumentList replicaResults =
                 replicaClient.query(perReplicaParams).getResults();
             if (log.isDebugEnabled()) {
diff --git a/solr/core/src/test/org/apache/solr/cloud/HttpPartitionOnCommitTest.java b/solr/core/src/test/org/apache/solr/cloud/HttpPartitionOnCommitTest.java
index a4c39ea7c7d..bcd91e1862a 100644
--- a/solr/core/src/test/org/apache/solr/cloud/HttpPartitionOnCommitTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/HttpPartitionOnCommitTest.java
@@ -190,7 +190,7 @@ public class HttpPartitionOnCommitTest extends BasicDistributedZkTest {
     String replicaCoreUrl = replica.getCoreUrl();
     log.info("Sending commit request to: {}", replicaCoreUrl);
     final RTimer timer = new RTimer();
-    try (SolrClient client = getHttpSolrClient(replicaCoreUrl)) {
+    try (SolrClient client = getHttpSolrClient(replica)) {
       try {
         client.commit();
 
diff --git a/solr/core/src/test/org/apache/solr/cloud/HttpPartitionTest.java b/solr/core/src/test/org/apache/solr/cloud/HttpPartitionTest.java
index f6e74fa2c52..2f3f62ad763 100644
--- a/solr/core/src/test/org/apache/solr/cloud/HttpPartitionTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/HttpPartitionTest.java
@@ -523,8 +523,7 @@ public class HttpPartitionTest extends AbstractFullDistribZkTestBase {
 
   protected SolrClient getHttpSolrClient(Replica replica, String collection) {
     ZkCoreNodeProps zkProps = new ZkCoreNodeProps(replica);
-    String url = zkProps.getBaseUrl() + "/" + collection;
-    return getHttpSolrClient(url);
+    return getHttpSolrClient(zkProps.getBaseUrl(), collection);
   }
 
   // Send doc directly to a server (without going through proxy)
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 146a05388e8..a54481b1f5e 100644
--- a/solr/core/src/test/org/apache/solr/cloud/LeaderVoteWaitTimeoutTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/LeaderVoteWaitTimeoutTest.java
@@ -342,7 +342,6 @@ public class LeaderVoteWaitTimeoutTest extends SolrCloudTestCase {
 
   protected SolrClient getSolrClient(Replica replica, String coll) {
     ZkCoreNodeProps zkProps = new ZkCoreNodeProps(replica);
-    String url = zkProps.getBaseUrl() + "/" + coll;
-    return getHttpSolrClient(url);
+    return getHttpSolrClient(zkProps.getBaseUrl(), coll);
   }
 }
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 7c733f3df47..dc0750fb7f0 100644
--- a/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java
@@ -134,7 +134,7 @@ public class MigrateRouteKeyTest extends SolrCloudTestCase {
 
     DocCollection state = getCollectionState(targetCollection);
     Replica replica = state.getReplicas().get(0);
-    try (SolrClient collectionClient = getHttpSolrClient(replica.getCoreUrl())) {
+    try (SolrClient collectionClient = getHttpSolrClient(replica)) {
 
       SolrQuery solrQuery = new SolrQuery("*:*");
       assertEquals(
diff --git a/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java b/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java
index c19ff114441..fb94304f897 100644
--- a/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java
@@ -65,7 +65,7 @@ public class NestedShardedAtomicUpdateTest extends SolrCloudTestCase {
     clients = new ArrayList<>();
     ClusterState clusterState = cloudClient.getClusterState();
     for (Replica replica : clusterState.getCollection(DEFAULT_COLLECTION).getReplicas()) {
-      clients.add(getHttpSolrClient(replica.getCoreUrl()));
+      clients.add(getHttpSolrClient(replica));
     }
   }
 
diff --git a/solr/core/src/test/org/apache/solr/cloud/ReplicationFactorTest.java b/solr/core/src/test/org/apache/solr/cloud/ReplicationFactorTest.java
index 5ebc71efa40..e62b3005c8b 100644
--- a/solr/core/src/test/org/apache/solr/cloud/ReplicationFactorTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/ReplicationFactorTest.java
@@ -268,8 +268,7 @@ public class ReplicationFactorTest extends AbstractFullDistribZkTestBase {
   protected void sendNonDirectUpdateRequestReplica(
       Replica replica, UpdateRequest up, int expectedRf, String collection) throws Exception {
     ZkCoreNodeProps zkProps = new ZkCoreNodeProps(replica);
-    String url = zkProps.getBaseUrl() + "/" + collection;
-    try (SolrClient solrServer = getHttpSolrClient(url)) {
+    try (SolrClient solrServer = getHttpSolrClient(zkProps.getBaseUrl(), collection)) {
       NamedList<?> resp = solrServer.request(up);
       NamedList<?> hdr = (NamedList<?>) resp.get("responseHeader");
       Integer batchRf = (Integer) hdr.get(UpdateRequest.REPFACT);
diff --git a/solr/core/src/test/org/apache/solr/cloud/SplitShardTest.java b/solr/core/src/test/org/apache/solr/cloud/SplitShardTest.java
index 31788138430..efd858ea4cb 100644
--- a/solr/core/src/test/org/apache/solr/cloud/SplitShardTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/SplitShardTest.java
@@ -195,8 +195,7 @@ public class SplitShardTest extends SolrCloudTestCase {
       if (!slice.getState().equals(Slice.State.ACTIVE)) continue;
       long lastReplicaCount = -1;
       for (Replica replica : slice.getReplicas()) {
-        SolrClient replicaClient =
-            getHttpSolrClient(replica.getBaseUrl() + "/" + replica.getCoreName());
+        SolrClient replicaClient = getHttpSolrClient(replica);
         long numFound;
         try {
           numFound =
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 aa3feb2a5f6..a1f1470d668 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestCloudConsistency.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudConsistency.java
@@ -350,7 +350,6 @@ public class TestCloudConsistency extends SolrCloudTestCase {
 
   protected SolrClient getHttpSolrClient(Replica replica, String coll) {
     ZkCoreNodeProps zkProps = new ZkCoreNodeProps(replica);
-    String url = zkProps.getBaseUrl() + "/" + coll;
-    return getHttpSolrClient(url);
+    return getHttpSolrClient(zkProps.getBaseUrl(), coll);
   }
 }
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudDeleteByQuery.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudDeleteByQuery.java
index d52525f5111..f2a6d7c1d76 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestCloudDeleteByQuery.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudDeleteByQuery.java
@@ -157,18 +157,17 @@ public class TestCloudDeleteByQuery extends SolrCloudTestCase {
       assertNotNull("could not find URL for " + shardName + " replica", passiveUrl);
 
       if (shardName.equals("shard1")) {
-        S_ONE_LEADER_CLIENT = getHttpSolrClient(leaderUrl + "/" + COLLECTION_NAME + "/");
-        S_ONE_NON_LEADER_CLIENT = getHttpSolrClient(passiveUrl + "/" + COLLECTION_NAME + "/");
+        S_ONE_LEADER_CLIENT = getHttpSolrClient(leaderUrl, COLLECTION_NAME);
+        S_ONE_NON_LEADER_CLIENT = getHttpSolrClient(passiveUrl, COLLECTION_NAME);
       } else if (shardName.equals("shard2")) {
-        S_TWO_LEADER_CLIENT = getHttpSolrClient(leaderUrl + "/" + COLLECTION_NAME + "/");
-        S_TWO_NON_LEADER_CLIENT = getHttpSolrClient(passiveUrl + "/" + COLLECTION_NAME + "/");
+        S_TWO_LEADER_CLIENT = getHttpSolrClient(leaderUrl, COLLECTION_NAME);
+        S_TWO_NON_LEADER_CLIENT = getHttpSolrClient(passiveUrl, COLLECTION_NAME);
       } else {
         fail("unexpected shard: " + shardName);
       }
     }
     assertEquals("Should be exactly one server left (not hosting either shard)", 1, urlMap.size());
-    NO_COLLECTION_CLIENT =
-        getHttpSolrClient(urlMap.values().iterator().next() + "/" + COLLECTION_NAME + "/");
+    NO_COLLECTION_CLIENT = getHttpSolrClient(urlMap.values().iterator().next(), COLLECTION_NAME);
 
     assertNotNull(S_ONE_LEADER_CLIENT);
     assertNotNull(S_TWO_LEADER_CLIENT);
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudPhrasesIdentificationComponent.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudPhrasesIdentificationComponent.java
index cf1972cfb02..c0d79824b8b 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestCloudPhrasesIdentificationComponent.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudPhrasesIdentificationComponent.java
@@ -80,7 +80,7 @@ public class TestCloudPhrasesIdentificationComponent extends SolrCloudTestCase {
     waitForRecoveriesToFinish(COLLECTION_CLIENT);
 
     for (JettySolrRunner jetty : cluster.getJettySolrRunners()) {
-      CLIENTS.add(getHttpSolrClient(jetty.getBaseUrl() + "/" + COLLECTION_NAME + "/"));
+      CLIENTS.add(getHttpSolrClient(jetty.getBaseUrl().toString(), COLLECTION_NAME));
     }
 
     // index some docs...
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudPseudoReturnFields.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudPseudoReturnFields.java
index 59a3a0feacc..2831202dcfb 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestCloudPseudoReturnFields.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudPseudoReturnFields.java
@@ -98,7 +98,7 @@ public class TestCloudPseudoReturnFields extends SolrCloudTestCase {
     waitForRecoveriesToFinish(COLLECTION_CLIENT);
 
     for (JettySolrRunner jetty : cluster.getJettySolrRunners()) {
-      CLIENTS.add(getHttpSolrClient(jetty.getBaseUrl() + "/" + COLLECTION_NAME + "/"));
+      CLIENTS.add(getHttpSolrClient(jetty.getBaseUrl().toString(), COLLECTION_NAME));
     }
 
     assertEquals(
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java b/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java
index ca516cdfb05..18ec44e430c 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java
@@ -418,6 +418,8 @@ public class TestMiniSolrCloudClusterSSL extends SolrTestCaseJ4 {
   /**
    * Generates an HttpSolrClient, either by using the test framework helper method or by direct
    * instantiation (determined randomly)
+   *
+   * @param url the base URL of a Solr node. Should not contain a collection or core name
    */
   public static SolrClient getRandomizedHttpSolrClient(String url) {
     // NOTE: at the moment, SolrTestCaseJ4 already returns "new HttpSolrClient" most of the time,
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 fd6d6eb7742..7b0ae43ab3b 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java
@@ -269,7 +269,7 @@ public class TestPullReplica extends SolrCloudTestCase {
       log.info("Committed doc {} to leader", numDocs);
 
       Slice s = docCollection.getSlices().iterator().next();
-      try (SolrClient leaderClient = getHttpSolrClient(s.getLeader().getCoreUrl())) {
+      try (SolrClient leaderClient = getHttpSolrClient(s.getLeader())) {
         assertEquals(numDocs, leaderClient.query(new SolrQuery("*:*")).getResults().getNumFound());
       }
       log.info(
@@ -284,7 +284,7 @@ public class TestPullReplica extends SolrCloudTestCase {
       waitForNumDocsInAllReplicas(numDocs, pullReplicas);
 
       for (Replica r : pullReplicas) {
-        try (SolrClient pullReplicaClient = getHttpSolrClient(r.getCoreUrl())) {
+        try (SolrClient pullReplicaClient = getHttpSolrClient(r)) {
           SolrQuery req = new SolrQuery("qt", "/admin/plugins", "stats", "true");
           QueryResponse statsResponse = pullReplicaClient.query(req);
           // The adds gauge metric should be null for pull replicas since they don't process adds
@@ -523,7 +523,7 @@ public class TestPullReplica extends SolrCloudTestCase {
     cluster.getSolrClient().add(collectionName, new SolrInputDocument("id", "1", "foo", "bar"));
     cluster.getSolrClient().commit(collectionName);
     Slice s = docCollection.getSlices().iterator().next();
-    try (SolrClient leaderClient = getHttpSolrClient(s.getLeader().getCoreUrl())) {
+    try (SolrClient leaderClient = getHttpSolrClient(s.getLeader())) {
       assertEquals(1, leaderClient.query(new SolrQuery("*:*")).getResults().getNumFound());
     }
 
@@ -578,8 +578,7 @@ public class TestPullReplica extends SolrCloudTestCase {
 
     // Also fails if I send the update to the pull replica explicitly
     try (SolrClient pullReplicaClient =
-        getHttpSolrClient(
-            docCollection.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0).getCoreUrl())) {
+        getHttpSolrClient(docCollection.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0))) {
       expectThrows(
           SolrException.class,
           () ->
@@ -626,7 +625,7 @@ public class TestPullReplica extends SolrCloudTestCase {
     // add docs agin
     cluster.getSolrClient().add(collectionName, new SolrInputDocument("id", "2", "foo", "zoo"));
     s = docCollection.getSlices().iterator().next();
-    try (SolrClient leaderClient = getHttpSolrClient(s.getLeader().getCoreUrl())) {
+    try (SolrClient leaderClient = getHttpSolrClient(s.getLeader())) {
       leaderClient.commit();
       assertEquals(1, leaderClient.query(new SolrQuery("*:*")).getResults().getNumFound());
     }
@@ -693,7 +692,7 @@ public class TestPullReplica extends SolrCloudTestCase {
     TimeOut t = new TimeOut(REPLICATION_TIMEOUT_SECS, TimeUnit.SECONDS, TimeSource.NANO_TIME);
     for (Replica r : replicas) {
       String replicaUrl = r.getCoreUrl();
-      try (SolrClient replicaClient = getHttpSolrClient(replicaUrl)) {
+      try (SolrClient replicaClient = getHttpSolrClient(r)) {
         while (true) {
           QueryRequest req = new QueryRequest(new SolrQuery(query));
           if (user != null && pass != null) {
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 90baeb15644..dd0363c16ac 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestPullReplicaErrorHandling.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestPullReplicaErrorHandling.java
@@ -138,7 +138,7 @@ public class TestPullReplicaErrorHandling extends SolrCloudTestCase {
       proxy.close();
       for (int i = 1; i <= 10; i++) {
         addDocs(10 + i);
-        try (SolrClient leaderClient = getHttpSolrClient(s.getLeader().getCoreUrl())) {
+        try (SolrClient leaderClient = getHttpSolrClient(s.getLeader())) {
           assertNumDocs(10 + i, leaderClient);
         }
       }
@@ -148,8 +148,7 @@ public class TestPullReplicaErrorHandling extends SolrCloudTestCase {
               SolrServerException.class,
               () -> {
                 try (SolrClient pullReplicaClient =
-                    getHttpSolrClient(
-                        s.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0).getCoreUrl())) {
+                    getHttpSolrClient(s.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0))) {
                   pullReplicaClient.query(new SolrQuery("*:*")).getResults().getNumFound();
                 }
               });
@@ -174,7 +173,7 @@ public class TestPullReplicaErrorHandling extends SolrCloudTestCase {
     }
 
     try (SolrClient pullReplicaClient =
-        getHttpSolrClient(s.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0).getCoreUrl())) {
+        getHttpSolrClient(s.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0))) {
       assertNumDocs(20, pullReplicaClient);
     }
   }
@@ -191,13 +190,13 @@ public class TestPullReplicaErrorHandling extends SolrCloudTestCase {
     try {
       // wait for replication
       try (SolrClient pullReplicaClient =
-          getHttpSolrClient(s.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0).getCoreUrl())) {
+          getHttpSolrClient(s.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0))) {
         assertNumDocs(10, pullReplicaClient);
       }
       proxy.close();
       expectThrows(SolrException.class, () -> addDocs(1));
       try (SolrClient pullReplicaClient =
-          getHttpSolrClient(s.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0).getCoreUrl())) {
+          getHttpSolrClient(s.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0))) {
         assertNumDocs(10, pullReplicaClient);
       }
       assertNumDocs(10, cluster.getSolrClient(collectionName));
@@ -227,7 +226,7 @@ public class TestPullReplicaErrorHandling extends SolrCloudTestCase {
     DocCollection docCollection = assertNumberOfReplicas(numShards, 0, numShards, false, true);
     Slice s = docCollection.getSlices().iterator().next();
     try (SolrClient pullReplicaClient =
-        getHttpSolrClient(s.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0).getCoreUrl())) {
+        getHttpSolrClient(s.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0))) {
       assertNumDocs(10, pullReplicaClient);
     }
     addDocs(20);
@@ -238,7 +237,7 @@ public class TestPullReplicaErrorHandling extends SolrCloudTestCase {
     addDocs(40);
     waitForState("Expecting node to be reconnected", collectionName, activeReplicaCount(1, 0, 1));
     try (SolrClient pullReplicaClient =
-        getHttpSolrClient(s.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0).getCoreUrl())) {
+        getHttpSolrClient(s.getReplicas(EnumSet.of(Replica.Type.PULL)).get(0))) {
       assertNumDocs(40, pullReplicaClient);
     }
   }
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestPullReplicaWithAuth.java b/solr/core/src/test/org/apache/solr/cloud/TestPullReplicaWithAuth.java
index a4d070b0c16..63ae8044618 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestPullReplicaWithAuth.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestPullReplicaWithAuth.java
@@ -117,7 +117,7 @@ public class TestPullReplicaWithAuth extends SolrCloudTestCase {
       ureq.commit(solrClient, collectionName);
 
       Slice s = docCollection.getSlices().iterator().next();
-      try (SolrClient leaderClient = getHttpSolrClient(s.getLeader().getCoreUrl())) {
+      try (SolrClient leaderClient = getHttpSolrClient(s.getLeader())) {
         assertEquals(
             numDocs,
             queryWithBasicAuth(leaderClient, new SolrQuery("*:*")).getResults().getNumFound());
@@ -127,7 +127,7 @@ public class TestPullReplicaWithAuth extends SolrCloudTestCase {
       waitForNumDocsInAllReplicas(numDocs, pullReplicas, "*:*", USER, PASS);
 
       for (Replica r : pullReplicas) {
-        try (SolrClient pullReplicaClient = getHttpSolrClient(r.getCoreUrl())) {
+        try (SolrClient pullReplicaClient = getHttpSolrClient(r)) {
           QueryResponse statsResponse =
               queryWithBasicAuth(
                   pullReplicaClient, new SolrQuery("qt", "/admin/plugins", "stats", "true"));
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestStressCloudBlindAtomicUpdates.java b/solr/core/src/test/org/apache/solr/cloud/TestStressCloudBlindAtomicUpdates.java
index 4848f92f295..72593d91e2f 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestStressCloudBlindAtomicUpdates.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestStressCloudBlindAtomicUpdates.java
@@ -142,7 +142,7 @@ public class TestStressCloudBlindAtomicUpdates extends SolrCloudTestCase {
       assertNotNull("Cluster contains null jetty?", jetty);
       final URL baseUrl = jetty.getBaseUrl();
       assertNotNull("Jetty has null baseUrl: " + jetty, baseUrl);
-      CLIENTS.add(getHttpSolrClient(baseUrl + "/" + COLLECTION_NAME + "/"));
+      CLIENTS.add(getHttpSolrClient(baseUrl.toString(), COLLECTION_NAME));
     }
 
     // sanity check no one broke the assumptions we make about our schema
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 c3baa8e5486..c13795dcfca 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java
@@ -262,14 +262,14 @@ public class TestTlogReplica extends SolrCloudTestCase {
     cluster.getSolrClient().commit(collectionName);
 
     Slice s = docCollection.getSlices().iterator().next();
-    try (SolrClient leaderClient = getHttpSolrClient(s.getLeader().getCoreUrl())) {
+    try (SolrClient leaderClient = getHttpSolrClient(s.getLeader())) {
       assertEquals(1, leaderClient.query(new SolrQuery("*:*")).getResults().getNumFound());
     }
 
     TimeOut t = new TimeOut(REPLICATION_TIMEOUT_SECS, TimeUnit.SECONDS, TimeSource.NANO_TIME);
     for (Replica r : s.getReplicas(EnumSet.of(Replica.Type.TLOG))) {
       // TODO: assert replication < REPLICATION_TIMEOUT_SECS
-      try (SolrClient tlogReplicaClient = getHttpSolrClient(r.getCoreUrl())) {
+      try (SolrClient tlogReplicaClient = getHttpSolrClient(r)) {
         while (true) {
           try {
             assertEquals(
@@ -459,7 +459,7 @@ public class TestTlogReplica extends SolrCloudTestCase {
     cluster.getSolrClient().add(collectionName, new SolrInputDocument("id", "1", "foo", "bar"));
     cluster.getSolrClient().commit(collectionName);
     Slice s = docCollection.getSlices().iterator().next();
-    try (SolrClient leaderClient = getHttpSolrClient(s.getLeader().getCoreUrl())) {
+    try (SolrClient leaderClient = getHttpSolrClient(s.getLeader())) {
       assertEquals(1, leaderClient.query(new SolrQuery("*:*")).getResults().getNumFound());
     }
 
@@ -1005,7 +1005,7 @@ public class TestTlogReplica extends SolrCloudTestCase {
       if (!r.isActive(cluster.getSolrClient().getClusterState().getLiveNodes())) {
         continue;
       }
-      try (SolrClient replicaClient = getHttpSolrClient(r.getCoreUrl())) {
+      try (SolrClient replicaClient = getHttpSolrClient(r)) {
         while (true) {
           try {
             assertEquals(
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestTolerantUpdateProcessorCloud.java b/solr/core/src/test/org/apache/solr/cloud/TestTolerantUpdateProcessorCloud.java
index 9e710d94f57..a7d59979928 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestTolerantUpdateProcessorCloud.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestTolerantUpdateProcessorCloud.java
@@ -146,18 +146,17 @@ public class TestTolerantUpdateProcessorCloud extends SolrCloudTestCase {
       assertNotNull("could not find URL for " + shardName + " replica", passiveUrl);
 
       if (shardName.equals("shard1")) {
-        S_ONE_LEADER_CLIENT = getHttpSolrClient(leaderUrl + "/" + COLLECTION_NAME + "/");
-        S_ONE_NON_LEADER_CLIENT = getHttpSolrClient(passiveUrl + "/" + COLLECTION_NAME + "/");
+        S_ONE_LEADER_CLIENT = getHttpSolrClient(leaderUrl, COLLECTION_NAME);
+        S_ONE_NON_LEADER_CLIENT = getHttpSolrClient(passiveUrl, COLLECTION_NAME);
       } else if (shardName.equals("shard2")) {
-        S_TWO_LEADER_CLIENT = getHttpSolrClient(leaderUrl + "/" + COLLECTION_NAME + "/");
-        S_TWO_NON_LEADER_CLIENT = getHttpSolrClient(passiveUrl + "/" + COLLECTION_NAME + "/");
+        S_TWO_LEADER_CLIENT = getHttpSolrClient(leaderUrl, COLLECTION_NAME);
+        S_TWO_NON_LEADER_CLIENT = getHttpSolrClient(passiveUrl, COLLECTION_NAME);
       } else {
         fail("unexpected shard: " + shardName);
       }
     }
     assertEquals("Should be exactly one server left (not hosting either shard)", 1, urlMap.size());
-    NO_COLLECTION_CLIENT =
-        getHttpSolrClient(urlMap.values().iterator().next() + "/" + COLLECTION_NAME + "/");
+    NO_COLLECTION_CLIENT = getHttpSolrClient(urlMap.values().iterator().next(), COLLECTION_NAME);
 
     assertNotNull(S_ONE_LEADER_CLIENT);
     assertNotNull(S_TWO_LEADER_CLIENT);
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestTolerantUpdateProcessorRandomCloud.java b/solr/core/src/test/org/apache/solr/cloud/TestTolerantUpdateProcessorRandomCloud.java
index 9689620b54d..8b72b7fda35 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestTolerantUpdateProcessorRandomCloud.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestTolerantUpdateProcessorRandomCloud.java
@@ -116,7 +116,7 @@ public class TestTolerantUpdateProcessorRandomCloud extends SolrCloudTestCase {
 
     for (JettySolrRunner jetty : cluster.getJettySolrRunners()) {
       URL jettyURL = jetty.getBaseUrl();
-      NODE_CLIENTS.add(getHttpSolrClient(jettyURL.toString() + "/" + COLLECTION_NAME + "/"));
+      NODE_CLIENTS.add(getHttpSolrClient(jettyURL.toString(), COLLECTION_NAME));
     }
     assertEquals(numServers, NODE_CLIENTS.size());
   }
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java
index 3794840112a..517a718416c 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java
@@ -966,9 +966,9 @@ public class ShardSplitTest extends BasicDistributedZkTest {
     waitForRecoveriesToFinish(false);
 
     getCommonCloudSolrClient();
-    String url = getUrlFromZk(cloudClient.getClusterState(), collectionName);
+    String baseUrl = getBaseUrlFromZk(cloudClient.getClusterState(), collectionName);
 
-    try (SolrClient collectionClient = getHttpSolrClient(url)) {
+    try (SolrClient collectionClient = getHttpSolrClient(baseUrl, collectionName)) {
 
       ClusterState clusterState = cloudClient.getClusterState();
       final DocRouter router = clusterState.getCollection(collectionName).getRouter();
@@ -1037,9 +1037,9 @@ public class ShardSplitTest extends BasicDistributedZkTest {
     waitForRecoveriesToFinish(false);
 
     getCommonCloudSolrClient();
-    String url = getUrlFromZk(cloudClient.getClusterState(), collectionName);
+    String baseUrl = getBaseUrlFromZk(cloudClient.getClusterState(), collectionName);
 
-    try (SolrClient collectionClient = getHttpSolrClient(url)) {
+    try (SolrClient collectionClient = getHttpSolrClient(baseUrl, collectionName)) {
 
       String splitKey = "b!";
 
@@ -1194,7 +1194,8 @@ public class ShardSplitTest extends BasicDistributedZkTest {
     ZkCoreNodeProps shard1_0 =
         getLeaderUrlFromZk(AbstractDistribZkTestBase.DEFAULT_COLLECTION, SHARD1_0);
     QueryResponse response;
-    try (SolrClient shard1_0Client = getHttpSolrClient(shard1_0.getCoreUrl())) {
+    try (SolrClient shard1_0Client =
+        getHttpSolrClient(shard1_0.getBaseUrl(), shard1_0.getCoreName())) {
       response = shard1_0Client.query(query);
     }
     long shard10Count = response.getResults().getNumFound();
@@ -1202,7 +1203,8 @@ public class ShardSplitTest extends BasicDistributedZkTest {
     ZkCoreNodeProps shard1_1 =
         getLeaderUrlFromZk(AbstractDistribZkTestBase.DEFAULT_COLLECTION, SHARD1_1);
     QueryResponse response2;
-    try (SolrClient shard1_1Client = getHttpSolrClient(shard1_1.getCoreUrl())) {
+    try (SolrClient shard1_1Client =
+        getHttpSolrClient(shard1_1.getBaseUrl(), shard1_1.getCoreName())) {
       response2 = shard1_1Client.query(query);
     }
     long shard11Count = response2.getResults().getNumFound();
@@ -1225,7 +1227,7 @@ public class ShardSplitTest extends BasicDistributedZkTest {
     for (Replica replica : slice.getReplicas()) {
       String coreUrl = new ZkCoreNodeProps(replica).getCoreUrl();
       QueryResponse response;
-      try (SolrClient client = getHttpSolrClient(coreUrl)) {
+      try (SolrClient client = getHttpSolrClient(replica)) {
         response = client.query(query);
       }
       numFound[c++] = response.getResults().getNumFound();
diff --git a/solr/core/src/test/org/apache/solr/handler/TestReplicationHandler.java b/solr/core/src/test/org/apache/solr/handler/TestReplicationHandler.java
index eeb0c360523..fc7c8e352d1 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestReplicationHandler.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestReplicationHandler.java
@@ -257,9 +257,7 @@ public class TestReplicationHandler extends SolrTestCaseJ4 {
   }
 
   private SolrClient adminClient(JettySolrRunner client) {
-    String adminUrl =
-        client.getBaseUrl().toString().replace("/" + DEFAULT_TEST_COLLECTION_NAME, "");
-    return getHttpSolrClient(adminUrl);
+    return getHttpSolrClient(client.getBaseUrl().toString());
   }
 
   @Test
diff --git a/solr/core/src/test/org/apache/solr/handler/TestStressIncrementalBackup.java b/solr/core/src/test/org/apache/solr/handler/TestStressIncrementalBackup.java
index 58286fec3de..f8965eddb3c 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestStressIncrementalBackup.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestStressIncrementalBackup.java
@@ -81,7 +81,7 @@ public class TestStressIncrementalBackup extends SolrCloudTestCase {
             .iterator()
             .next();
     coreName = r.getCoreName();
-    coreClient = getHttpSolrClient(r.getCoreUrl());
+    coreClient = getHttpSolrClient(r);
   }
 
   @After
diff --git a/solr/core/src/test/org/apache/solr/handler/TestStressThreadBackup.java b/solr/core/src/test/org/apache/solr/handler/TestStressThreadBackup.java
index 8b81b733ab5..2b60d769075 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestStressThreadBackup.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestStressThreadBackup.java
@@ -370,7 +370,7 @@ public class TestStressThreadBackup extends SolrCloudTestCase {
             .iterator()
             .next();
     coreName = r.getCoreName();
-    coreClient = getHttpSolrClient(r.getCoreUrl());
+    coreClient = getHttpSolrClient(r);
   }
 
   /**
diff --git a/solr/core/src/test/org/apache/solr/handler/component/DistributedDebugComponentTest.java b/solr/core/src/test/org/apache/solr/handler/component/DistributedDebugComponentTest.java
index f9b13f318ce..5027f975c33 100644
--- a/solr/core/src/test/org/apache/solr/handler/component/DistributedDebugComponentTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/component/DistributedDebugComponentTest.java
@@ -63,8 +63,8 @@ public class DistributedDebugComponentTest extends SolrJettyTestBase {
     createAndStartJetty(solrHome.getAbsolutePath());
     String url = getBaseUrl();
 
-    collection1 = getHttpSolrClient(url + "/collection1");
-    collection2 = getHttpSolrClient(url + "/collection2");
+    collection1 = getHttpSolrClient(url, "collection1");
+    collection2 = getHttpSolrClient(url, "collection2");
 
     String urlCollection1 = getBaseUrl() + "/" + "collection1";
     String urlCollection2 = getBaseUrl() + "/" + "collection2";
diff --git a/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetJoinDomain.java b/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetJoinDomain.java
index e11c4a7795a..430ba44a56d 100644
--- a/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetJoinDomain.java
+++ b/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetJoinDomain.java
@@ -125,7 +125,7 @@ public class TestCloudJSONFacetJoinDomain extends SolrCloudTestCase {
     waitForRecoveriesToFinish(CLOUD_CLIENT);
 
     for (JettySolrRunner jetty : cluster.getJettySolrRunners())
-      CLIENTS.add(getHttpSolrClient(jetty.getBaseUrl() + "/" + COLLECTION_NAME + "/"));
+      CLIENTS.add(getHttpSolrClient(jetty.getBaseUrl().toString(), COLLECTION_NAME));
 
     final int numDocs = atLeast(100);
     for (int id = 0; id < numDocs; id++) {
diff --git a/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKG.java b/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKG.java
index 685b5d3419d..c2b6e1149e4 100644
--- a/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKG.java
+++ b/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKG.java
@@ -152,7 +152,7 @@ public class TestCloudJSONFacetSKG extends SolrCloudTestCase {
     waitForRecoveriesToFinish(CLOUD_CLIENT);
 
     for (JettySolrRunner jetty : cluster.getJettySolrRunners()) {
-      CLIENTS.add(getHttpSolrClient(jetty.getBaseUrl() + "/" + COLLECTION_NAME + "/"));
+      CLIENTS.add(getHttpSolrClient(jetty.getBaseUrl().toString(), COLLECTION_NAME));
     }
 
     final int numDocs = atLeast(100);
diff --git a/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKGEquiv.java b/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKGEquiv.java
index 285154d4351..31e1b0892ec 100644
--- a/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKGEquiv.java
+++ b/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKGEquiv.java
@@ -143,7 +143,7 @@ public class TestCloudJSONFacetSKGEquiv extends SolrCloudTestCase {
     waitForRecoveriesToFinish(CLOUD_CLIENT);
 
     for (JettySolrRunner jetty : cluster.getJettySolrRunners()) {
-      CLIENTS.add(getHttpSolrClient(jetty.getBaseUrl() + "/" + COLLECTION_NAME + "/"));
+      CLIENTS.add(getHttpSolrClient(jetty.getBaseUrl().toString(), COLLECTION_NAME));
     }
 
     final int numDocs = atLeast(100);
diff --git a/solr/core/src/test/org/apache/solr/update/DeleteByIdWithRouterFieldTest.java b/solr/core/src/test/org/apache/solr/update/DeleteByIdWithRouterFieldTest.java
index e4339f045eb..5e818dd045a 100644
--- a/solr/core/src/test/org/apache/solr/update/DeleteByIdWithRouterFieldTest.java
+++ b/solr/core/src/test/org/apache/solr/update/DeleteByIdWithRouterFieldTest.java
@@ -116,10 +116,10 @@ public class DeleteByIdWithRouterFieldTest extends SolrCloudTestCase {
       final String shardName = entry.getKey();
       final Slice slice = entry.getValue();
       final Replica leader = entry.getValue().getLeader();
-      try (SolrClient leaderClient = getHttpSolrClient(leader.getCoreUrl())) {
+      try (SolrClient leaderClient = getHttpSolrClient(leader)) {
         final SolrDocumentList leaderResults = leaderClient.query(params).getResults();
         for (Replica replica : slice) {
-          try (SolrClient replicaClient = getHttpSolrClient(replica.getCoreUrl())) {
+          try (SolrClient replicaClient = getHttpSolrClient(replica)) {
             final SolrDocumentList replicaResults = replicaClient.query(params).getResults();
             assertEquals(
                 "inconsistency w/leader: shard=" + shardName + "core=" + replica.getCoreName(),
diff --git a/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesDistrib.java b/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesDistrib.java
index 329f379fd35..33ee84a376b 100644
--- a/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesDistrib.java
+++ b/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesDistrib.java
@@ -1146,7 +1146,9 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
       // the resurrection can happen from there (instead of the leader)
       update.setParam(
           DistributedUpdateProcessor.DISTRIB_FROM,
-          ((HttpSolrClient) NONLEADERS.get(1)).getBaseURL());
+          ((HttpSolrClient) NONLEADERS.get(1)).getBaseURL()
+              + "/"
+              + NONLEADERS.get(1).getDefaultCollection());
       AsyncUpdateWithRandomCommit task =
           new AsyncUpdateWithRandomCommit(update, NONLEADERS.get(0), random().nextLong());
       updateResponses.add(threadpool.submit(task));
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttpSolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttpSolrClient.java
index b6b5c51707f..24d7edc175e 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttpSolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttpSolrClient.java
@@ -122,10 +122,14 @@ public class LBHttpSolrClient extends LBSolrClient {
     HttpSolrClient client;
     if (httpSolrClientBuilder != null) {
       synchronized (this) {
-        httpSolrClientBuilder.withBaseSolrUrl(server).withHttpClient(httpClient);
-        httpSolrClientBuilder.withConnectionTimeout(connectionTimeoutMillis, TimeUnit.MILLISECONDS);
-        httpSolrClientBuilder.withSocketTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS);
-
+        httpSolrClientBuilder
+            .withBaseSolrUrl(server)
+            .withHttpClient(httpClient)
+            .withConnectionTimeout(connectionTimeoutMillis, TimeUnit.MILLISECONDS)
+            .withSocketTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS);
+        if (defaultCollection != null) {
+          httpSolrClientBuilder.withDefaultCollection(defaultCollection);
+        }
         if (requestWriter != null) {
           httpSolrClientBuilder.withRequestWriter(requestWriter);
         }
@@ -145,6 +149,12 @@ public class LBHttpSolrClient extends LBSolrClient {
           .withResponseParser(parser)
           .withConnectionTimeout(connectionTimeoutMillis, TimeUnit.MILLISECONDS)
           .withSocketTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS);
+
+      // Note that this may override the value extracted from the base URL..should we log a warning
+      // here?
+      if (defaultCollection != null) {
+        clientBuilder.withDefaultCollection(defaultCollection);
+      }
       if (requestWriter != null) {
         clientBuilder.withRequestWriter(requestWriter);
       }
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleBinaryTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleBinaryTest.java
index 897e37c2ab0..4aa7c0938bc 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleBinaryTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleBinaryTest.java
@@ -35,7 +35,8 @@ public class SolrExampleBinaryTest extends SolrExampleTests {
 
   @Override
   public SolrClient createNewSolrClient() {
-    return new HttpSolrClient.Builder(getCoreUrl())
+    return new HttpSolrClient.Builder(getBaseUrl())
+        .withDefaultCollection(DEFAULT_TEST_CORENAME)
         .allowMultiPartPost(random().nextBoolean())
         .withRequestWriter(new BinaryRequestWriter())
         .withResponseParser(new BinaryResponseParser())
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleCborTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleCborTest.java
index 9441eacfa1d..dd1bbb0f0de 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleCborTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleCborTest.java
@@ -52,7 +52,8 @@ public class SolrExampleCborTest extends SolrExampleTests {
 
   @Override
   public SolrClient createNewSolrClient() {
-    return new HttpSolrClient.Builder(getCoreUrl())
+    return new HttpSolrClient.Builder(getBaseUrl())
+        .withDefaultCollection(DEFAULT_TEST_CORENAME)
         .allowMultiPartPost(random().nextBoolean())
         .withRequestWriter(cborRequestWriter())
         .withResponseParser(cborResponseparser())
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleXMLTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleXMLTest.java
index faa4c176526..ae392fd11ed 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleXMLTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleXMLTest.java
@@ -35,12 +35,11 @@ public class SolrExampleXMLTest extends SolrExampleTests {
 
   @Override
   public SolrClient createNewSolrClient() {
-    HttpSolrClient.Builder httpSolrClientBuilder = new HttpSolrClient.Builder(getCoreUrl());
-    httpSolrClientBuilder.allowMultiPartPost(random().nextBoolean());
-
-    httpSolrClientBuilder
+    return new HttpSolrClient.Builder(getBaseUrl())
+        .withDefaultCollection(DEFAULT_TEST_CORENAME)
+        .allowMultiPartPost(random().nextBoolean())
         .withRequestWriter(new RequestWriter())
-        .withResponseParser(new XMLResponseParser());
-    return httpSolrClientBuilder.build();
+        .withResponseParser(new XMLResponseParser())
+        .build();
   }
 }
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrSchemalessExampleTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrSchemalessExampleTest.java
index f188c66f299..e66d8362631 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrSchemalessExampleTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrSchemalessExampleTest.java
@@ -130,14 +130,15 @@ public class SolrSchemalessExampleTest extends SolrExampleTestsBase {
 
   @Override
   public SolrClient createNewSolrClient() {
-    HttpSolrClient.Builder httpSolrClientBuilder = new HttpSolrClient.Builder(getCoreUrl());
+    HttpSolrClient.Builder httpSolrClientBuilder =
+        new HttpSolrClient.Builder(getBaseUrl())
+            .withDefaultCollection(DEFAULT_TEST_CORENAME)
+            .allowMultiPartPost(random().nextBoolean());
     if (random().nextBoolean()) {
       httpSolrClientBuilder
           .withRequestWriter(new BinaryRequestWriter())
           .withResponseParser(new BinaryResponseParser());
     }
-    httpSolrClientBuilder.allowMultiPartPost(random().nextBoolean());
-
     return httpSolrClientBuilder.build();
   }
 }
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/TestBatchUpdate.java b/solr/solrj/src/test/org/apache/solr/client/solrj/TestBatchUpdate.java
index 68d70c8ca44..9343d76bc36 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/TestBatchUpdate.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/TestBatchUpdate.java
@@ -47,7 +47,10 @@ public class TestBatchUpdate extends SolrJettyTestBase {
   @Test
   public void testWithXml() throws Exception {
     try (SolrClient client =
-        new HttpSolrClient.Builder(getCoreUrl()).withRequestWriter(new RequestWriter()).build()) {
+        new HttpSolrClient.Builder(getBaseUrl())
+            .withDefaultCollection(DEFAULT_TEST_CORENAME)
+            .withRequestWriter(new RequestWriter())
+            .build()) {
       client.deleteByQuery("*:*"); // delete everything!
       doIt(client);
     }
@@ -56,7 +59,8 @@ public class TestBatchUpdate extends SolrJettyTestBase {
   @Test
   public void testWithBinary() throws Exception {
     try (SolrClient client =
-        new HttpSolrClient.Builder(getCoreUrl())
+        new HttpSolrClient.Builder(getBaseUrl())
+            .withDefaultCollection(DEFAULT_TEST_CORENAME)
             .withRequestWriter(new BinaryRequestWriter())
             .build()) {
       client.deleteByQuery("*:*"); // delete everything!
@@ -67,7 +71,8 @@ public class TestBatchUpdate extends SolrJettyTestBase {
   @Test
   public void testWithBinaryBean() throws Exception {
     try (SolrClient client =
-        new HttpSolrClient.Builder(getCoreUrl())
+        new HttpSolrClient.Builder(getBaseUrl())
+            .withDefaultCollection(DEFAULT_TEST_CORENAME)
             .withRequestWriter(new BinaryRequestWriter())
             .build()) {
       client.deleteByQuery("*:*"); // delete everything!
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttp2SolrClient.java b/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttp2SolrClient.java
index 60e3cff52cd..ac8a358e7d9 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttp2SolrClient.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttp2SolrClient.java
@@ -102,7 +102,8 @@ public class TestLBHttp2SolrClient extends SolrTestCaseJ4 {
       docs.add(doc);
     }
     SolrResponseBase resp;
-    try (SolrClient client = getHttpSolrClient(solrInstance.getUrl())) {
+    try (SolrClient client =
+        getHttpSolrClient(solrInstance.getBaseUrl(), solrInstance.getDefaultCollection())) {
       resp = client.add(docs);
       assertEquals(0, resp.getStatus());
       resp = client.commit();
@@ -274,6 +275,14 @@ public class TestLBHttp2SolrClient extends SolrTestCaseJ4 {
       return buildUrl(port) + "/collection1";
     }
 
+    public String getBaseUrl() {
+      return buildUrl(port);
+    }
+
+    public String getDefaultCollection() {
+      return "collection1";
+    }
+
     public String getSchemaFile() {
       return "solrj/solr/collection1/conf/schema-replication1.xml";
     }
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrClient.java b/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrClient.java
index f53139d53ba..fea222fcffe 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrClient.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrClient.java
@@ -101,7 +101,10 @@ public class TestLBHttpSolrClient extends SolrTestCaseJ4 {
     }
     SolrResponseBase resp;
     try (SolrClient client =
-        new HttpSolrClient.Builder(solrInstance.getUrl()).withHttpClient(httpClient).build()) {
+        new HttpSolrClient.Builder(solrInstance.getBaseUrl())
+            .withDefaultCollection(solrInstance.getDefaultCollection())
+            .withHttpClient(httpClient)
+            .build()) {
       resp = client.add(docs);
       assertEquals(0, resp.getStatus());
       resp = client.commit();
@@ -277,6 +280,14 @@ public class TestLBHttpSolrClient extends SolrTestCaseJ4 {
       return buildUrl(port) + "/collection1";
     }
 
+    public String getBaseUrl() {
+      return buildUrl(port);
+    }
+
+    public String getDefaultCollection() {
+      return "collection1";
+    }
+
     public String getSchemaFile() {
       return "solrj/solr/collection1/conf/schema-replication1.xml";
     }
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java b/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java
index 789d39d516d..0941775980d 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java
@@ -102,8 +102,10 @@ public class TestSolrJErrorHandling extends SolrJettyTestBase {
   @Test
   public void testWithXml() throws Exception {
     try (SolrClient client =
-        new HttpSolrClient.Builder(getCoreUrl()).withRequestWriter(new RequestWriter()).build()) {
-
+        new HttpSolrClient.Builder(getBaseUrl())
+            .withDefaultCollection(DEFAULT_TEST_CORENAME)
+            .withRequestWriter(new RequestWriter())
+            .build()) {
       client.deleteByQuery("*:*"); // delete everything!
       doIt(client);
     }
@@ -112,7 +114,8 @@ public class TestSolrJErrorHandling extends SolrJettyTestBase {
   @Test
   public void testWithBinary() throws Exception {
     try (SolrClient client =
-        new HttpSolrClient.Builder(getCoreUrl())
+        new HttpSolrClient.Builder(getBaseUrl())
+            .withDefaultCollection(DEFAULT_TEST_CORENAME)
             .withRequestWriter(new BinaryRequestWriter())
             .build()) {
       client.deleteByQuery("*:*"); // delete everything!
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/BasicHttpSolrClientTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/BasicHttpSolrClientTest.java
index 0b299f34b4c..b2b2a4ce6be 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/BasicHttpSolrClientTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/BasicHttpSolrClientTest.java
@@ -208,13 +208,15 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
   @Test
   public void testTimeout() throws Exception {
     SolrQuery q = new SolrQuery("*:*");
+    final var queryRequest = new QueryRequest(q);
+    queryRequest.setPath("/slow/foo" + queryRequest.getPath());
     try (SolrClient client =
-        new HttpSolrClient.Builder(getBaseUrl() + "/slow/foo")
+        new HttpSolrClient.Builder(getBaseUrl())
             .withConnectionTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
             .withSocketTimeout(2000, TimeUnit.MILLISECONDS)
             .build()) {
       SolrServerException e =
-          expectThrows(SolrServerException.class, () -> client.query(q, METHOD.GET));
+          expectThrows(SolrServerException.class, () -> queryRequest.process(client));
       assertTrue(e.getMessage().contains("Timeout"));
     }
   }
@@ -231,10 +233,12 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
         ErrorCode.UNKNOWN,
         ErrorCode.getErrorCode(status));
 
-    try (SolrClient client = getHttpSolrClient(getBaseUrl() + "/debug/foo")) {
+    try (SolrClient client = getHttpSolrClient(getBaseUrl())) {
       DebugServlet.setErrorCode(status);
       SolrQuery q = new SolrQuery("foo");
-      SolrException e = expectThrows(SolrException.class, () -> client.query(q, METHOD.GET));
+      final var queryRequest = new QueryRequest(q);
+      queryRequest.setPath("/debug/foo" + queryRequest.getPath());
+      SolrException e = expectThrows(SolrException.class, () -> queryRequest.process(client));
       assertEquals("Unexpected exception status code", status, e.code());
     } finally {
       DebugServlet.clear();
@@ -244,12 +248,15 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
   @Test
   public void testQuery() throws Exception {
     DebugServlet.clear();
-    String url = getBaseUrl() + "/debug/foo";
+    final String debugPath = "/debug/foo";
     SolrQuery q = new SolrQuery("foo");
     q.setParam("a", "\u1234");
-    try (HttpSolrClient client = getHttpSolrClient(url)) {
+    final var queryRequest = new QueryRequest(q);
+    queryRequest.setPath(debugPath);
+    try (HttpSolrClient client = getHttpSolrClient(getBaseUrl())) {
 
-      expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> client.query(q, METHOD.GET));
+      expectThrows(
+          BaseHttpSolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
 
       // default method
       assertEquals("get", DebugServlet.lastMethod);
@@ -278,8 +285,9 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
 
       // POST
       DebugServlet.clear();
+      queryRequest.setMethod(METHOD.POST);
       expectThrows(
-          BaseHttpSolrClient.RemoteSolrException.class, () -> client.query(q, METHOD.POST));
+          BaseHttpSolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
 
       assertEquals("post", DebugServlet.lastMethod);
       assertEquals(
@@ -302,7 +310,9 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
 
       // PUT
       DebugServlet.clear();
-      expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> client.query(q, METHOD.PUT));
+      queryRequest.setMethod(METHOD.PUT);
+      expectThrows(
+          BaseHttpSolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
 
       assertEquals("put", DebugServlet.lastMethod);
       assertEquals(
@@ -326,10 +336,14 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
 
     // XML
     try (HttpSolrClient client =
-        new HttpSolrClient.Builder(url).withResponseParser(new XMLResponseParser()).build()) {
+        new HttpSolrClient.Builder(getBaseUrl())
+            .withResponseParser(new XMLResponseParser())
+            .build()) {
       // XML/GET
       DebugServlet.clear();
-      expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> client.query(q, METHOD.GET));
+      queryRequest.setMethod(METHOD.GET); // Reset to the default here after using 'PUT' above
+      expectThrows(
+          BaseHttpSolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
 
       assertEquals("get", DebugServlet.lastMethod);
       assertEquals(
@@ -349,8 +363,9 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
 
       // XML/POST
       DebugServlet.clear();
+      queryRequest.setMethod(METHOD.POST);
       expectThrows(
-          BaseHttpSolrClient.RemoteSolrException.class, () -> client.query(q, METHOD.POST));
+          BaseHttpSolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
 
       assertEquals("post", DebugServlet.lastMethod);
       assertEquals(
@@ -372,7 +387,9 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
           DebugServlet.headers.get("Content-Type"));
 
       DebugServlet.clear();
-      expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> client.query(q, METHOD.PUT));
+      queryRequest.setMethod(METHOD.PUT);
+      expectThrows(
+          BaseHttpSolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
 
       assertEquals("put", DebugServlet.lastMethod);
       assertEquals(
@@ -398,9 +415,13 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
   @Test
   public void testDelete() throws Exception {
     DebugServlet.clear();
-    String url = getBaseUrl() + "/debug/foo";
-    try (HttpSolrClient client = getHttpSolrClient(url)) {
-      expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> client.deleteById("id"));
+    final String debugPath = "/debug/foo";
+
+    try (HttpSolrClient client = getHttpSolrClient(getBaseUrl())) {
+      final UpdateRequest deleteById = new UpdateRequest();
+      deleteById.deleteById("id");
+      deleteById.setPath(debugPath + deleteById.getPath());
+      expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> deleteById.process(client));
 
       // default method
       assertEquals("post", DebugServlet.lastMethod);
@@ -425,8 +446,15 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
 
     // XML
     try (HttpSolrClient client =
-        new HttpSolrClient.Builder(url).withResponseParser(new XMLResponseParser()).build()) {
-      expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> client.deleteByQuery("*:*"));
+        new HttpSolrClient.Builder(getBaseUrl())
+            .withResponseParser(new XMLResponseParser())
+            .build()) {
+      final var deleteByQueryRequest = new UpdateRequest();
+      deleteByQueryRequest.setPath(debugPath + deleteByQueryRequest.getPath());
+      deleteByQueryRequest.deleteByQuery("*:*");
+      deleteByQueryRequest.setCommitWithin(-1);
+      expectThrows(
+          BaseHttpSolrClient.RemoteSolrException.class, () -> deleteByQueryRequest.process(client));
 
       assertEquals("post", DebugServlet.lastMethod);
       assertEquals(
@@ -460,13 +488,14 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
   @Test
   public void testUpdate() throws Exception {
     DebugServlet.clear();
-    String url = getBaseUrl() + "/debug/foo";
+    final String debugPath = "/debug/foo";
 
-    try (HttpSolrClient client = getHttpSolrClient(url)) {
+    try (HttpSolrClient client = getHttpSolrClient(getBaseUrl())) {
       UpdateRequest req = new UpdateRequest();
       req.add(new SolrInputDocument());
+      req.setPath(debugPath + req.getPath());
       req.setParam("a", "\u1234");
-      expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> client.request(req));
+      expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> req.process(client));
 
       // default method
       assertEquals("post", DebugServlet.lastMethod);
@@ -490,12 +519,13 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
     DebugServlet.clear();
     // XML response and writer
     try (HttpSolrClient client =
-        new HttpSolrClient.Builder(url)
+        new HttpSolrClient.Builder(getBaseUrl())
             .withRequestWriter(new RequestWriter())
             .withResponseParser(new XMLResponseParser())
             .build()) {
       UpdateRequest req = new UpdateRequest();
       req.add(new SolrInputDocument());
+      req.setPath(debugPath + req.getPath());
       req.setParam("a", "\u1234");
 
       expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> client.request(req));
@@ -516,12 +546,13 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
     DebugServlet.clear();
     // javabin request
     try (HttpSolrClient client =
-        new HttpSolrClient.Builder(url)
+        new HttpSolrClient.Builder(getBaseUrl())
             .withRequestWriter(new BinaryRequestWriter())
             .withResponseParser(new BinaryResponseParser())
             .build()) {
       UpdateRequest req = new UpdateRequest();
       req.add(new SolrInputDocument());
+      req.setPath(debugPath + req.getPath());
       req.setParam("a", "\u1234");
 
       expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> client.request(req));
@@ -543,53 +574,61 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
 
   @Test
   public void testRedirect() throws Exception {
-    final String clientUrl = getBaseUrl() + "/redirect/foo";
+    final String redirectPath = "/redirect/foo";
     SolrQuery q = new SolrQuery("*:*");
+    final var queryRequest = new QueryRequest(q);
+    queryRequest.setPath(redirectPath + queryRequest.getPath());
 
     // default for redirect is false.
-    try (HttpSolrClient client = new HttpSolrClient.Builder(clientUrl).build()) {
-      SolrServerException e = expectThrows(SolrServerException.class, () -> client.query(q));
+    try (HttpSolrClient client = new HttpSolrClient.Builder(getBaseUrl()).build()) {
+      SolrServerException e =
+          expectThrows(SolrServerException.class, () -> queryRequest.process(client));
       assertTrue(e.getMessage().contains("redirect"));
     }
 
     try (HttpSolrClient client =
-        new HttpSolrClient.Builder(clientUrl).withFollowRedirects(true).build()) {
+        new HttpSolrClient.Builder(getBaseUrl()).withFollowRedirects(true).build()) {
       // No exception expected
-      client.query(q);
+      queryRequest.process(client);
     }
 
     // And with explicit false:
     try (HttpSolrClient client =
-        new HttpSolrClient.Builder(clientUrl).withFollowRedirects(false).build()) {
-      SolrServerException e = expectThrows(SolrServerException.class, () -> client.query(q));
+        new HttpSolrClient.Builder(getBaseUrl()).withFollowRedirects(false).build()) {
+      SolrServerException e =
+          expectThrows(SolrServerException.class, () -> queryRequest.process(client));
       assertTrue(e.getMessage().contains("redirect"));
     }
   }
 
   @Test
   public void testCompression() throws Exception {
+    final String debugPath = "/debug/foo";
     final SolrQuery q = new SolrQuery("*:*");
+    final var queryRequest = new QueryRequest(q);
+    queryRequest.setPath(debugPath + queryRequest.getPath());
 
-    final String clientUrl = getBaseUrl() + "/debug/foo";
-    try (SolrClient client = getHttpSolrClient(clientUrl)) {
+    try (SolrClient client = getHttpSolrClient(getBaseUrl())) {
       // verify request header gets set
       DebugServlet.clear();
-      expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> client.query(q));
+      expectThrows(
+          BaseHttpSolrClient.RemoteSolrException.class, () -> queryRequest.process(client));
       assertNull(DebugServlet.headers.toString(), DebugServlet.headers.get("Accept-Encoding"));
     }
 
-    try (SolrClient client = new HttpSolrClient.Builder(clientUrl).allowCompression(true).build()) {
+    try (SolrClient client =
+        new HttpSolrClient.Builder(getBaseUrl()).allowCompression(true).build()) {
       try {
-        client.query(q);
+        queryRequest.process(client);
       } catch (BaseHttpSolrClient.RemoteSolrException ignored) {
       }
       assertNotNull(DebugServlet.headers.get("Accept-Encoding"));
     }
 
     try (SolrClient client =
-        new HttpSolrClient.Builder(clientUrl).allowCompression(false).build()) {
+        new HttpSolrClient.Builder(getBaseUrl()).allowCompression(false).build()) {
       try {
-        client.query(q);
+        queryRequest.process(client);
       } catch (BaseHttpSolrClient.RemoteSolrException ignored) {
       }
     }
@@ -621,7 +660,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
     }
 
     // verify compressed response can be handled
-    try (SolrClient client = getHttpSolrClient(getCoreUrl())) {
+    try (SolrClient client = getHttpSolrClient(getBaseUrl(), DEFAULT_TEST_COLLECTION_NAME)) {
       QueryResponse response = client.query(new SolrQuery("foo"));
       assertEquals(0, response.getStatus());
     }
@@ -641,8 +680,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
           client.query("collection1", new SolrQuery("id:collection")).getResults().getNumFound());
     }
 
-    final String collection1Url = getCoreUrl();
-    try (SolrClient client = getHttpSolrClient(collection1Url)) {
+    try (SolrClient client = getHttpSolrClient(getBaseUrl(), DEFAULT_TEST_CORENAME)) {
       assertEquals(1, client.query(new SolrQuery("id:collection")).getResults().getNumFound());
     }
   }
@@ -651,7 +689,8 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
   public void testGetRawStream() throws SolrServerException, IOException {
     CloseableHttpClient httpClient = HttpClientUtil.createClient(null);
     try (SolrClient solrClient =
-        new HttpSolrClient.Builder(getCoreUrl())
+        new HttpSolrClient.Builder(getBaseUrl())
+            .withDefaultCollection(DEFAULT_TEST_CORENAME)
             .withHttpClient(httpClient)
             .withResponseParser(null)
             .build(); ) {
@@ -722,14 +761,19 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
     HttpClientUtil.addRequestInterceptor(changeRequestInterceptor);
     HttpClientUtil.addRequestInterceptor(cookieSettingRequestInterceptor);
 
-    final String clientUrl = getBaseUrl() + "/debug/foo";
-    try (SolrClient server = getHttpSolrClient(clientUrl)) {
+    final String debugPath = "/debug/foo";
+    try (SolrClient server = getHttpSolrClient(getBaseUrl())) {
 
       SolrQuery q = new SolrQuery("foo");
       q.setParam("a", "\u1234");
+      final var queryRequest = new QueryRequest(q);
+      queryRequest.setPath(debugPath + queryRequest.getPath());
       expectThrows(
           Exception.class,
-          () -> server.query(q, random().nextBoolean() ? METHOD.POST : METHOD.GET));
+          () -> {
+            queryRequest.setMethod(random().nextBoolean() ? METHOD.POST : METHOD.GET);
+            queryRequest.process(server);
+          });
 
       // Assert cookies from UseContextCallback
       assertNotNull(DebugServlet.cookies);
@@ -786,14 +830,14 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
 
   @Test
   public void testQueryString() throws Exception {
-
-    final String clientUrl = getBaseUrl() + "/debug/foo";
-    HttpSolrClient.Builder builder = new HttpSolrClient.Builder(clientUrl);
+    final String debugPath = "/debug/foo";
+    HttpSolrClient.Builder builder = new HttpSolrClient.Builder(getBaseUrl());
     try (HttpSolrClient client =
         builder.withTheseParamNamesInTheUrl(Set.of("serverOnly")).build()) {
       // test without request query params
       DebugServlet.clear();
       UpdateRequest req = new UpdateRequest();
+      req.setPath(debugPath + req.getPath());
       setReqParamsOf(req, "serverOnly", "notServer");
       expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> client.request(req));
       verifyServletState(client, req);
@@ -802,6 +846,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
       // test without server query params
       DebugServlet.clear();
       UpdateRequest req2 = new UpdateRequest();
+      req2.setPath(debugPath + req2.getPath());
       req2.setQueryParams(Set.of("requestOnly"));
       setReqParamsOf(req2, "requestOnly", "notRequest");
       expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> client.request(req2));
@@ -812,6 +857,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
       // test with both request and server query params
       DebugServlet.clear();
       UpdateRequest req3 = new UpdateRequest();
+      req3.setPath(debugPath + req3.getPath());
       req3.setQueryParams(Set.of("requestOnly", "both"));
       setReqParamsOf(req3, "serverOnly", "requestOnly", "both", "neither");
       expectThrows(BaseHttpSolrClient.RemoteSolrException.class, () -> client.request(req3));
@@ -822,6 +868,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase {
       // test with both request and server query params with single stream
       DebugServlet.clear();
       UpdateRequest req4 = new UpdateRequest();
+      req4.setPath(debugPath + req4.getPath());
       req4.add(new SolrInputDocument());
       req4.setQueryParams(Set.of("requestOnly", "both"));
       setReqParamsOf(req4, "serverOnly", "requestOnly", "both", "neither");
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java
index 2c4f4657d99..0934fd5d331 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java
@@ -65,6 +65,7 @@ import org.apache.solr.common.params.ShardParams;
 import org.apache.solr.common.params.UpdateParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.common.util.URLUtil;
 import org.apache.solr.embedded.JettySolrRunner;
 import org.apache.solr.handler.admin.CollectionsHandler;
 import org.apache.solr.handler.admin.ConfigSetsHandler;
@@ -268,7 +269,9 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
         routes.entrySet().iterator();
     while (it.hasNext()) {
       Map.Entry<String, ? extends LBSolrClient.Req> entry = it.next();
-      String url = entry.getKey();
+      String coreUrl = entry.getKey();
+      final String baseUrl = URLUtil.extractBaseUrl(coreUrl);
+      final String coreName = URLUtil.extractCoreFromCoreUrl(coreUrl);
       UpdateRequest updateRequest = (UpdateRequest) entry.getValue().getRequest();
       SolrInputDocument doc = updateRequest.getDocuments().get(0);
       String id = doc.getField("id").getValue().toString();
@@ -276,7 +279,8 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
       params.add("q", "id:" + id);
       params.add("distrib", "false");
       QueryRequest queryRequest = new QueryRequest(params);
-      try (SolrClient solrClient = getHttpSolrClient(url)) {
+
+      try (SolrClient solrClient = getHttpSolrClient(baseUrl, coreName)) {
         QueryResponse queryResponse = queryRequest.process(solrClient);
         SolrDocumentList docList = queryResponse.getResults();
         assertEquals(1, docList.getNumFound());
@@ -315,7 +319,9 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
       it = routes.entrySet().iterator();
       while (it.hasNext()) {
         Map.Entry<String, ? extends LBSolrClient.Req> entry = it.next();
-        String url = entry.getKey();
+        String coreUrl = entry.getKey();
+        final String baseUrl = URLUtil.extractBaseUrl(coreUrl);
+        final String coreName = URLUtil.extractCoreFromCoreUrl(coreUrl);
         UpdateRequest updateRequest = (UpdateRequest) entry.getValue().getRequest();
         SolrInputDocument doc = updateRequest.getDocuments().get(0);
         String id = doc.getField("id").getValue().toString();
@@ -323,7 +329,7 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
         params.add("q", "id:" + id);
         params.add("distrib", "false");
         QueryRequest queryRequest = new QueryRequest(params);
-        try (SolrClient solrClient = getHttpSolrClient(url)) {
+        try (SolrClient solrClient = getHttpSolrClient(baseUrl, coreName)) {
           QueryResponse queryResponse = queryRequest.process(solrClient);
           SolrDocumentList docList = queryResponse.getResults();
           assertEquals(1, docList.getNumFound());
@@ -593,7 +599,8 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
 
     NamedList<Object> resp;
     try (SolrClient client =
-        new HttpSolrClient.Builder(baseUrl + "/" + collectionName)
+        new HttpSolrClient.Builder(baseUrl)
+            .withDefaultCollection(collectionName)
             .withConnectionTimeout(15000, TimeUnit.MILLISECONDS)
             .withSocketTimeout(60000, TimeUnit.MILLISECONDS)
             .build()) {
@@ -760,8 +767,7 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
     SolrQuery q = new SolrQuery().setQuery("*:*");
     BaseHttpSolrClient.RemoteSolrException sse = null;
 
-    final String url = r.getBaseUrl() + "/" + COLLECTION;
-    try (SolrClient solrClient = getHttpSolrClient(url)) {
+    try (SolrClient solrClient = getHttpSolrClient(r.getBaseUrl(), COLLECTION)) {
 
       if (log.isInfoEnabled()) {
         log.info("should work query, result {}", solrClient.query(q));
@@ -807,8 +813,7 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
     log.info("the node which does not serve this collection{} ", theNode);
     assertNotNull(theNode);
 
-    final String solrClientUrl = theNode + "/" + COLLECTION;
-    try (SolrClient solrClient = getHttpSolrClient(solrClientUrl)) {
+    try (SolrClient solrClient = getHttpSolrClient(theNode, COLLECTION)) {
 
       q.setParam(CloudSolrClient.STATE_VERSION, COLLECTION + ":" + (coll.getZNodeVersion() - 1));
       try {
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientTest.java
index 714b284da49..fdfb06b2ad2 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientTest.java
@@ -69,6 +69,7 @@ import org.apache.solr.common.params.ShardParams;
 import org.apache.solr.common.params.UpdateParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.common.util.URLUtil;
 import org.apache.solr.embedded.JettySolrRunner;
 import org.apache.solr.handler.admin.CollectionsHandler;
 import org.apache.solr.handler.admin.ConfigSetsHandler;
@@ -269,7 +270,9 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
     Iterator<Map.Entry<String, LBSolrClient.Req>> it = routes.entrySet().iterator();
     while (it.hasNext()) {
       Map.Entry<String, LBSolrClient.Req> entry = it.next();
-      String url = entry.getKey();
+      String coreUrl = entry.getKey();
+      final String baseUrl = URLUtil.extractBaseUrl(coreUrl);
+      final String coreName = URLUtil.extractCoreFromCoreUrl(coreUrl);
       UpdateRequest updateRequest = (UpdateRequest) entry.getValue().getRequest();
       SolrInputDocument doc = updateRequest.getDocuments().get(0);
       String id = doc.getField("id").getValue().toString();
@@ -277,7 +280,7 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
       params.add("q", "id:" + id);
       params.add("distrib", "false");
       QueryRequest queryRequest = new QueryRequest(params);
-      try (SolrClient solrClient = getHttpSolrClient(url)) {
+      try (SolrClient solrClient = getHttpSolrClient(baseUrl, coreName)) {
         QueryResponse queryResponse = queryRequest.process(solrClient);
         SolrDocumentList docList = queryResponse.getResults();
         assertEquals(1, docList.getNumFound());
@@ -316,7 +319,9 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
       it = routes.entrySet().iterator();
       while (it.hasNext()) {
         Map.Entry<String, LBSolrClient.Req> entry = it.next();
-        String url = entry.getKey();
+        String coreUrl = entry.getKey();
+        final String baseUrl = URLUtil.extractBaseUrl(coreUrl);
+        final String coreName = URLUtil.extractCoreFromCoreUrl(coreUrl);
         UpdateRequest updateRequest = (UpdateRequest) entry.getValue().getRequest();
         SolrInputDocument doc = updateRequest.getDocuments().get(0);
         String id = doc.getField("id").getValue().toString();
@@ -324,7 +329,7 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
         params.add("q", "id:" + id);
         params.add("distrib", "false");
         QueryRequest queryRequest = new QueryRequest(params);
-        try (SolrClient solrClient = getHttpSolrClient(url)) {
+        try (SolrClient solrClient = getHttpSolrClient(baseUrl, coreName)) {
           QueryResponse queryResponse = queryRequest.process(solrClient);
           SolrDocumentList docList = queryResponse.getResults();
           assertEquals(1, docList.getNumFound());
@@ -594,7 +599,8 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
 
     NamedList<Object> resp;
     try (SolrClient client =
-        new HttpSolrClient.Builder(baseUrl + "/" + collectionName)
+        new HttpSolrClient.Builder(baseUrl)
+            .withDefaultCollection(collectionName)
             .withConnectionTimeout(15000, TimeUnit.MILLISECONDS)
             .withSocketTimeout(60000, TimeUnit.MILLISECONDS)
             .build()) {
@@ -766,8 +772,7 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
     SolrQuery q = new SolrQuery().setQuery("*:*");
     BaseHttpSolrClient.RemoteSolrException sse = null;
 
-    final String url = r.getBaseUrl() + "/" + COLLECTION;
-    try (SolrClient solrClient = getHttpSolrClient(url)) {
+    try (SolrClient solrClient = getHttpSolrClient(r.getBaseUrl(), COLLECTION)) {
 
       if (log.isInfoEnabled()) {
         log.info("should work query, result {}", solrClient.query(q));
@@ -813,8 +818,7 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
     log.info("the node which does not serve this collection{} ", theNode);
     assertNotNull(theNode);
 
-    final String solrClientUrl = theNode + "/" + COLLECTION;
-    try (SolrClient solrClient = getHttpSolrClient(solrClientUrl)) {
+    try (SolrClient solrClient = getHttpSolrClient(theNode, COLLECTION)) {
 
       q.setParam(CloudSolrClient.STATE_VERSION, COLLECTION + ":" + (coll.getZNodeVersion() - 1));
       try {
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientBadInputTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientBadInputTest.java
index e3e6d513beb..2afa39725e4 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientBadInputTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientBadInputTest.java
@@ -41,7 +41,7 @@ public class HttpSolrClientBadInputTest extends SolrJettyTestBase {
 
   @Test
   public void testDeleteByIdReportsInvalidIdLists() throws Exception {
-    try (SolrClient client = getHttpSolrClient(getBaseUrl() + "/" + ANY_COLLECTION)) {
+    try (SolrClient client = getHttpSolrClient(getBaseUrl(), ANY_COLLECTION)) {
       assertExceptionThrownWithMessageContaining(
           IllegalArgumentException.class,
           List.of("ids", "null"),
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientConPoolTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientConPoolTest.java
index 57b03eff90a..c169faab0e7 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientConPoolTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientConPoolTest.java
@@ -48,10 +48,9 @@ public class HttpSolrClientConPoolTest extends SolrJettyTestBase {
   @BeforeClass
   public static void beforeTest() throws Exception {
     createAndStartJetty(legacyExampleCollection1SolrHome());
-    fooUrl = getBaseUrl() + "/" + "collection1";
-
+    fooUrl = getBaseUrl();
     secondJetty.startSolr(Path.of(legacyExampleCollection1SolrHome()));
-    barUrl = secondJetty.getBaseUrl() + "/" + "collection1";
+    barUrl = secondJetty.getBaseUrl();
   }
 
   public void testPoolSize() throws SolrServerException, IOException {
@@ -61,9 +60,15 @@ public class HttpSolrClientConPoolTest extends SolrJettyTestBase {
         HttpClientUtil.createClient(
             new ModifiableSolrParams(), pool, false /* let client shutdown it*/);
     final HttpSolrClient clientFoo =
-        new HttpSolrClient.Builder(fooUrl).withHttpClient(httpClient).build();
+        new HttpSolrClient.Builder(fooUrl)
+            .withDefaultCollection(DEFAULT_TEST_COLLECTION_NAME)
+            .withHttpClient(httpClient)
+            .build();
     final HttpSolrClient clientBar =
-        new HttpSolrClient.Builder(barUrl).withHttpClient(httpClient).build();
+        new HttpSolrClient.Builder(barUrl)
+            .withDefaultCollection(DEFAULT_TEST_COLLECTION_NAME)
+            .withHttpClient(httpClient)
+            .build();
 
     clientFoo.deleteByQuery("*:*");
     clientBar.deleteByQuery("*:*");
@@ -118,18 +123,21 @@ public class HttpSolrClientConPoolTest extends SolrJettyTestBase {
           new LBHttpSolrClient.Builder()
               .withBaseSolrUrl(fooUrl)
               .withBaseSolrUrl(barUrl)
+              .withDefaultCollection(DEFAULT_TEST_COLLECTION_NAME)
               .withHttpClient(httpClient)
               .build();
 
       List<ConcurrentUpdateSolrClient> concurrentClients =
           Arrays.asList(
               new ConcurrentUpdateSolrClient.Builder(fooUrl)
+                  .withDefaultCollection(DEFAULT_TEST_COLLECTION_NAME)
                   .withHttpClient(httpClient)
                   .withThreadCount(threadCount)
                   .withQueueSize(10)
                   .withExecutorService(threads)
                   .build(),
               new ConcurrentUpdateSolrClient.Builder(barUrl)
+                  .withDefaultCollection(DEFAULT_TEST_COLLECTION_NAME)
                   .withHttpClient(httpClient)
                   .withThreadCount(threadCount)
                   .withQueueSize(10)
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/response/NoOpResponseParserTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/response/NoOpResponseParserTest.java
index a97c36676f8..e8b916f3482 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/response/NoOpResponseParserTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/response/NoOpResponseParserTest.java
@@ -71,7 +71,8 @@ public class NoOpResponseParserTest extends SolrJettyTestBase {
   public void testQueryParse() throws Exception {
 
     try (SolrClient client =
-        new HttpSolrClient.Builder(getCoreUrl())
+        new HttpSolrClient.Builder(getBaseUrl())
+            .withDefaultCollection(DEFAULT_TEST_CORENAME)
             .withResponseParser(new NoOpResponseParser())
             .build()) {
       SolrQuery query = new SolrQuery("id:1234");
diff --git a/solr/test-framework/src/java/org/apache/solr/SolrJettyTestBase.java b/solr/test-framework/src/java/org/apache/solr/SolrJettyTestBase.java
index a4b08656fd7..cb80310f635 100644
--- a/solr/test-framework/src/java/org/apache/solr/SolrJettyTestBase.java
+++ b/solr/test-framework/src/java/org/apache/solr/SolrJettyTestBase.java
@@ -127,7 +127,9 @@ public abstract class SolrJettyTestBase extends SolrTestCaseJ4 {
    * options.
    */
   public SolrClient createNewSolrClient() {
-    return new HttpSolrClient.Builder(getCoreUrl()).build();
+    return new HttpSolrClient.Builder(getBaseUrl())
+        .withDefaultCollection(DEFAULT_TEST_CORENAME)
+        .build();
   }
 
   protected HttpClient getHttpClient() {
diff --git a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseHS.java b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseHS.java
index 26234b5e9f3..1d9a175c741 100644
--- a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseHS.java
+++ b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseHS.java
@@ -461,10 +461,6 @@ public class SolrTestCaseHS extends SolrTestCaseJ4 {
       return (SolrTestCaseJ4.isSSLMode() ? "https" : "http") + "://127.0.0.1:" + port + "/solr";
     }
 
-    public String getCollectionURL() {
-      return getBaseURL() + "/" + collection;
-    }
-
     /** string appropriate for passing in shards param (i.e. missing http://) */
     public String getShardURL() {
       return "127.0.0.1:" + port + "/solr" + "/" + collection;
@@ -472,7 +468,7 @@ public class SolrTestCaseHS extends SolrTestCaseJ4 {
 
     public SolrClient getSolrJ() {
       if (solrj == null) {
-        solrj = getHttpSolrClient(getCollectionURL());
+        solrj = getHttpSolrClient(getBaseURL(), collection);
       }
       return solrj;
     }
diff --git a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
index 5ada12e61d2..7f1fc596160 100644
--- a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
+++ b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
@@ -100,6 +100,7 @@ import org.apache.solr.common.SolrDocumentList;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.SolrInputField;
+import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.params.MultiMapSolrParams;
@@ -2655,14 +2656,25 @@ public abstract class SolrTestCaseJ4 extends SolrTestCase {
   /**
    * This method creates a basic HttpSolrClient. Tests that want to control the creation process
    * should use the {@link org.apache.solr.client.solrj.impl.Http2SolrClient.Builder} class directly
+   *
+   * @param url the base URL for a Solr node. Should not contain a core or collection name.
    */
   public static HttpSolrClient getHttpSolrClient(String url) {
     return new HttpSolrClient.Builder(url).build();
   }
 
+  /** Create a basic HttpSolrClient pointed at the specified replica */
+  public static HttpSolrClient getHttpSolrClient(Replica replica) {
+    return getHttpSolrClient(replica.getBaseUrl(), replica.getCoreName());
+  }
+
   /**
    * This method creates a basic HttpSolrClient. Tests that want to control the creation process
    * should use the {@link org.apache.solr.client.solrj.impl.Http2SolrClient.Builder} class directly
+   *
+   * @param url the base URL of a Solr node. Should <em>not</em> include a collection or core name.
+   * @param defaultCoreName the name of a core that the created client should default to when making
+   *     core-aware requests
    */
   public static HttpSolrClient getHttpSolrClient(String url, String defaultCoreName) {
     return new HttpSolrClient.Builder(url).withDefaultCollection(defaultCoreName).build();
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractBasicDistributedZk2TestBase.java b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractBasicDistributedZk2TestBase.java
index 899efc03dcb..7888598238b 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractBasicDistributedZk2TestBase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractBasicDistributedZk2TestBase.java
@@ -189,7 +189,7 @@ public abstract class AbstractBasicDistributedZk2TestBase extends AbstractFullDi
     SolrQuery query = new SolrQuery("*:*");
 
     String collectionUrl = baseUrl + "/onenodecollection" + "core";
-    try (SolrClient client = getHttpSolrClient(collectionUrl)) {
+    try (SolrClient client = getHttpSolrClient(baseUrl, "onenodecollectioncore")) {
 
       // it might take a moment for the proxy node to see us in their cloud state
       waitForNon403or404or503(client, collectionUrl);
@@ -204,7 +204,7 @@ public abstract class AbstractBasicDistributedZk2TestBase extends AbstractFullDi
       assertEquals(docs - 1, results.getResults().getNumFound());
     }
 
-    try (SolrClient client = getHttpSolrClient(baseUrl + "/onenodecollection")) {
+    try (SolrClient client = getHttpSolrClient(baseUrl, "onenodecollection")) {
       QueryResponse results = client.query(query);
       assertEquals(docs - 1, results.getResults().getNumFound());
 
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractBasicDistributedZkTestBase.java b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractBasicDistributedZkTestBase.java
index edcd0a562fd..96d0c9952a3 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractBasicDistributedZkTestBase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractBasicDistributedZkTestBase.java
@@ -18,7 +18,6 @@ package org.apache.solr.cloud;
 
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -911,7 +910,7 @@ public abstract class AbstractBasicDistributedZkTestBase extends AbstractFullDis
     for (Slice slice : dColl.getActiveSlices()) {
       long sliceDocCount = -1;
       for (Replica rep : slice.getReplicas()) {
-        try (SolrClient one = getHttpSolrClient(rep.getCoreUrl())) {
+        try (SolrClient one = getHttpSolrClient(rep)) {
           SolrQuery query = new SolrQuery("*:*");
           query.setDistrib(false);
           QueryResponse resp = one.query(query);
@@ -1159,14 +1158,7 @@ public abstract class AbstractBasicDistributedZkTestBase extends AbstractFullDis
 
     CollectionAdminResponse res = new CollectionAdminResponse();
     if (client == null) {
-      final String baseUrl =
-          ((HttpSolrClient) clients.get(clientIndex))
-              .getBaseURL()
-              .substring(
-                  0,
-                  ((HttpSolrClient) clients.get(clientIndex)).getBaseURL().length()
-                      - DEFAULT_COLLECTION.length()
-                      - 1);
+      final String baseUrl = ((HttpSolrClient) clients.get(clientIndex)).getBaseURL();
 
       try (SolrClient aClient = createNewSolrClient("", baseUrl)) {
         res.setResponse(aClient.request(request));
@@ -1293,15 +1285,9 @@ public abstract class AbstractBasicDistributedZkTestBase extends AbstractFullDis
   }
 
   private Long getNumCommits(HttpSolrClient sourceClient) throws SolrServerException, IOException {
-    // construct the /admin/metrics URL
-    URL url = new URL(sourceClient.getBaseURL());
-    String path = url.getPath().substring(1);
-    String[] elements = path.split("/");
-    String collection = elements[elements.length - 1];
-    String urlString = url.toString();
-    urlString = urlString.substring(0, urlString.length() - collection.length() - 1);
+    String collection = sourceClient.getDefaultCollection();
     try (SolrClient client =
-        new HttpSolrClient.Builder(urlString)
+        new HttpSolrClient.Builder(sourceClient.getBaseURL())
             .withConnectionTimeout(15000, TimeUnit.MILLISECONDS)
             .withSocketTimeout(60000, TimeUnit.MILLISECONDS)
             .build()) {
@@ -1454,12 +1440,7 @@ public abstract class AbstractBasicDistributedZkTestBase extends AbstractFullDis
   private void testSearchByCollectionName() throws SolrServerException, IOException {
     log.info("### STARTING testSearchByCollectionName");
     SolrClient client = clients.get(0);
-    final String baseUrl =
-        ((HttpSolrClient) client)
-            .getBaseURL()
-            .substring(
-                0,
-                ((HttpSolrClient) client).getBaseURL().length() - DEFAULT_COLLECTION.length() - 1);
+    final String baseUrl = ((HttpSolrClient) client).getBaseURL();
 
     // the cores each have different names, but if we add the collection name to the url
     // we should get mapped to the right core
@@ -1473,12 +1454,7 @@ public abstract class AbstractBasicDistributedZkTestBase extends AbstractFullDis
   private void testUpdateByCollectionName() throws SolrServerException, IOException {
     log.info("### STARTING testUpdateByCollectionName");
     SolrClient client = clients.get(0);
-    final String baseUrl =
-        ((HttpSolrClient) client)
-            .getBaseURL()
-            .substring(
-                0,
-                ((HttpSolrClient) client).getBaseURL().length() - DEFAULT_COLLECTION.length() - 1);
+    final String baseUrl = ((HttpSolrClient) client).getBaseURL();
 
     // the cores each have different names, but if we add the collection name to the url
     // we should get mapped to the right core
@@ -1535,11 +1511,6 @@ public abstract class AbstractBasicDistributedZkTestBase extends AbstractFullDis
     IOUtils.close(collectionClients);
   }
 
-  private void createCollection(
-      String collection, List<SolrClient> collectionClients, String baseUrl, int num) {
-    createSolrCore(collection, collectionClients, baseUrl, num, null);
-  }
-
   private void createSolrCore(
       final String collection,
       List<SolrClient> collectionClients,
@@ -1713,16 +1684,25 @@ public abstract class AbstractBasicDistributedZkTestBase extends AbstractFullDis
   @Override
   protected SolrClient createNewSolrClient(String collection, String baseUrl) {
 
-    SolrClient client = getHttpSolrClient(baseUrl + "/" + collection);
+    SolrClient client = getHttpSolrClient(baseUrl, collection);
 
     return client;
   }
 
+  /**
+   * @param collection the name of a collection or core to set as the "default" on the created
+   *     client.
+   * @param baseUrl the "base" URL of a Solr node. Should <em>not</em> contain a collection or core
+   *     name.
+   * @param connectionTimeoutMillis the HTTP connection timeout in milliseconds
+   * @param socketTimeoutMillis the HTTP socket-read timeout in milliseconds
+   */
   protected SolrClient createNewSolrClient(
       String collection, String baseUrl, int connectionTimeoutMillis, int socketTimeoutMillis) {
 
     SolrClient client =
-        new HttpSolrClient.Builder(baseUrl + "/" + collection)
+        new HttpSolrClient.Builder(baseUrl)
+            .withDefaultCollection(collection)
             .withConnectionTimeout(connectionTimeoutMillis, TimeUnit.MILLISECONDS)
             .withSocketTimeout(socketTimeoutMillis, TimeUnit.MILLISECONDS)
             .build();
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 e2f2074873d..fbb71d02d1a 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
@@ -356,7 +356,9 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
     }
 
     controlClient =
-        new HttpSolrClient.Builder(controlJetty.getBaseUrl() + "/control_collection").build();
+        new HttpSolrClient.Builder(controlJetty.getBaseUrl().toString())
+            .withDefaultCollection("control_collection")
+            .build();
     if (sliceCount <= 0) {
       // for now, just create the cloud client for the control if we don't
       // create the normal cloud client.
@@ -2204,15 +2206,15 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
 
   protected SolrClient createNewSolrClient(String coreName, int port) {
     String baseUrl = buildUrl(port);
-    String url = baseUrl + (baseUrl.endsWith("/") ? "" : "/") + coreName;
-    return new HttpSolrClient.Builder(url)
+    return new HttpSolrClient.Builder(baseUrl)
+        .withDefaultCollection(coreName)
         .withConnectionTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
         .withSocketTimeout(60000, TimeUnit.MILLISECONDS)
         .build();
   }
 
   protected SolrClient createNewSolrClient(String collection, String baseUrl) {
-    return getHttpSolrClient(baseUrl + "/" + collection);
+    return getHttpSolrClient(baseUrl, collection);
   }
 
   protected String getBaseUrl(JettySolrRunner jetty) {
@@ -2343,7 +2345,15 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
         });
   }
 
-  public static String getUrlFromZk(ClusterState clusterState, String collection) {
+  /**
+   * Returns the base URL of a live Solr node hosting the specified collection
+   *
+   * <p>Note that the returned URL does not contain the collection name itself.
+   *
+   * @param clusterState used to identify which live nodes host the collection
+   * @param collection the name of the collection to search for
+   */
+  public static String getBaseUrlFromZk(ClusterState clusterState, String collection) {
     Map<String, Slice> slices = clusterState.getCollection(collection).getSlicesMap();
 
     if (slices == null) {
@@ -2359,7 +2369,7 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
         final ZkNodeProps node = shardEntry.getValue();
         final String nodeName = node.getStr(ZkStateReader.NODE_NAME_PROP);
         if (clusterState.liveNodesContain(nodeName)) {
-          return ZkCoreNodeProps.getCoreUrl(node.getStr(ZkStateReader.BASE_URL_PROP), collection);
+          return node.getStr(ZkStateReader.BASE_URL_PROP);
         }
       }
     }
@@ -2755,7 +2765,10 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
   }
 
   protected long getIndexVersion(Replica replica) throws IOException {
-    try (SolrClient client = new HttpSolrClient.Builder(replica.getCoreUrl()).build()) {
+    try (SolrClient client =
+        new HttpSolrClient.Builder(replica.getBaseUrl())
+            .withDefaultCollection(replica.getCoreName())
+            .build()) {
       ModifiableSolrParams params = new ModifiableSolrParams();
       params.set("qt", "/replication");
       params.set(ReplicationHandler.COMMAND, ReplicationHandler.CMD_SHOW_COMMITS);
@@ -2802,7 +2815,10 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
   }
 
   protected void logReplicationDetails(Replica replica, StringBuilder builder) throws IOException {
-    try (SolrClient client = new HttpSolrClient.Builder(replica.getCoreUrl()).build()) {
+    try (SolrClient client =
+        new HttpSolrClient.Builder(replica.getBaseUrl())
+            .withDefaultCollection(replica.getCoreName())
+            .build()) {
       ModifiableSolrParams params = new ModifiableSolrParams();
       params.set("qt", "/replication");
       params.set(ReplicationHandler.COMMAND, ReplicationHandler.CMD_DETAILS);
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractRecoveryZkTestBase.java b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractRecoveryZkTestBase.java
index c4975e388d2..3cb3339f48c 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractRecoveryZkTestBase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractRecoveryZkTestBase.java
@@ -139,7 +139,8 @@ public abstract class AbstractRecoveryZkTestBase extends SolrCloudTestCase {
     int i = 0;
     for (Replica replica : replicas) {
       try (var client =
-          new HttpSolrClient.Builder(replica.getCoreUrl())
+          new HttpSolrClient.Builder(replica.getBaseUrl())
+              .withDefaultCollection(replica.getCoreName())
               .withHttpClient(((CloudLegacySolrClient) cluster.getSolrClient()).getHttpClient())
               .build()) {
         numCounts[i] =
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractSyncSliceTestBase.java b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractSyncSliceTestBase.java
index 26690d699d8..b043c097f64 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractSyncSliceTestBase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractSyncSliceTestBase.java
@@ -28,9 +28,10 @@ import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.impl.HttpSolrClient;
-import org.apache.solr.client.solrj.request.QueryRequest;
+import org.apache.solr.client.solrj.request.GenericSolrRequest;
 import org.apache.solr.client.solrj.request.UpdateRequest;
 import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.cloud.Replica;
@@ -99,8 +100,8 @@ public abstract class AbstractSyncSliceTestBase extends AbstractFullDistribZkTes
     params.set("action", CollectionAction.SYNCSHARD.toString());
     params.set("collection", "collection1");
     params.set("shard", "shard1");
-    QueryRequest request = new QueryRequest(params);
-    request.setPath("/admin/collections");
+    final var request =
+        new GenericSolrRequest(SolrRequest.METHOD.GET, "/admin/collections", params);
 
     String baseUrl = shardToJetty.get(SHARD1).get(2).jetty.getBaseUrl().toString();
 
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractUnloadDistributedZkTestBase.java b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractUnloadDistributedZkTestBase.java
index 423a02d6f8f..2f77b69b27b 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractUnloadDistributedZkTestBase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractUnloadDistributedZkTestBase.java
@@ -84,6 +84,9 @@ public abstract class AbstractUnloadDistributedZkTestBase extends AbstractFullDi
     testUnloadShardAndCollection();
   }
 
+  /**
+   * @param url a Solr node base URL. Should <em>not</em> contain a core or collection name.
+   */
   private SolrClient newSolrClient(String url) {
     return new HttpSolrClient.Builder(url)
         .withConnectionTimeout(15000, TimeUnit.MILLISECONDS)
@@ -250,7 +253,8 @@ public abstract class AbstractUnloadDistributedZkTestBase extends AbstractFullDi
 
     Random random = random();
     if (random.nextBoolean()) {
-      try (SolrClient collectionClient = getHttpSolrClient(leaderProps.getCoreUrl())) {
+      try (SolrClient collectionClient =
+          getHttpSolrClient(leaderProps.getBaseUrl(), leaderProps.getCoreName())) {
         // lets try and use the solrj client to index and retrieve a couple
         // documents
         SolrInputDocument doc1 =
@@ -279,7 +283,8 @@ public abstract class AbstractUnloadDistributedZkTestBase extends AbstractFullDi
     TestInjection.skipIndexWriterCommitOnClose = true;
 
     try (SolrClient addClient =
-        new HttpSolrClient.Builder(jettys.get(2).getBaseUrl() + "/unloadcollection_shard1_replica3")
+        new HttpSolrClient.Builder(jettys.get(2).getBaseUrl().toString())
+            .withDefaultCollection("unloadcollection_shard1_replica3")
             .withConnectionTimeout(30000, TimeUnit.MILLISECONDS)
             .build()) {
 
@@ -319,7 +324,8 @@ public abstract class AbstractUnloadDistributedZkTestBase extends AbstractFullDi
     zkStateReader.getLeaderRetry("unloadcollection", "shard1", 15000);
 
     try (SolrClient addClient =
-        new HttpSolrClient.Builder(jettys.get(1).getBaseUrl() + "/unloadcollection_shard1_replica2")
+        new HttpSolrClient.Builder(jettys.get(1).getBaseUrl().toString())
+            .withDefaultCollection("unloadcollection_shard1_replica2")
             .withConnectionTimeout(30000, TimeUnit.MILLISECONDS)
             .withSocketTimeout(90000, TimeUnit.MILLISECONDS)
             .build()) {
@@ -383,7 +389,8 @@ public abstract class AbstractUnloadDistributedZkTestBase extends AbstractFullDi
     }
 
     try (SolrClient adminClient =
-        new HttpSolrClient.Builder(jettys.get(2).getBaseUrl() + "/unloadcollection_shard1_replica3")
+        new HttpSolrClient.Builder(jettys.get(2).getBaseUrl().toString())
+            .withDefaultCollection("unloadcollection_shard1_replica3")
             .withConnectionTimeout(15000, TimeUnit.MILLISECONDS)
             .withSocketTimeout(30000, TimeUnit.MILLISECONDS)
             .build()) {
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCloudBackupRestoreTestCase.java b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCloudBackupRestoreTestCase.java
index e27d7bdcc5d..3707d944656 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCloudBackupRestoreTestCase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCloudBackupRestoreTestCase.java
@@ -497,7 +497,8 @@ public abstract class AbstractCloudBackupRestoreTestCase extends SolrCloudTestCa
     for (Slice slice : docCollection.getActiveSlices()) {
       String shardName = slice.getName();
       try (var leaderClient =
-          new HttpSolrClient.Builder(slice.getLeader().getCoreUrl())
+          new HttpSolrClient.Builder(slice.getLeader().getBaseUrl())
+              .withDefaultCollection(slice.getLeader().getCoreName())
               .withHttpClient(((CloudLegacySolrClient) client).getHttpClient())
               .build()) {
         long docsInShard =
diff --git a/solr/test-framework/src/java/org/apache/solr/util/SolrJettyTestRule.java b/solr/test-framework/src/java/org/apache/solr/util/SolrJettyTestRule.java
index a7abba9c852..d0311f6e4f6 100644
--- a/solr/test-framework/src/java/org/apache/solr/util/SolrJettyTestRule.java
+++ b/solr/test-framework/src/java/org/apache/solr/util/SolrJettyTestRule.java
@@ -24,7 +24,6 @@ import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.impl.HttpSolrClient;
 import org.apache.solr.common.util.IOUtils;
-import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.embedded.JettyConfig;
 import org.apache.solr.embedded.JettySolrRunner;
@@ -119,8 +118,9 @@ public class SolrJettyTestRule extends SolrClientTestRule {
   }
 
   protected SolrClient newSolrClient(String collection) {
-    String url = getBaseUrl() + (StrUtils.isBlank(collection) ? "" : "/" + collection);
-    return new HttpSolrClient.Builder(url).build();
+    return new HttpSolrClient.Builder(getBaseUrl())
+        .withDefaultCollection(collection) // Properly handles when collection is 'null'
+        .build();
   }
 
   /** URL to Solr. */