diff --git a/solr/core/src/java/org/apache/solr/security/SimplePrincipal.java b/solr/core/src/java/org/apache/solr/security/SimplePrincipal.java index f6840db3758a..fb82f85c7368 100644 --- a/solr/core/src/java/org/apache/solr/security/SimplePrincipal.java +++ b/solr/core/src/java/org/apache/solr/security/SimplePrincipal.java @@ -18,37 +18,12 @@ package org.apache.solr.security; import java.security.Principal; -import java.util.Objects; /** A basic name-only {@link Principal}. */ -public final class SimplePrincipal implements Principal { - // TODO use a record. But javadoc tooling complained as it was confused (Java version issue?) - private final String name; - - public SimplePrincipal(String name) { - this.name = name; - } +public record SimplePrincipal(String name) implements Principal { @Override public String getName() { return name; } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || obj.getClass() != this.getClass()) return false; - var that = (SimplePrincipal) obj; - return Objects.equals(this.name, that.name); - } - - @Override - public int hashCode() { - return Objects.hash(name); - } - - @Override - public String toString() { - return "SimplePrincipal[" + "name=" + name + ']'; - } } 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 b6b7b67211c9..18e4d92ba4b6 100644 --- a/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java @@ -19,25 +19,16 @@ import static org.apache.solr.common.cloud.ZkStateReader.ALIASES; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.UnaryOperator; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.util.EntityUtils; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; import org.apache.solr.client.solrj.cloud.SolrCloudManager; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.impl.ClusterStateProvider; @@ -60,6 +51,10 @@ import org.apache.solr.embedded.JettySolrRunner; import org.apache.solr.util.TimeOut; import org.apache.zookeeper.KeeperException; +import org.eclipse.jetty.client.ContentResponse; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.StringRequestContent; +import org.eclipse.jetty.http.HttpMethod; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -67,8 +62,6 @@ public class AliasIntegrationTest extends SolrCloudTestCase { - private CloseableHttpClient httpClient; - @BeforeClass public static void setupCluster() throws Exception { configureCluster(2).addConfig("conf", configset("cloud-minimal")).configure(); @@ -78,9 +71,6 @@ public static void setupCluster() throws Exception { @Override public void setUp() throws Exception { super.setUp(); - - httpClient = - (CloseableHttpClient) ((CloudLegacySolrClient) cluster.getSolrClient()).getHttpClient(); } @After @@ -238,49 +228,53 @@ public void testProperties() throws Exception { public void testModifyPropertiesV2() throws Exception { final String aliasName = getSaferTestName(); ZkStateReader zkStateReader = createColectionsAndAlias(aliasName); - final String baseUrl = cluster.getRandomJetty(random()).getBaseURLV2().toString(); + final JettySolrRunner runner = cluster.getRandomJetty(random()); + final String baseUrl = runner.getBaseURLV2().toString(); + final HttpClient httpClient = runner.getSolrClient().getHttpClient(); String aliasApi = String.format(Locale.ENGLISH, "/aliases/%s/properties", aliasName); - HttpPut withoutBody = new HttpPut(baseUrl + aliasApi); - assertEquals(400, httpClient.execute(withoutBody).getStatusLine().getStatusCode()); - - HttpPut update = new HttpPut(baseUrl + aliasApi); - update.setEntity( - new StringEntity( - "{\n" - + " \"properties\":\n" - + " {\n" - + " \"foo\": \"baz\",\n" - + " \"bar\": \"bam\"\n" - + " }\n" - + "}", - ContentType.APPLICATION_JSON)); - assertSuccess(update); + assertEquals( + 400, httpClient.newRequest(baseUrl + aliasApi).method(HttpMethod.PUT).send().getStatus()); + + String body = + "{\n" + + " \"properties\":\n" + + " {\n" + + " \"foo\": \"baz\",\n" + + " \"bar\": \"bam\"\n" + + " }\n" + + "}"; + assertSuccess( + httpClient + .newRequest(baseUrl + aliasApi) + .method(HttpMethod.PUT) + .body(new StringRequestContent("application/json", body, StandardCharsets.UTF_8)) + .send()); checkFooAndBarMeta(aliasName, zkStateReader, "baz", "bam"); String aliasPropertyApi = String.format(Locale.ENGLISH, "/aliases/%s/properties/%s", aliasName, "foo"); - HttpPut updateByProperty = new HttpPut(baseUrl + aliasPropertyApi); - updateByProperty.setEntity( - new StringEntity("{ \"value\": \"zab\" }", ContentType.APPLICATION_JSON)); - assertSuccess(updateByProperty); + assertSuccess( + httpClient + .newRequest(baseUrl + aliasPropertyApi) + .method(HttpMethod.PUT) + .body( + new StringRequestContent( + "application/json", "{ \"value\": \"zab\" }", StandardCharsets.UTF_8)) + .send()); checkFooAndBarMeta(aliasName, zkStateReader, "zab", "bam"); - HttpDelete deleteByProperty = new HttpDelete(baseUrl + aliasPropertyApi); - assertSuccess(deleteByProperty); + assertSuccess( + httpClient.newRequest(baseUrl + aliasPropertyApi).method(HttpMethod.DELETE).send()); checkFooAndBarMeta(aliasName, zkStateReader, null, "bam"); - HttpPut deleteByEmptyValue = new HttpPut(baseUrl + aliasApi); - deleteByEmptyValue.setEntity( - new StringEntity( - "{\n" - + " \"properties\":\n" - + " {\n" - + " \"bar\": \"\"\n" - + " }\n" - + "}", - ContentType.APPLICATION_JSON)); - assertSuccess(deleteByEmptyValue); + body = "{ \"properties\": { \"bar\": \"\" } }"; + assertSuccess( + httpClient + .newRequest(baseUrl + aliasApi) + .method(HttpMethod.PUT) + .body(new StringRequestContent("application/json", body, StandardCharsets.UTF_8)) + .send()); checkFooAndBarMeta(aliasName, zkStateReader, null, null); } @@ -289,29 +283,29 @@ public void testModifyPropertiesV1() throws Exception { // note we don't use TZ in this test, thus it's UTC final String aliasName = getSaferTestName(); ZkStateReader zkStateReader = createColectionsAndAlias(aliasName); - final String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); - HttpGet get = - new HttpGet( - baseUrl - + "/admin/collections?action=ALIASPROP" - + "&wt=xml" - + "&name=" - + aliasName - + "&property.foo=baz" - + "&property.bar=bam"); - assertSuccess(get); + final JettySolrRunner runner = cluster.getRandomJetty(random()); + final String baseUrl = runner.getBaseUrl().toString(); + final HttpClient httpClient = runner.getSolrClient().getHttpClient(); + String url = + baseUrl + + "/admin/collections?action=ALIASPROP" + + "&wt=xml" + + "&name=" + + aliasName + + "&property.foo=baz" + + "&property.bar=bam"; + assertSuccess(httpClient.GET(url)); checkFooAndBarMeta(aliasName, zkStateReader, "baz", "bam"); - HttpGet remove = - new HttpGet( - baseUrl - + "/admin/collections?action=ALIASPROP" - + "&wt=xml" - + "&name=" - + aliasName - + "&property.foo=" - + "&property.bar=bar"); - assertSuccess(remove); + url = + baseUrl + + "/admin/collections?action=ALIASPROP" + + "&wt=xml" + + "&name=" + + aliasName + + "&property.foo=" + + "&property.bar=bar"; + assertSuccess(httpClient.GET(url)); checkFooAndBarMeta(aliasName, zkStateReader, null, "bar"); } @@ -508,12 +502,10 @@ private ZkStateReader createColectionsAndAlias(String aliasName) return zkStateReader; } - private void assertSuccess(HttpUriRequest msg) throws IOException { - try (CloseableHttpResponse response = httpClient.execute(msg)) { - if (200 != response.getStatusLine().getStatusCode()) { - System.err.println(EntityUtils.toString(response.getEntity())); - fail("Unexpected status: " + response.getStatusLine()); - } + private void assertSuccess(ContentResponse response) { + if (200 != response.getStatus()) { + System.err.println(response.getContentAsString()); + fail("Unexpected status: " + response.getStatus()); } } diff --git a/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java b/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java index b1144d5caff1..7fb0d8ddb4fb 100644 --- a/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java @@ -17,8 +17,6 @@ package org.apache.solr.cloud; -import static java.nio.charset.StandardCharsets.UTF_8; - import java.io.IOException; import java.lang.invoke.MethodHandles; import java.util.ArrayList; @@ -27,14 +25,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import org.apache.http.HttpEntity; -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.entity.ContentType; -import org.apache.http.util.EntityUtils; import org.apache.solr.client.api.model.BalanceReplicasRequestBody; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.common.cloud.DocCollection; @@ -42,6 +33,8 @@ import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.util.Utils; +import org.eclipse.jetty.client.BytesRequestContent; +import org.eclipse.jetty.client.HttpClient; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -99,8 +92,7 @@ public void testAllNodes() throws Exception { DocCollection collection = cloudClient.getClusterState().getCollection(coll); log.debug("### Before balancing: {}", collection); - postDataAndGetResponse( - cluster.getSolrClient(), "/api/cluster/replicas/balance", SimpleOrderedMap.of()); + postDataAndGetResponse("/api/cluster/replicas/balance", SimpleOrderedMap.of()); collection = cloudClient.getClusterState().getCollectionOrNull(coll, false); log.debug("### After balancing: {}", collection); @@ -146,7 +138,6 @@ public void testSomeNodes() throws Exception { log.debug("### Before balancing: {}", collection); postDataAndGetResponse( - cluster.getSolrClient(), "/api/cluster/replicas/balance", Utils.getReflectWriter( new BalanceReplicasRequestBody(new HashSet<>(l.subList(1, 4)), true, null))); @@ -162,31 +153,24 @@ public void testSomeNodes() throws Exception { "A non-balanced node gained replicas during balancing", replicaNodes.contains(l.get(4))); } - public Map postDataAndGetResponse(CloudSolrClient cloudClient, String uri, Object body) - throws IOException { - HttpEntityEnclosingRequestBase httpRequest = null; - HttpEntity entity; - String response = null; - Map m = null; + public Map postDataAndGetResponse(String uri, Object jsonBody) throws IOException { + String rspStr = null; uri = cluster.getJettySolrRunners().get(0).getBaseUrl().toString().replace("/solr", "") + uri; + HttpClient httpClient = cluster.getRandomJetty(random()).getSolrClient().getHttpClient(); try { - httpRequest = new HttpPost(uri); - - httpRequest.setEntity(new ByteArrayEntity(Utils.toJSON(body), ContentType.APPLICATION_JSON)); - httpRequest.setHeader("Accept", "application/json"); - entity = - ((CloudLegacySolrClient) cloudClient).getHttpClient().execute(httpRequest).getEntity(); - try { - response = EntityUtils.toString(entity, UTF_8); - m = (Map) Utils.fromJSONString(response); - } catch (JSONParser.ParseException e) { - log.error("err response: {}", response); - throw new AssertionError(e); - } - } finally { - httpRequest.releaseConnection(); + var rsp = + httpClient + .POST(uri) + .body(new BytesRequestContent("application/json", Utils.toJSON(jsonBody))) + .send(); + rspStr = rsp.getContentAsString(); + return (Map) Utils.fromJSONString(rspStr); + } catch (JSONParser.ParseException e) { + log.error("err response: {}", rspStr); + throw new AssertionError(e); + } catch (Exception e) { + throw new IOException(e); } - return m; } } diff --git a/solr/core/src/test/org/apache/solr/cloud/CreateRoutedAliasTest.java b/solr/core/src/test/org/apache/solr/cloud/CreateRoutedAliasTest.java index aa2c2e1e8fee..f81ed5de9334 100644 --- a/solr/core/src/test/org/apache/solr/cloud/CreateRoutedAliasTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/CreateRoutedAliasTest.java @@ -20,6 +20,7 @@ import static org.apache.solr.client.solrj.request.RoutedAliasTypes.TIME; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; @@ -27,17 +28,8 @@ import java.util.List; import java.util.Map; import java.util.TimeZone; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.util.EntityUtils; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.response.CollectionAdminResponse; @@ -49,6 +41,8 @@ import org.apache.solr.common.cloud.Replica; import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.util.DateMathParser; +import org.eclipse.jetty.client.Request; +import org.eclipse.jetty.client.StringRequestContent; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -92,7 +86,8 @@ public void testV2() throws Exception { String createNode = cluster.getRandomJetty(random()).getNodeName(); - final String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); + final var jetty = cluster.getRandomJetty(random()); + final String baseUrl = jetty.getBaseUrl().toString(); // TODO fix Solr test infra so that this /____v2/ becomes /api/ final String aliasJson = "{\n" @@ -127,9 +122,12 @@ public void testV2() throws Exception { + " }\n" + " }\n" + " }\n"; - HttpPost post = new HttpPost(baseUrl + "/____v2/aliases"); - post.setEntity(new StringEntity(aliasJson, ContentType.APPLICATION_JSON)); - assertSuccess(post); + assertSuccess( + jetty + .getSolrClient() + .getHttpClient() + .POST(baseUrl + "/____v2/aliases") + .body(new StringRequestContent("application/json", aliasJson, StandardCharsets.UTF_8))); Date startDate = DateMathParser.parseMath(new Date(), "NOW/DAY"); String initialCollectionName = @@ -249,32 +247,38 @@ public void testUpdateRoutedAliasDoesNotChangeCollectionList() throws Exception public void testCantAddRoutingToNonRouted() throws Exception { String aliasName = getSaferTestName() + "Alias"; createCollection(); - final String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); - HttpGet get = - new HttpGet( - baseUrl - + "/admin/collections?action=CREATEALIAS" - + "&wt=xml" - + "&name=" - + aliasName - + "&collections=" - + getSaferTestName()); - assertSuccess(get); - - HttpGet get2 = - new HttpGet( - baseUrl - + "/admin/collections?action=CREATEALIAS" - + "&wt=json" - + "&name=" - + aliasName - + "&router.field=evt_dt" - + "&router.name=time" - + "&router.start=2018-01-15T00:00:00Z" - + "&router.interval=%2B30MINUTE" - + "&create-collection.collection.configName=_default" - + "&create-collection.numShards=1"); - assertFailure(get2, "Cannot add routing parameters to existing non-routed Alias"); + final var jetty = cluster.getRandomJetty(random()); + final String baseUrl = jetty.getBaseUrl().toString(); + assertSuccess( + jetty + .getSolrClient() + .getHttpClient() + .newRequest( + baseUrl + + "/admin/collections?action=CREATEALIAS" + + "&wt=xml" + + "&name=" + + aliasName + + "&collections=" + + getSaferTestName())); + + assertFailure( + jetty + .getSolrClient() + .getHttpClient() + .newRequest( + baseUrl + + "/admin/collections?action=CREATEALIAS" + + "&wt=json" + + "&name=" + + aliasName + + "&router.field=evt_dt" + + "&router.name=time" + + "&router.start=2018-01-15T00:00:00Z" + + "&router.interval=%2B30MINUTE" + + "&create-collection.collection.configName=_default" + + "&create-collection.numShards=1"), + "Cannot add routing parameters to existing non-routed Alias"); } private void createCollection() throws SolrServerException, IOException { @@ -287,24 +291,27 @@ private void createCollection() throws SolrServerException, IOException { } private void createTRAv1(String aliasName, Instant start) throws IOException { - final String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); - HttpGet get = - new HttpGet( - baseUrl - + "/admin/collections?action=CREATEALIAS" - + "&wt=xml" - + "&name=" - + aliasName - + "&router.field=evt_dt" - + "&router.name=time" - + "&router.start=" - + start - + "&router.interval=%2B30MINUTE" - + "&create-collection.collection.configName=_default" - + "&create-collection.router.field=foo_s" - + "&create-collection.numShards=1" - + "&create-collection.replicationFactor=2"); - assertSuccess(get); + final var jetty = cluster.getRandomJetty(random()); + final String baseUrl = jetty.getBaseUrl().toString(); + assertSuccess( + jetty + .getSolrClient() + .getHttpClient() + .newRequest( + baseUrl + + "/admin/collections?action=CREATEALIAS" + + "&wt=xml" + + "&name=" + + aliasName + + "&router.field=evt_dt" + + "&router.name=time" + + "&router.start=" + + start + + "&router.interval=%2B30MINUTE" + + "&create-collection.collection.configName=_default" + + "&create-collection.router.field=foo_s" + + "&create-collection.numShards=1" + + "&create-collection.replicationFactor=2")); } // TZ should not affect the first collection name if absolute date given for start @@ -345,171 +352,195 @@ public void testCollectionNamesMustBeAbsent() throws Exception { ZkStateReader zkStateReader = cluster.getZkStateReader(); zkStateReader.createClusterStateWatchersAndUpdate(); - final String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); - HttpGet get = - new HttpGet( - baseUrl - + "/admin/collections?action=CREATEALIAS" - + "&wt=json" - + "&name=" - + getTestName() - + "&collections=collection1meta,collection2meta" - + "&router.field=evt_dt" - + "&router.name=time" - + "&router.start=2018-01-15T00:00:00Z" - + "&router.interval=%2B30MINUTE" - + "&create-collection.collection.configName=_default" - + "&create-collection.numShards=1"); - assertFailure(get, "Collections cannot be specified"); + final var jetty = cluster.getRandomJetty(random()); + final String baseUrl = jetty.getBaseUrl().toString(); + assertFailure( + jetty + .getSolrClient() + .getHttpClient() + .newRequest( + baseUrl + + "/admin/collections?action=CREATEALIAS" + + "&wt=json" + + "&name=" + + getTestName() + + "&collections=collection1meta,collection2meta" + + "&router.field=evt_dt" + + "&router.name=time" + + "&router.start=2018-01-15T00:00:00Z" + + "&router.interval=%2B30MINUTE" + + "&create-collection.collection.configName=_default" + + "&create-collection.numShards=1"), + "Collections cannot be specified"); } @Test public void testAliasNameMustBeValid() throws Exception { - final String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); - HttpGet get = - new HttpGet( - baseUrl - + "/admin/collections?action=CREATEALIAS" - + "&wt=json" - + "&name=735741!45" - + // ! not allowed - "&router.field=evt_dt" - + "&router.name=time" - + "&router.start=2018-01-15T00:00:00Z" - + "&router.interval=%2B30MINUTE" - + "&create-collection.collection.configName=_default" - + "&create-collection.numShards=1"); - assertFailure(get, "Invalid alias"); + final var jetty = cluster.getRandomJetty(random()); + final String baseUrl = jetty.getBaseUrl().toString(); + assertFailure( + jetty + .getSolrClient() + .getHttpClient() + .newRequest( + baseUrl + + "/admin/collections?action=CREATEALIAS" + + "&wt=json" + + "&name=735741!45" // ! not allowed + + "&router.field=evt_dt" + + "&router.name=time" + + "&router.start=2018-01-15T00:00:00Z" + + "&router.interval=%2B30MINUTE" + + "&create-collection.collection.configName=_default" + + "&create-collection.numShards=1"), + "Invalid alias"); } @Test public void testRandomRouterNameFails() throws Exception { final String aliasName = getSaferTestName(); - final String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); - HttpGet get = - new HttpGet( - baseUrl - + "/admin/collections?action=CREATEALIAS" - + "&wt=json" - + "&name=" - + aliasName - + "&router.field=evt_dt" - + "&router.name=tiafasme" - + // bad - "&router.start=2018-01-15T00:00:00Z" - + "&router.interval=%2B30MINUTE" - + "&create-collection.collection.configName=_default" - + "&create-collection.numShards=1"); - assertFailure(get, " is not in supported types, "); + final var jetty = cluster.getRandomJetty(random()); + final String baseUrl = jetty.getBaseUrl().toString(); + assertFailure( + jetty + .getSolrClient() + .getHttpClient() + .newRequest( + baseUrl + + "/admin/collections?action=CREATEALIAS" + + "&wt=json" + + "&name=" + + aliasName + + "&router.field=evt_dt" + + "&router.name=tiafasme" // bad + + "&router.start=2018-01-15T00:00:00Z" + + "&router.interval=%2B30MINUTE" + + "&create-collection.collection.configName=_default" + + "&create-collection.numShards=1"), + " is not in supported types, "); } @Test public void testTimeStampWithMsFails() throws Exception { final String aliasName = getSaferTestName(); - final String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); - HttpGet get = - new HttpGet( - baseUrl - + "/admin/collections?action=CREATEALIAS" - + "&wt=json" - + "&name=" - + aliasName - + "&router.field=evt_dt" - + "&router.name=time" - + "&router.start=2018-01-15T00:00:00.001Z" - + // bad: no milliseconds permitted - "&router.interval=%2B30MINUTE" - + "&create-collection.collection.configName=_default" - + "&create-collection.numShards=1"); - assertFailure(get, "Date or date math for start time includes milliseconds"); + final var jetty = cluster.getRandomJetty(random()); + final String baseUrl = jetty.getBaseUrl().toString(); + assertFailure( + jetty + .getSolrClient() + .getHttpClient() + .newRequest( + baseUrl + + "/admin/collections?action=CREATEALIAS" + + "&wt=json" + + "&name=" + + aliasName + + "&router.field=evt_dt" + + "&router.name=time" + + "&router.start=2018-01-15T00:00:00.001Z" // bad: no milliseconds permitted + + "&router.interval=%2B30MINUTE" + + "&create-collection.collection.configName=_default" + + "&create-collection.numShards=1"), + "Date or date math for start time includes milliseconds"); } @Test public void testBadDateMathIntervalFails() throws Exception { final String aliasName = getSaferTestName(); - final String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); - HttpGet get = - new HttpGet( - baseUrl - + "/admin/collections?action=CREATEALIAS" - + "&wt=json" - + "&name=" - + aliasName - + "&router.field=evt_dt" - + "&router.name=time" - + "&router.start=2018-01-15T00:00:00Z" - + "&router.interval=%2B30MINUTEx" - + // bad; trailing 'x' - "&router.maxFutureMs=60000" - + "&create-collection.collection.configName=_default" - + "&create-collection.numShards=1"); - assertFailure(get, "Unit not recognized"); + final var jetty = cluster.getRandomJetty(random()); + final String baseUrl = jetty.getBaseUrl().toString(); + assertFailure( + jetty + .getSolrClient() + .getHttpClient() + .newRequest( + baseUrl + + "/admin/collections?action=CREATEALIAS" + + "&wt=json" + + "&name=" + + aliasName + + "&router.field=evt_dt" + + "&router.name=time" + + "&router.start=2018-01-15T00:00:00Z" + + "&router.interval=%2B30MINUTEx" // bad; trailing 'x' + + "&router.maxFutureMs=60000" + + "&create-collection.collection.configName=_default" + + "&create-collection.numShards=1"), + "Unit not recognized"); } @Test public void testNegativeFutureFails() throws Exception { final String aliasName = getSaferTestName(); - final String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); - HttpGet get = - new HttpGet( - baseUrl - + "/admin/collections?action=CREATEALIAS" - + "&wt=json" - + "&name=" - + aliasName - + "&router.field=evt_dt" - + "&router.name=time" - + "&router.start=2018-01-15T00:00:00Z" - + "&router.interval=%2B30MINUTE" - + "&router.maxFutureMs=-60000" - + // bad: negative - "&create-collection.collection.configName=_default" - + "&create-collection.numShards=1"); - assertFailure(get, "must be >= 0"); + final var jetty = cluster.getRandomJetty(random()); + final String baseUrl = jetty.getBaseUrl().toString(); + assertFailure( + jetty + .getSolrClient() + .getHttpClient() + .newRequest( + baseUrl + + "/admin/collections?action=CREATEALIAS" + + "&wt=json" + + "&name=" + + aliasName + + "&router.field=evt_dt" + + "&router.name=time" + + "&router.start=2018-01-15T00:00:00Z" + + "&router.interval=%2B30MINUTE" + + "&router.maxFutureMs=-60000" // bad: negative + + "&create-collection.collection.configName=_default" + + "&create-collection.numShards=1"), + "must be >= 0"); } @Test public void testUnParseableFutureFails() throws Exception { final String aliasName = "testAlias"; - final String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); - HttpGet get = - new HttpGet( - baseUrl - + "/admin/collections?action=CREATEALIAS" - + "&wt=json" - + "&name=" - + aliasName - + "&router.field=evt_dt" - + "&router.name=time" - + "&router.start=2018-01-15T00:00:00Z" - + "&router.interval=%2B30MINUTE" - + "&router.maxFutureMs=SixtyThousandMilliseconds" - + // bad - "&create-collection.collection.configName=_default" - + "&create-collection.numShards=1"); - assertFailure(get, "SixtyThousandMilliseconds"); // TODO improve SolrParams.getLong + final var jetty = cluster.getRandomJetty(random()); + final String baseUrl = jetty.getBaseUrl().toString(); + assertFailure( + jetty + .getSolrClient() + .getHttpClient() + .newRequest( + baseUrl + + "/admin/collections?action=CREATEALIAS" + + "&wt=json" + + "&name=" + + aliasName + + "&router.field=evt_dt" + + "&router.name=time" + + "&router.start=2018-01-15T00:00:00Z" + + "&router.interval=%2B30MINUTE" + + "&router.maxFutureMs=SixtyThousandMilliseconds" // bad + + "&create-collection.collection.configName=_default" + + "&create-collection.numShards=1"), + "SixtyThousandMilliseconds"); // TODO improve SolrParams.getLong } - private void assertSuccess(HttpUriRequest msg) throws IOException { - CloseableHttpClient httpClient = - (CloseableHttpClient) ((CloudLegacySolrClient) solrClient).getHttpClient(); - try (CloseableHttpResponse response = httpClient.execute(msg)) { - if (200 != response.getStatusLine().getStatusCode()) { - System.err.println(EntityUtils.toString(response.getEntity())); - fail("Unexpected status: " + response.getStatusLine()); + private void assertSuccess(Request req) throws IOException { + try { + var response = req.send(); + if (200 != response.getStatus()) { + System.err.println(response.getContentAsString()); + assertEquals("Unexpected status: " + response.getStatus(), 200, response.getStatus()); } + } catch (Exception e) { + throw new RuntimeException(e); } } - private void assertFailure(HttpUriRequest msg, String expectedErrorSubstring) throws IOException { - CloseableHttpClient httpClient = - (CloseableHttpClient) ((CloudLegacySolrClient) solrClient).getHttpClient(); - try (CloseableHttpResponse response = httpClient.execute(msg)) { - assertEquals(400, response.getStatusLine().getStatusCode()); - String entity = EntityUtils.toString(response.getEntity()); + private void assertFailure(Request req, String expectedErrorSubstring) throws IOException { + try { + var response = req.send(); + assertEquals(400, response.getStatus()); + String entity = response.getContentAsString(); assertTrue( "Didn't find expected error string within response: " + entity, entity.contains(expectedErrorSubstring)); + } catch (Exception e) { + throw new RuntimeException(e); } } 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 6068d7880455..c271c88adb7a 100644 --- a/solr/core/src/test/org/apache/solr/cloud/HttpPartitionOnCommitTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/HttpPartitionOnCommitTest.java @@ -16,10 +16,10 @@ */ package org.apache.solr.cloud; +import java.io.IOException; import java.lang.invoke.MethodHandles; import java.nio.file.Path; import java.util.List; -import org.apache.http.NoHttpResponseException; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.common.SolrException; import org.apache.solr.common.cloud.Replica; @@ -199,7 +199,7 @@ protected void sendCommitWithRetry(Replica replica) throws Exception { } } catch (Exception exc) { Throwable rootCause = SolrException.getRootCause(exc); - if (rootCause instanceof NoHttpResponseException) { + if (rootCause instanceof IOException) { log.warn( "No HTTP response from sending commit request to {}; will re-try after waiting 3 seconds", replicaCoreUrl); diff --git a/solr/core/src/test/org/apache/solr/cloud/MigrateReplicasTest.java b/solr/core/src/test/org/apache/solr/cloud/MigrateReplicasTest.java index 09e81e6107d0..1d4d431d6df2 100644 --- a/solr/core/src/test/org/apache/solr/cloud/MigrateReplicasTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/MigrateReplicasTest.java @@ -17,8 +17,6 @@ package org.apache.solr.cloud; -import static java.nio.charset.StandardCharsets.UTF_8; - import java.io.IOException; import java.lang.invoke.MethodHandles; import java.util.ArrayList; @@ -28,15 +26,8 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.http.HttpEntity; -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.entity.ContentType; -import org.apache.http.util.EntityUtils; import org.apache.solr.client.api.model.MigrateReplicasRequestBody; import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.CoreAdminRequest; @@ -51,6 +42,8 @@ import org.apache.solr.core.SolrInfoBean; import org.apache.solr.embedded.JettySolrRunner; import org.apache.solr.util.SolrMetricTestUtils; +import org.eclipse.jetty.client.BytesRequestContent; +import org.eclipse.jetty.client.HttpClient; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -123,7 +116,6 @@ public void test() throws Exception { log.info("excluded_node : {} ", emptyNode); Map response = callMigrateReplicas( - cloudClient, new MigrateReplicasRequestBody( Set.of(nodeToBeDecommissioned), Set.of(emptyNode), true, null)); assertEquals( @@ -151,7 +143,6 @@ public void test() throws Exception { // let's do it back - this time wait for recoveries response = callMigrateReplicas( - cloudClient, new MigrateReplicasRequestBody( Set.of(emptyNode), Set.of(nodeToBeDecommissioned), true, null)); assertEquals( @@ -259,7 +250,6 @@ public void testWithNoTarget() throws Exception { log.info("### Before decommission: {}", initialCollection); Map response = callMigrateReplicas( - cloudClient, new MigrateReplicasRequestBody( new HashSet<>(nodesToBeDecommissioned), Set.of(), true, null)); assertEquals( @@ -304,8 +294,7 @@ public void testFailOnSingleNode() throws Exception { String liveNode = cloudClient.getClusterState().getLiveNodes().iterator().next(); Map response = - callMigrateReplicas( - cloudClient, new MigrateReplicasRequestBody(Set.of(liveNode), Set.of(), true, null)); + callMigrateReplicas(new MigrateReplicasRequestBody(Set.of(liveNode), Set.of(), true, null)); assertNotNull( "No error in response, when the request should have failed", response.get("error")); assertEquals( @@ -314,37 +303,29 @@ public void testFailOnSingleNode() throws Exception { ((Map) response.get("error")).get("msg")); } - public Map callMigrateReplicas(CloudSolrClient cloudClient, MigrateReplicasRequestBody body) - throws IOException { - HttpEntityEnclosingRequestBase httpRequest = null; - HttpEntity entity; - String response = null; - Map r = null; - - String uri = - cluster.getJettySolrRunners().get(0).getBaseURLV2().toString() - + "/cluster/replicas/migrate"; + public Map callMigrateReplicas(MigrateReplicasRequestBody body) throws IOException { + String rspStr = null; + var jetty = cluster.getRandomJetty(random()); + HttpClient httpClient = jetty.getSolrClient().getHttpClient(); try { - httpRequest = new HttpPost(uri); - - httpRequest.setEntity( - new ByteArrayEntity( - Utils.toJSON(Utils.getReflectWriter(body)), ContentType.APPLICATION_JSON)); - httpRequest.setHeader("Accept", "application/json"); - entity = - ((CloudLegacySolrClient) cloudClient).getHttpClient().execute(httpRequest).getEntity(); - try { - response = EntityUtils.toString(entity, UTF_8); - r = (Map) Utils.fromJSONString(response); - assertNotNull("No response given from MigrateReplicas API", r); - assertNotNull("No responseHeader given from MigrateReplicas API", r.get("responseHeader")); - } catch (JSONParser.ParseException e) { - log.error("err response: {}", response); - throw new AssertionError(e); - } - } finally { - httpRequest.releaseConnection(); + var rsp = + httpClient + .POST(jetty.getBaseURLV2() + "/cluster/replicas/migrate") + .body( + new BytesRequestContent( + "application/json", Utils.toJSON(Utils.getReflectWriter(body)))) + .send(); + rspStr = rsp.getContentAsString(); + var rspMap = (Map) Utils.fromJSONString(rspStr); + assertNotNull("No response given from MigrateReplicas API", rspMap); + assertNotNull( + "No responseHeader given from MigrateReplicas API", rspMap.get("responseHeader")); + return rspMap; + } catch (JSONParser.ParseException e) { + log.error("err response: {}", rspStr); + throw new AssertionError(e); + } catch (Exception e) { + throw new IOException(e); } - return r; } } diff --git a/solr/core/src/test/org/apache/solr/cloud/OverseerCollectionConfigSetProcessorTest.java b/solr/core/src/test/org/apache/solr/cloud/OverseerCollectionConfigSetProcessorTest.java index 9b5c8b302522..371568db8697 100644 --- a/solr/core/src/test/org/apache/solr/cloud/OverseerCollectionConfigSetProcessorTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/OverseerCollectionConfigSetProcessorTest.java @@ -48,7 +48,6 @@ import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import java.util.stream.Collectors; -import org.apache.http.client.HttpClient; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.SolrResponse; import org.apache.solr.client.solrj.cloud.DistribStateManager; @@ -131,7 +130,6 @@ public class OverseerCollectionConfigSetProcessorTest extends SolrTestCaseJ4 { private static DistribStateManager distribStateManagerMock; private static CoreContainer coreContainerMock; private static UpdateShardHandler updateShardHandlerMock; - private static HttpClient httpClientMock; @SuppressWarnings("rawtypes") private final PlacementPluginFactory placementPluginFactory = new SimplePlacementFactory(); @@ -258,7 +256,6 @@ public static void setUpOnce() { distribStateManagerMock = mock(DistribStateManager.class); coreContainerMock = mock(CoreContainer.class); updateShardHandlerMock = mock(UpdateShardHandler.class); - httpClientMock = mock(HttpClient.class); solrMetricsContextMock = mock(SolrMetricsContext.class); } @@ -285,7 +282,6 @@ public static void tearDownOnce() { distribStateManagerMock = null; coreContainerMock = null; updateShardHandlerMock = null; - httpClientMock = null; solrMetricsContextMock = null; } @@ -318,7 +314,6 @@ public void setUp() throws Exception { reset(distribStateManagerMock); reset(coreContainerMock); reset(updateShardHandlerMock); - reset(httpClientMock); reset(solrMetricsContextMock); zkClientData.clear(); diff --git a/solr/core/src/test/org/apache/solr/cloud/TestAuthenticationFramework.java b/solr/core/src/test/org/apache/solr/cloud/TestAuthenticationFramework.java index a971102b67fd..6a90af12d04f 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestAuthenticationFramework.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestAuthenticationFramework.java @@ -19,12 +19,9 @@ import jakarta.servlet.FilterChain; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; import java.lang.invoke.MethodHandles; import java.util.Map; -import org.apache.http.HttpRequestInterceptor; import org.apache.solr.client.solrj.RemoteSolrException; -import org.apache.solr.client.solrj.apache.HttpClientUtil; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.SolrQuery; @@ -127,7 +124,6 @@ public static class MockAuthenticationPlugin extends AuthenticationPlugin implements HttpClientBuilderPlugin { public static String expectedUsername; public static String expectedPassword; - private HttpRequestInterceptor interceptor; @Override public void init(Map pluginConfig) {} @@ -153,11 +149,5 @@ public boolean doAuthenticate( return false; } } - - @Override - public void close() throws IOException { - HttpClientUtil.removeRequestInterceptor(interceptor); - super.close(); - } } } diff --git a/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java b/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java index c30bcabed916..d0e6a70e66d7 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java @@ -55,14 +55,6 @@ import java.util.zip.ZipOutputStream; import javax.script.ScriptEngineManager; import org.apache.commons.io.file.PathUtils; -import org.apache.http.HttpEntity; -import org.apache.http.auth.BasicUserPrincipal; -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.message.BasicHeader; -import org.apache.http.util.EntityUtils; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.api.AnnotatedApi; import org.apache.solr.client.solrj.RemoteSolrException; @@ -70,7 +62,6 @@ import org.apache.solr.client.solrj.SolrRequest.METHOD; import org.apache.solr.client.solrj.SolrRequest.SolrRequestType; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.request.ConfigSetAdminRequest; import org.apache.solr.client.solrj.request.ConfigSetAdminRequest.Create; @@ -95,15 +86,21 @@ import org.apache.solr.core.ConfigSetProperties; import org.apache.solr.core.ConfigSetService; import org.apache.solr.core.TestSolrConfigHandler; +import org.apache.solr.embedded.JettySolrRunner; import org.apache.solr.handler.admin.api.ModifyBasicAuthConfigAPI; import org.apache.solr.security.AuthorizationContext; import org.apache.solr.security.AuthorizationPlugin; import org.apache.solr.security.AuthorizationResponse; import org.apache.solr.security.BasicAuthPlugin; +import org.apache.solr.security.SimplePrincipal; import org.apache.solr.util.ExternalPaths; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.data.Stat; +import org.eclipse.jetty.client.ByteBufferRequestContent; +import org.eclipse.jetty.client.ContentResponse; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.http.HttpMethod; import org.junit.After; import org.junit.Assume; import org.junit.BeforeClass; @@ -332,25 +329,19 @@ private void verifyProperties( @Test public void testUploadErrors() throws Exception { - final SolrClient solrClient = - getHttpSolrClient(cluster.getJettySolrRunners().get(0).getBaseUrl().toString()); - ByteBuffer emptyData = ByteBuffer.allocate(0); ignoreException("The configuration name should be provided"); // Checking error when no configuration name is specified in request Map map = postDataAndGetResponse( - cluster.getSolrClient(), - cluster.getJettySolrRunners().get(0).getBaseUrl().toString() - + "/admin/configs?action=UPLOAD", + cluster.getJettySolrRunners().getFirst(), + "/admin/configs?action=UPLOAD", emptyData, null, false); - assertNotNull(map); unIgnoreException("The configuration name should be provided"); - long statusCode = (long) getObjectByPath(map, Arrays.asList("responseHeader", "status")); - assertEquals(400l, statusCode); + assertEquals(400, getStatusCode(map)); SolrZkClient zkClient = new SolrZkClient.Builder() @@ -374,16 +365,13 @@ public void testUploadErrors() throws Exception { ignoreException("already exists"); map = postDataAndGetResponse( - cluster.getSolrClient(), - cluster.getJettySolrRunners().get(0).getBaseUrl().toString() - + "/admin/configs?action=UPLOAD&name=myconf", + cluster.getJettySolrRunners().getFirst(), + "/admin/configs?action=UPLOAD&name=myconf", emptyData, null, false); - assertNotNull(map); unIgnoreException("already exists`"); - statusCode = (long) getObjectByPath(map, Arrays.asList("responseHeader", "status")); - assertEquals(400l, statusCode); + assertEquals(400, getStatusCode(map)); assertTrue( "Expected file doesnt exist in zk. It's possibly overwritten", zkClient.exists("/configs/myconf/firstDummyFile")); @@ -393,22 +381,15 @@ public void testUploadErrors() throws Exception { // Checking error when configuration name contains invalid characters for (String invalidName : new String[] {"configset!", "-configset"}) { + JettySolrRunner jetty = cluster.getJettySolrRunners().getFirst(); map = postDataAndGetResponse( - cluster.getSolrClient(), - cluster.getJettySolrRunners().get(0).getBaseUrl().toString() - + "/admin/configs?action=UPLOAD&name=" - + invalidName, - emptyData, - null, - false); - assertNotNull(map); - statusCode = (long) getObjectByPath(map, Arrays.asList("responseHeader", "status")); - assertEquals("Expected 400 for invalid configset name: " + invalidName, 400l, statusCode); + jetty, "/admin/configs?action=UPLOAD&name=" + invalidName, emptyData, null, false); + int statusCode = getStatusCode(map); + assertEquals("Expected 400 for invalid configset name: " + invalidName, 400, statusCode); } zkClient.close(); - solrClient.close(); } @Test @@ -481,16 +462,13 @@ public void testUploadLegacyManagedSchemaFile() throws Exception { ByteBuffer buff = UTF_8.encode(payload); Map map = postDataAndGetResponse( - cluster.getSolrClient(), - cluster.getJettySolrRunners().get(0).getBaseUrl().toString() - + "/newcollection/schema?wt=js" - + "on", + cluster.getJettySolrRunners().getFirst(), + "/newcollection/schema?wt=json", + "application/json", buff, null, false); - Map responseHeader = (Map) map.get("responseHeader"); - Long status = (Long) responseHeader.get("status"); - assertEquals((long) status, 0L); + assertEquals(0, getStatusCode(map)); } @Test @@ -1165,14 +1143,14 @@ private void assertConfigsetFiles(String configSetName, String suffix, SolrZkCli readFile("solr/configsets/upload/" + configSetName + "/solrconfig.xml")); } - private long uploadConfigSet( + private int uploadConfigSet( String configSetName, String suffix, String username, SolrZkClient zkClient, boolean v2) - throws IOException { + throws Exception { assertFalse(getConfigSetService().checkConfigExists(configSetName + suffix)); return uploadConfigSet(configSetName, suffix, username, false, false, v2, false, false); } - private long uploadConfigSet( + private int uploadConfigSet( String configSetName, String suffix, String username, @@ -1181,7 +1159,7 @@ private long uploadConfigSet( boolean v2, boolean forbiddenTypes, boolean forbiddenContent) - throws IOException { + throws Exception { Path zipFile; if (forbiddenTypes) { @@ -1200,21 +1178,7 @@ private long uploadConfigSet( return uploadGivenConfigSet(zipFile, configSetName, suffix, username, overwrite, cleanup, v2); } - private long uploadBadConfigSet(String configSetName, String suffix, String username, boolean v2) - throws IOException { - - // Read single file from sample configs. This should fail the unzipping - return uploadGivenConfigSet( - SolrTestCaseJ4.getFile("solr/configsets/upload/regular/solrconfig.xml"), - configSetName, - suffix, - username, - true /* overwrite */, - true /* cleanup */, - v2); - } - - private long uploadGivenConfigSet( + private int uploadGivenConfigSet( Path file, String configSetName, String suffix, @@ -1222,7 +1186,7 @@ private long uploadGivenConfigSet( boolean overwrite, boolean cleanup, boolean v2) - throws IOException { + throws Exception { if (v2) { // TODO: switch to using V2Request @@ -1235,15 +1199,11 @@ private long uploadGivenConfigSet( + (!overwrite ? "?overwrite=false" : "") + (cleanup ? "?cleanup=true" : ""); final boolean usePut = true; + JettySolrRunner jetty = cluster.getJettySolrRunners().getFirst(); Map map = postDataAndGetResponse( - cluster.getSolrClient(), - cluster.getJettySolrRunners().get(0).getBaseURLV2().toString() + uriEnding, - fileBytes, - username, - usePut); - assertNotNull(map); - return (Long) getObjectByPath(map, Arrays.asList("responseHeader", "status")); + jetty, jetty.getBaseURLV2() + uriEnding, fileBytes, username, usePut); + return getStatusCode(map); } // else "not" a V2 request... try { @@ -1262,7 +1222,7 @@ private long uploadGivenConfigSet( } } - private long uploadSingleConfigSetFile( + private int uploadSingleConfigSetFile( String configSetName, String suffix, String username, @@ -1271,7 +1231,7 @@ private long uploadSingleConfigSetFile( boolean overwrite, boolean cleanup, boolean v2) - throws IOException { + throws Exception { // Read single file from sample configs final Path file = SolrTestCaseJ4.getFile(localFilePath); @@ -1292,15 +1252,11 @@ private long uploadSingleConfigSetFile( + (cleanup ? "?cleanup=true" : ""); final boolean usePut = true; + JettySolrRunner jetty = cluster.getJettySolrRunners().getFirst(); Map map = postDataAndGetResponse( - cluster.getSolrClient(), - cluster.getJettySolrRunners().get(0).getBaseURLV2().toString() + uriEnding, - sampleConfigFile, - username, - usePut); - assertNotNull(map); - return (long) getObjectByPath(map, Arrays.asList("responseHeader", "status")); + jetty, jetty.getBaseURLV2() + uriEnding, sampleConfigFile, username, usePut); + return getStatusCode(map); } // else "not" a V2 request... try { @@ -1500,59 +1456,47 @@ protected CollectionAdminResponse createCollection( return res; } + /** for Javabin request, JSON response */ public static Map postDataAndGetResponse( - CloudSolrClient cloudClient, String uri, ByteBuffer bytarr, String username, boolean usePut) - throws IOException { - HttpEntityEnclosingRequestBase httpRequest = null; - HttpEntity entity; - String response = null; - Map m = null; + JettySolrRunner jetty, String uri, ByteBuffer javabinBody, String username, boolean usePut) + throws Exception { + return postDataAndGetResponse( + jetty, uri, "application/octet-stream", javabinBody, username, usePut); + } + /** for {@code contentType} request, JSON response */ + public static Map postDataAndGetResponse( + JettySolrRunner jetty, + String uri, // possibly relative to jetty URI + String contentType, + ByteBuffer payload, + String username, + boolean usePut) + throws Exception { + if (!uri.contains("://")) { + uri = jetty.getBaseUrl() + uri; + } + HttpClient httpClient = jetty.getSolrClient().getHttpClient(); + ContentResponse rsp = + httpClient + .newRequest(uri) + .method(usePut ? HttpMethod.PUT : HttpMethod.POST) + .headers(h -> h.add("user", username)) + .body(new ByteBufferRequestContent(contentType, payload)) + .send(); + String response = rsp.getContentAsString(); try { - if (usePut) { - httpRequest = new HttpPut(uri); - } else { - httpRequest = new HttpPost(uri); - } - - if (username != null) { - httpRequest.addHeader(new BasicHeader("user", username)); - } - - httpRequest.setHeader("Content-Type", "application/octet-stream"); - httpRequest.setEntity( - new ByteArrayEntity(bytarr.array(), bytarr.arrayOffset(), bytarr.limit())); - log.info("Uploading configset with user {}", username); - entity = - ((CloudLegacySolrClient) cloudClient).getHttpClient().execute(httpRequest).getEntity(); - try { - response = EntityUtils.toString(entity, UTF_8); - m = (Map) Utils.fromJSONString(response); - } catch (JSONParser.ParseException e) { - System.err.println("err response: " + response); - throw new AssertionError(e); - } - } finally { - httpRequest.releaseConnection(); + return (Map) Utils.fromJSONString(response); + } catch (JSONParser.ParseException e) { + System.err.println("err response: " + response); + throw new AssertionError(e); } - return m; } - private static Object getObjectByPath(Map root, List hierarchy) { - Map obj = root; - for (int i = 0; i < hierarchy.size(); i++) { - String s = hierarchy.get(i); - if (i < hierarchy.size() - 1) { - if (!(obj.get(s) instanceof Map)) return null; - obj = (Map) obj.get(s); - if (obj == null) return null; - } else { - Object val = obj.get(s); - return val; - } - } - - return false; + private static int getStatusCode(Map rsp) { + assertNotNull("no response", rsp); + Object sObj = Utils.getObjectByPath(rsp, false, List.of("responseHeader", "status")); + return ((Number) sObj).intValue(); } private byte[] readFile(String fname) throws IOException { @@ -1759,8 +1703,8 @@ public boolean doAuthenticate( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws Exception { if (request.getHeader("user") != null) { - final Principal p = new BasicUserPrincipal("solr"); - filterChain.doFilter(wrap(request, p, "solr"), response); + var principal = new SimplePrincipal("solr"); + filterChain.doFilter(wrap(request, principal, "solr"), response); return true; } return super.doAuthenticate(request, response, filterChain); 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 457429a21ac0..58b5a175ca8f 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java @@ -16,20 +16,10 @@ */ package org.apache.solr.cloud; -import java.io.IOException; import java.lang.invoke.MethodHandles; import java.util.List; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; -import org.apache.http.client.methods.HttpHead; -import org.apache.http.config.Registry; -import org.apache.http.config.RegistryBuilder; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.conn.socket.PlainConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.lucene.tests.util.TestRuleRestoreSystemProperties; import org.apache.lucene.util.Constants; import org.apache.solr.SolrTestCaseJ4; @@ -47,6 +37,11 @@ import org.apache.solr.embedded.JettyConfig; import org.apache.solr.embedded.JettySolrRunner; import org.apache.solr.util.SSLTestConfig; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.io.ClientConnector; +import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -157,7 +152,7 @@ public void testSslWithCheckPeerName() throws Exception { * Constructs a cluster with the specified sslConfigs, runs {@link * #checkClusterWithCollectionCreations}, then verifies that if we modify the default SSLContext * (mimicing javax.net.ssl.* sysprops set on JVM startup) and reset to the default - * HttpClientBuilder, new HttpSolrClient instances will still be able to talk to our servers. + * HttpClientBuilder, new HttpJettySolrClient instances will still be able to talk to our servers. * * @see SSLContext#setDefault * @see HttpClientUtil#resetHttpClientBuilder @@ -300,6 +295,7 @@ private static void checkCreateCollection( * * @see #getRandomizedHttpSolrClient */ + @SuppressWarnings("try") // don't care that HttpClient.close can throw InterruptedException private static void checkClusterJettys( final MiniSolrCloudCluster cluster, final SSLTestConfig sslConfig) throws Exception { @@ -341,14 +337,14 @@ private static void checkClusterJettys( if (!sslConfig.isClientAuthMode()) { // verify simple HTTP(S) client can't do HEAD request for URL with wrong protocol - try (CloseableHttpClient client = getSslAwareClientWithNoClientCerts()) { + try (var httpClient = newSslAwareClientWithNoClientCerts()) { final String wrongUrl = wrongBaseURL + "/admin/cores"; // vastly diff exception details between plain http vs https, not worried about details // here expectThrows( - IOException.class, + Exception.class, () -> { - doHeadRequest(client, wrongUrl); + doHeadRequest(httpClient, wrongUrl); }); } } @@ -356,15 +352,15 @@ private static void checkClusterJettys( if (ssl) { // verify expected results for a HEAD request to valid URL from HTTP(S) client w/o client // certs - try (CloseableHttpClient client = getSslAwareClientWithNoClientCerts()) { + try (var httpClient = newSslAwareClientWithNoClientCerts()) { final String url = baseURL + "/admin/cores"; if (sslConfig.isClientAuthMode()) { // w/o a valid client cert, SSL connection should fail expectThrows( - IOException.class, + Exception.class, () -> { - doHeadRequest(client, url); + doHeadRequest(httpClient, url); }); } else { assertEquals( @@ -373,7 +369,7 @@ private static void checkClusterJettys( + ") when clientAuth=" + sslConfig.isClientAuthMode(), 200, - doHeadRequest(client, url)); + doHeadRequest(httpClient, url)); } } } @@ -384,16 +380,15 @@ private static void checkClusterJettys( * Trivial helper method for doing a HEAD request of the specified URL using the specified client * and getting the HTTP statusCode from the response */ - private static int doHeadRequest(final CloseableHttpClient client, final String url) - throws Exception { - return client.execute(new HttpHead(url)).getStatusLine().getStatusCode(); + private static int doHeadRequest(final HttpClient client, final String url) throws Exception { + return client.newRequest(url).method(HttpMethod.HEAD).send().getStatus(); } /** * Returns a new HttpClient that supports both HTTP and HTTPS (with the default test truststore), * but has no keystore -- so servers requiring client authentication should fail. */ - private static CloseableHttpClient getSslAwareClientWithNoClientCerts() { + private static HttpClient newSslAwareClientWithNoClientCerts() throws Exception { // NOTE: This method explicitly does *NOT* use HttpClientUtil code because that // will change the global static HttpClientBuilder / SchemeRegistryProvider, and @@ -401,20 +396,19 @@ private static CloseableHttpClient getSslAwareClientWithNoClientCerts() { final SSLTestConfig clientConfig = new SSLTestConfig(true, false); - final SSLConnectionSocketFactory sslFactory = - clientConfig.buildClientSSLConnectionSocketFactory(); - assertNotNull(sslFactory); + SslContextFactory.Client sslContextFactory = + clientConfig.buildClientSSLConfig().createClientContextFactory(); + assertNotNull(sslContextFactory); - final Registry socketFactoryReg = - RegistryBuilder.create() - .register("https", sslFactory) - .register("http", PlainConnectionSocketFactory.INSTANCE) - .build(); + var clientConnector = new ClientConnector(); + clientConnector.setSslContextFactory(sslContextFactory); - final HttpClientBuilder builder = HttpClientBuilder.create(); - builder.setConnectionManager(new PoolingHttpClientConnectionManager(socketFactoryReg)); + var transport = new HttpClientTransportOverHTTP(clientConnector); - return builder.build(); + var httpClient = new HttpClient(transport); + httpClient.start(); + + return httpClient; } /** 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 e7b0ffaa1449..b2d307aa8521 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java @@ -19,6 +19,7 @@ import com.carrotsearch.randomizedtesting.annotations.Repeat; import java.io.IOException; import java.lang.invoke.MethodHandles; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -32,14 +33,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.request.SolrQuery; @@ -64,6 +59,7 @@ import org.apache.solr.util.TestInjection; import org.apache.solr.util.TimeOut; import org.apache.zookeeper.KeeperException; +import org.eclipse.jetty.client.StringRequestContent; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Ignore; @@ -133,30 +129,31 @@ public void tearDown() throws Exception { public void testCreateDelete() throws Exception { try { switch (random().nextInt(3)) { - case 0: - // Sometimes use SolrJ - CollectionAdminRequest.createCollection(collectionName, "conf", 2, 1, 0, 3) - .process(cluster.getSolrClient()); - break; - case 1: + case 0 -> + // Sometimes use SolrJ + CollectionAdminRequest.createCollection(collectionName, "conf", 2, 1, 0, 3) + .process(cluster.getSolrClient()); + case 1 -> { // Sometimes use v1 API + var jetty = cluster.getRandomJetty(random()); String url = String.format( Locale.ROOT, "%s/admin/collections?action=CREATE&name=%s&collection.configName=%s&numShards=%s&pullReplicas=%s", - cluster.getRandomJetty(random()).getBaseUrl(), + jetty.getBaseUrl(), collectionName, "conf", 2, // numShards 3); // pullReplicas // These options should all mean the same url = url + pickRandom("", "&nrtReplicas=1", "&replicationFactor=1"); - HttpGet createCollectionGet = new HttpGet(url); - getHttpClient().execute(createCollectionGet); - break; - case 2: + var response = jetty.getSolrClient().getHttpClient().GET(url); + assertEquals(200, response.getStatus()); + } + case 2 -> { // Sometimes use V2 API - url = cluster.getRandomJetty(random()).getBaseUrl().toString() + "/____v2/collections"; + var jetty = cluster.getRandomJetty(random()); + String url = jetty.getBaseUrl().toString() + "/____v2/collections"; String requestBody = String.format( Locale.ROOT, @@ -169,12 +166,17 @@ public void testCreateDelete() throws Exception { "", ", \"nrtReplicas\": 1", ", \"replicationFactor\": 1")); // These options should all mean the same - HttpPost createCollectionPost = new HttpPost(url); - createCollectionPost.setHeader("Content-type", "application/json"); - createCollectionPost.setEntity(new StringEntity(requestBody)); - HttpResponse httpResponse = getHttpClient().execute(createCollectionPost); - assertEquals(200, httpResponse.getStatusLine().getStatusCode()); - break; + var response = + jetty + .getSolrClient() + .getHttpClient() + .POST(url) + .body( + new StringRequestContent( + "application/json", requestBody, StandardCharsets.UTF_8)) + .send(); + assertEquals(200, response.getStatus()); + } } boolean reloaded = false; while (true) { @@ -1023,48 +1025,49 @@ private void addDocs(int numDocs) throws SolrServerException, IOException { cluster.getSolrClient().commit(collectionName); } - private void addReplicaToShard(String shardName, Replica.Type type) - throws IOException, SolrServerException { + private void addReplicaToShard(String shardName, Replica.Type type) throws Exception { switch (random().nextInt(3)) { - case 0: // Add replica with SolrJ + case 0 -> { CollectionAdminResponse response = CollectionAdminRequest.addReplicaToShard(collectionName, shardName, type) .process(cluster.getSolrClient()); assertEquals( "Unexpected response status: " + response.getStatus(), 0, response.getStatus()); - break; - case 1: // Add replica with V1 API + } + case 1 -> { + var jetty = cluster.getRandomJetty(random()); String url = String.format( Locale.ROOT, "%s/admin/collections?action=ADDREPLICA&collection=%s&shard=%s&type=%s", - cluster.getRandomJetty(random()).getBaseUrl(), + jetty.getBaseUrl(), collectionName, shardName, type); - HttpGet addReplicaGet = new HttpGet(url); - HttpResponse httpResponse = getHttpClient().execute(addReplicaGet); - assertEquals(200, httpResponse.getStatusLine().getStatusCode()); - break; - case 2: // Add replica with V2 API - url = + var response = jetty.getSolrClient().getHttpClient().GET(url); + assertEquals(200, response.getStatus()); + } + case 2 -> { + var jetty = cluster.getRandomJetty(random()); + String url = String.format( Locale.ROOT, "%s/____v2/collections/%s/shards/%s/replicas", - cluster.getRandomJetty(random()).getBaseUrl(), + jetty.getBaseUrl(), collectionName, shardName); String requestBody = String.format(Locale.ROOT, "{\"type\": \"%s\"}", type); - HttpPost addReplicaPost = new HttpPost(url); - addReplicaPost.setHeader("Content-type", "application/json"); - addReplicaPost.setEntity(new StringEntity(requestBody)); - httpResponse = getHttpClient().execute(addReplicaPost); - assertEquals(200, httpResponse.getStatusLine().getStatusCode()); - break; + var response = + jetty + .getSolrClient() + .getHttpClient() + .POST(url) + .body( + new StringRequestContent( + "application/json", requestBody, StandardCharsets.UTF_8)) + .send(); + assertEquals(200, response.getStatus()); + } } } - - private HttpClient getHttpClient() { - return ((CloudLegacySolrClient) cluster.getSolrClient()).getHttpClient(); - } } 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 c52ca5805b16..aec3a34ed362 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java @@ -35,19 +35,10 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.util.EntityUtils; import org.apache.lucene.index.IndexWriter; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; -import org.apache.solr.client.solrj.apache.HttpSolrClient; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.GenericSolrRequest; @@ -76,6 +67,8 @@ import org.apache.solr.util.TestInjection; import org.apache.solr.util.TimeOut; import org.apache.zookeeper.KeeperException; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.StringRequestContent; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Ignore; @@ -176,9 +169,7 @@ public void testCreateDelete() throws Exception { "conf", 2, // numShards 4); // tlogReplicas - HttpGet createCollectionGet = new HttpGet(url); - HttpResponse httpResponse = getHttpClient().execute(createCollectionGet); - assertEquals(200, httpResponse.getStatusLine().getStatusCode()); + getHttpClient().GET(url); cluster.waitForActiveCollection(collectionName, 2, 8); break; case 2: @@ -193,11 +184,10 @@ public void testCreateDelete() throws Exception { 2, // numShards 4); // tlogReplicas - HttpPost createCollectionPost = new HttpPost(url); - createCollectionPost.setHeader("Content-type", "application/json"); - createCollectionPost.setEntity(new StringEntity(requestBody)); - httpResponse = getHttpClient().execute(createCollectionPost); - assertEquals(200, httpResponse.getStatusLine().getStatusCode()); + getHttpClient() + .POST(url) + .body(new StringRequestContent("application/json", requestBody)) + .send(); cluster.waitForActiveCollection(collectionName, 2, 8); break; } @@ -251,7 +241,7 @@ public void testCreateDelete() throws Exception { } private HttpClient getHttpClient() { - return ((CloudLegacySolrClient) cluster.getSolrClient()).getHttpClient(); + return cluster.getRandomJetty(random()).getSolrClient().getHttpClient(); } @SuppressWarnings("unchecked") @@ -342,8 +332,7 @@ public void testAddRemoveTlogReplica() throws Exception { assertNumberOfReplicas(0, 3, 0, true, true); } - private void addReplicaToShard(String shardName, Replica.Type type) - throws ClientProtocolException, IOException, SolrServerException { + private void addReplicaToShard(String shardName, Replica.Type type) throws Exception { switch (random().nextInt(3)) { case 0: // Add replica with SolrJ CollectionAdminResponse response = @@ -361,9 +350,8 @@ private void addReplicaToShard(String shardName, Replica.Type type) collectionName, shardName, type); - HttpGet addReplicaGet = new HttpGet(url); - HttpResponse httpResponse = getHttpClient().execute(addReplicaGet); - assertEquals(200, httpResponse.getStatusLine().getStatusCode()); + var httpResponse = getHttpClient().GET(url); + assertEquals(200, httpResponse.getStatus()); break; case 2: // Add replica with V2 API url = @@ -374,15 +362,12 @@ private void addReplicaToShard(String shardName, Replica.Type type) collectionName, shardName); String requestBody = String.format(Locale.ROOT, "{\"type\": \"%s\"}", type); - HttpPost addReplicaPost = new HttpPost(url); - addReplicaPost.setHeader("Content-type", "application/json"); - addReplicaPost.setEntity(new StringEntity(requestBody)); - httpResponse = getHttpClient().execute(addReplicaPost); - if (httpResponse.getStatusLine().getStatusCode() == 400) { - final String entity = EntityUtils.toString(httpResponse.getEntity()); - System.out.println(entity); - } - assertEquals(200, httpResponse.getStatusLine().getStatusCode()); + var httpResponse2 = + getHttpClient() + .POST(url) + .body(new StringRequestContent("application/json", requestBody)) + .send(); + assertEquals(200, httpResponse2.getStatus()); break; } } @@ -409,16 +394,11 @@ public void testRealTimeGet() activeReplicaCount(numNrtReplicas, numReplicas, 0)); DocCollection docCollection = assertNumberOfReplicas(numNrtReplicas, numReplicas, 0, false, true); - HttpClient httpClient = getHttpClient(); int id = 0; Slice slice = docCollection.getSlice("shard1"); List ids = new ArrayList<>(slice.getReplicas().size()); for (Replica rAdd : slice.getReplicas()) { - try (SolrClient client = - new HttpSolrClient.Builder(rAdd.getBaseUrl()) - .withDefaultCollection(rAdd.getCoreName()) - .withHttpClient(httpClient) - .build()) { + try (SolrClient client = cluster.getReplicaJetty(rAdd).newSolrClient(rAdd.getCoreName())) { client.add(new SolrInputDocument("id", String.valueOf(id), "foo_s", "bar")); } SolrDocument docCloudClient = @@ -426,11 +406,7 @@ public void testRealTimeGet() assertNotNull(docCloudClient); assertEquals("bar", docCloudClient.getFieldValue("foo_s")); for (Replica rGet : slice.getReplicas()) { - try (SolrClient client = - new HttpSolrClient.Builder(rGet.getBaseUrl()) - .withDefaultCollection(rGet.getCoreName()) - .withHttpClient(httpClient) - .build()) { + try (SolrClient client = cluster.getReplicaJetty(rGet).newSolrClient(rGet.getCoreName())) { SolrDocument doc = client.getById(String.valueOf(id)); assertEquals("bar", doc.getFieldValue("foo_s")); } @@ -440,11 +416,7 @@ public void testRealTimeGet() } SolrDocumentList previousAllIdsResult = null; for (Replica rAdd : slice.getReplicas()) { - try (SolrClient client = - new HttpSolrClient.Builder(rAdd.getBaseUrl()) - .withDefaultCollection(rAdd.getCoreName()) - .withHttpClient(httpClient) - .build()) { + try (SolrClient client = cluster.getReplicaJetty(rAdd).newSolrClient(rAdd.getCoreName())) { SolrDocumentList allIdsResult = client.getById(ids); if (previousAllIdsResult != null) { assertTrue(compareSolrDocumentList(previousAllIdsResult, allIdsResult)); diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionReloadTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionReloadTest.java index 3546677792a5..68c81dd8a7a7 100644 --- a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionReloadTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionReloadTest.java @@ -17,22 +17,17 @@ package org.apache.solr.cloud.api.collections; import com.carrotsearch.randomizedtesting.annotations.Repeat; -import java.io.IOException; import java.lang.invoke.MethodHandles; +import java.nio.charset.StandardCharsets; import java.util.Locale; import java.util.concurrent.TimeUnit; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; import org.apache.solr.SolrTestCaseJ4.SuppressSSL; -import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.response.CollectionAdminResponse; import org.apache.solr.cloud.SolrCloudTestCase; import org.apache.solr.common.cloud.Replica; import org.apache.solr.common.util.RetryUtil; +import org.eclipse.jetty.client.StringRequestContent; import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; @@ -143,24 +138,25 @@ private void assertSuccessfulAdminRequest(CollectionAdminResponse response) { private void createCollection( int numShards, int nrtReplicas, int tlogReplicas, int pullReplicas, String collectionName) - throws SolrServerException, IOException { + throws Exception { switch (random().nextInt(3)) { - case 0: + case 0 -> { log.info("Creating collection with SolrJ"); // Sometimes use SolrJ assertSuccessfulAdminRequest( CollectionAdminRequest.createCollection( collectionName, "conf", numShards, nrtReplicas, tlogReplicas, pullReplicas) .process(cluster.getSolrClient())); - break; - case 1: + } + case 1 -> { log.info("Creating collection with V1 API"); // Sometimes use v1 API + var jetty = cluster.getRandomJetty(random()); String url = String.format( Locale.ROOT, "%s/admin/collections?action=CREATE&name=%s&collection.configName=%s&numShards=%s&maxShardsPerNode=%s&nrtReplicas=%s&tlogReplicas=%s&pullReplicas=%s", - cluster.getRandomJetty(random()).getBaseUrl(), + jetty.getBaseUrl(), collectionName, "conf", numShards, @@ -168,15 +164,14 @@ private void createCollection( nrtReplicas, tlogReplicas, pullReplicas); - HttpGet createCollectionGet = new HttpGet(url); - ((CloudLegacySolrClient) cluster.getSolrClient()) - .getHttpClient() - .execute(createCollectionGet); - break; - case 2: + var response = jetty.getSolrClient().getHttpClient().GET(url); + assertEquals(200, response.getStatus()); + } + case 2 -> { log.info("Creating collection with V2 API"); // Sometimes use V2 API - url = cluster.getRandomJetty(random()).getBaseUrl().toString() + "/____v2/collections"; + var jetty = cluster.getRandomJetty(random()); + String url = jetty.getBaseUrl().toString() + "/____v2/collections"; String requestBody = String.format( Locale.ROOT, @@ -187,15 +182,17 @@ private void createCollection( nrtReplicas, tlogReplicas, pullReplicas); - HttpPost createCollectionPost = new HttpPost(url); - createCollectionPost.setHeader("Content-type", "application/json"); - createCollectionPost.setEntity(new StringEntity(requestBody)); - HttpResponse httpResponse = - ((CloudLegacySolrClient) cluster.getSolrClient()) + var response = + jetty + .getSolrClient() .getHttpClient() - .execute(createCollectionPost); - assertEquals(200, httpResponse.getStatusLine().getStatusCode()); - break; + .POST(url) + .body( + new StringRequestContent( + "application/json", requestBody, StandardCharsets.UTF_8)) + .send(); + assertEquals(200, response.getStatus()); + } } } } diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionsAPIViaSolrCloudCluster.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionsAPIViaSolrCloudCluster.java index 7f8634e448a1..4f6d009cfe52 100644 --- a/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionsAPIViaSolrCloudCluster.java +++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionsAPIViaSolrCloudCluster.java @@ -17,6 +17,7 @@ package org.apache.solr.cloud.api.collections; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -26,11 +27,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.SolrQuery; @@ -46,6 +42,7 @@ import org.apache.solr.common.cloud.Slice; import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.embedded.JettySolrRunner; +import org.eclipse.jetty.client.StringRequestContent; import org.junit.Test; /** Test of the Collections API with the MiniSolrCloudCluster. */ @@ -317,22 +314,22 @@ public void testUserDefinedProperties() throws Exception { String collectionName = "testUserDefinedPropertiesCollection"; switch (random().nextInt(3)) { - case 0: + case 0 -> { CollectionAdminRequest.Create createOp = CollectionAdminRequest.createCollection(collectionName, confName, 1, 2); createOp.withProperty("my.custom.prop", "customProp"); CollectionAdminResponse rsp = createOp.process(cluster.getSolrClient()); assertNull(rsp.getErrorMessages()); assertSame(0, rsp.getStatus()); - break; - - case 1: + } + case 1 -> { // Sometimes use v1 API + var jetty = cluster.getRandomJetty(random()); String url = String.format( Locale.ROOT, "%s/admin/collections?action=CREATE&name=%s&collection.configName=%s&numShards=%s&nrtReplicas=%s&tlogReplicas=%s&pullReplicas=%s&&property.my.custom.prop=%s", - cluster.getRandomJetty(random()).getBaseUrl(), + jetty.getBaseUrl(), collectionName, confName, 2, @@ -341,37 +338,43 @@ public void testUserDefinedProperties() throws Exception { 0, "customProp"); - HttpGet createCollectionGet = new HttpGet(url); - HttpResponse httpResponseV1 = - ((CloudLegacySolrClient) cluster.getSolrClient()) - .getHttpClient() - .execute(createCollectionGet); - assertEquals(200, httpResponseV1.getStatusLine().getStatusCode()); - break; - - case 2: + var response = jetty.getSolrClient().getHttpClient().GET(url); + assertEquals(200, response.getStatus()); + } + case 2 -> { // Sometimes use V2 API - url = cluster.getRandomJetty(random()).getBaseUrl().toString() + "/____v2/collections"; + var jetty = cluster.getRandomJetty(random()); + String url = jetty.getBaseUrl().toString() + "/____v2/collections"; String requestBody = String.format( Locale.ROOT, - "{\"name\":\"%s\", \"config\":\"%s\", \"numShards\":%s, \"nrtReplicas\":%s, \"tlogReplicas\":%s, \"pullReplicas\":%s," - + " \"properties\": { \"my.custom.prop\": \"test\" } }", + """ + { + "name": "%s", + "config": "%s", + "numShards": %s, + "nrtReplicas": %s, + "tlogReplicas": %s, + "pullReplicas": %s, + "properties": { "my.custom.prop": "test" } + }""", collectionName, confName, 2, 2, 2, 0); - HttpPost createCollectionPost = new HttpPost(url); - createCollectionPost.setHeader("Content-type", "application/json"); - createCollectionPost.setEntity(new StringEntity(requestBody)); - HttpResponse httpResponseV2 = - ((CloudLegacySolrClient) cluster.getSolrClient()) + var response = + jetty + .getSolrClient() .getHttpClient() - .execute(createCollectionPost); - assertEquals(200, httpResponseV2.getStatusLine().getStatusCode()); - break; + .POST(url) + .body( + new StringRequestContent( + "application/json", requestBody, StandardCharsets.UTF_8)) + .send(); + assertEquals(200, response.getStatus()); + } } } } diff --git a/solr/core/src/test/org/apache/solr/filestore/TestDistribFileStore.java b/solr/core/src/test/org/apache/solr/filestore/TestDistribFileStore.java index ed017f588399..a5c0d8fdb864 100644 --- a/solr/core/src/test/org/apache/solr/filestore/TestDistribFileStore.java +++ b/solr/core/src/test/org/apache/solr/filestore/TestDistribFileStore.java @@ -17,7 +17,6 @@ package org.apache.solr.filestore; -import static org.apache.solr.common.util.Utils.JAVABINCONSUMER; import static org.apache.solr.core.TestSolrConfigHandler.getFileContent; import static org.hamcrest.CoreMatchers.containsString; @@ -33,13 +32,10 @@ import java.util.concurrent.Callable; import java.util.function.Predicate; import org.apache.commons.codec.digest.DigestUtils; -import org.apache.http.client.methods.HttpDelete; import org.apache.solr.client.solrj.RemoteSolrException; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.apache.HttpClientUtil; -import org.apache.solr.client.solrj.apache.HttpSolrClient; import org.apache.solr.client.solrj.request.FileStoreApi; import org.apache.solr.client.solrj.request.V2Request; import org.apache.solr.client.solrj.response.SimpleSolrResponse; @@ -49,6 +45,7 @@ import org.apache.solr.common.NavigableObject; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.ModifiableSolrParams; +import org.apache.solr.common.util.JavaBinCodec; import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.util.Utils; import org.apache.solr.embedded.JettySolrRunner; @@ -194,10 +191,9 @@ public void testFileStoreManagement() throws Exception { JettySolrRunner j = cluster.getRandomJetty(random()); String path = j.getBaseURLV2() + "/cluster/filestore/files" + "/package/mypkg/v1.0/runtimelibs.jar"; - HttpDelete del = new HttpDelete(path); - try (HttpSolrClient cl = (HttpSolrClient) j.newClient()) { - HttpClientUtil.executeHttpMethod(cl.getHttpClient(), path, Utils.JSONCONSUMER, del); - } + var resp = j.getSolrClient().getHttpClient().newRequest(path).method("DELETE").send(); + assertEquals(200, resp.getStatus()); + expected = Collections.singletonMap(":files:/package/mypkg/v1.0/runtimelibs.jar", null); checkAllNodesForFile(cluster, "/package/mypkg/v1.0/runtimelibs.jar", expected, false); } finally { @@ -217,16 +213,16 @@ public static void checkAllNodesForFile( assertResponseValues(10, new Fetcher(url, jettySolrRunner), expected); if (verifyContent) { - try (HttpSolrClient solrClient = (HttpSolrClient) jettySolrRunner.newClient()) { - ByteBuffer buf = - HttpClientUtil.executeGET( - solrClient.getHttpClient(), - baseUrl + "/cluster/filestore/files" + path, - Utils.newBytesConsumer(Integer.MAX_VALUE)); - assertEquals( - "d01b51de67ae1680a84a813983b1de3b592fc32f1a22b662fc9057da5953abd1b72476388ba342cad21671cd0b805503c78ab9075ff2f3951fdf75fa16981420", - DigestUtils.sha512Hex(new ByteBufferInputStream(buf))); - } + var resp = + jettySolrRunner + .getSolrClient() + .getHttpClient() + .GET(baseUrl + "/cluster/filestore/files" + path); + assertEquals(200, resp.getStatus()); + ByteBuffer buf = ByteBuffer.wrap(resp.getContent()); + assertEquals( + "d01b51de67ae1680a84a813983b1de3b592fc32f1a22b662fc9057da5953abd1b72476388ba342cad21671cd0b805503c78ab9075ff2f3951fdf75fa16981420", + DigestUtils.sha512Hex(new ByteBufferInputStream(buf))); } } } @@ -242,10 +238,9 @@ public Fetcher(String s, JettySolrRunner jettySolrRunner) { @Override public NavigableObject call() throws Exception { - try (HttpSolrClient solrClient = (HttpSolrClient) jetty.newClient()) { - return (NavigableObject) - HttpClientUtil.executeGET(solrClient.getHttpClient(), this.url, JAVABINCONSUMER); - } + var resp = jetty.getSolrClient().getHttpClient().GET(this.url); + assertEquals(200, resp.getStatus()); + return NavigableObject.wrap(new JavaBinCodec().unmarshal(resp.getContent())); } @Override @@ -334,15 +329,12 @@ public static T assertResponseValues( public static void uploadKey(byte[] bytes, String path, MiniSolrCloudCluster cluster) throws Exception { JettySolrRunner jetty = cluster.getRandomJetty(random()); - try (HttpSolrClient client = (HttpSolrClient) jetty.newClient()) { - PackageUtils.uploadKey(bytes, path, jetty.getCoreContainer().getSolrHome()); + PackageUtils.uploadKey(bytes, path, jetty.getCoreContainer().getSolrHome()); + + final var syncReq = new FileStoreApi.SyncFile(path); + final var syncRsp = syncReq.process(jetty.getSolrClient()); + log.info("sync resp for path {} was {}", path, syncRsp.responseHeader.status); - final var syncReq = new FileStoreApi.SyncFile(path); - final var syncRsp = syncReq.process(client); - if (log.isInfoEnabled()) { - log.info("sync resp for path {} was {}", path, syncRsp.responseHeader.status); - } - } checkAllNodesForFile( cluster, path, diff --git a/solr/core/src/test/org/apache/solr/handler/TestConfigReload.java b/solr/core/src/test/org/apache/solr/handler/TestConfigReload.java index 6189a1454717..d590dd5aa22e 100644 --- a/solr/core/src/test/org/apache/solr/handler/TestConfigReload.java +++ b/solr/core/src/test/org/apache/solr/handler/TestConfigReload.java @@ -25,10 +25,6 @@ import java.util.HashSet; import java.util.List; import java.util.concurrent.TimeUnit; -import org.apache.http.HttpEntity; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.util.EntityUtils; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; import org.apache.solr.cloud.AbstractFullDistribZkTestBase; import org.apache.solr.cloud.ZkConfigSetService; import org.apache.solr.common.LinkedHashMapWriter; @@ -55,11 +51,8 @@ public class TestConfigReload extends AbstractFullDistribZkTestBase { @Test public void test() throws Exception { setupRestTestHarnesses(); - try { - reloadTest(); - } finally { - closeRestTestHarnesses(); - } + reloadTest(); + closeRestTestHarnesses(); } private void reloadTest() throws Exception { @@ -121,20 +114,12 @@ private void checkConfReload(SolrZkClient client, String resPath, String name, S @SuppressWarnings({"rawtypes"}) private LinkedHashMapWriter getAsMap(String uri) throws Exception { - HttpGet get = new HttpGet(uri); - HttpEntity entity = null; - try { - entity = - ((CloudLegacySolrClient) cloudClient) - .getLbClient() - .getHttpClient() - .execute(get) - .getEntity(); - String response = EntityUtils.toString(entity, StandardCharsets.UTF_8); - return (LinkedHashMapWriter) - Utils.MAPWRITEROBJBUILDER.apply(Utils.getJSONParser(new StringReader(response))).getVal(); - } finally { - EntityUtils.consumeQuietly(entity); - } + var response = cloudJettys.getFirst().jetty.getSolrClient().getHttpClient().GET(uri); + assertEquals(200, response.getStatus()); + String responseStr = response.getContentAsString(); + return (LinkedHashMapWriter) + Utils.MAPWRITEROBJBUILDER + .apply(Utils.getJSONParser(new StringReader(responseStr))) + .getVal(); } } diff --git a/solr/core/src/test/org/apache/solr/handler/V2ApiIntegrationTest.java b/solr/core/src/test/org/apache/solr/handler/V2ApiIntegrationTest.java index d9a2f40aecb5..4bdeb7bcae25 100644 --- a/solr/core/src/test/org/apache/solr/handler/V2ApiIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/handler/V2ApiIntegrationTest.java @@ -24,14 +24,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.client.utils.URIBuilder; import org.apache.solr.client.solrj.RemoteSolrException; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.jetty.HttpJettySolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; @@ -49,6 +44,7 @@ import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.Utils; +import org.eclipse.jetty.client.HttpClient; import org.junit.BeforeClass; import org.junit.Test; @@ -147,48 +143,45 @@ public void testWTParam() throws Exception { @Test public void testObeysWtParameterWhenProvided() throws Exception { - final var httpClient = getRawClient(); - final var listCollRequest = getListCollectionsRequest(); - listCollRequest.setURI( - new URIBuilder(listCollRequest.getURI()).addParameter("wt", "xml").build()); + final HttpClient httpClient = getRawClient(); + final String url = getListCollectionsUrl(); - final var response = httpClient.execute(listCollRequest); + final var response = httpClient.GET(url + "?wt=xml"); - assertEquals(200, response.getStatusLine().getStatusCode()); - assertEquals("application/xml", response.getFirstHeader("Content-type").getValue()); + assertEquals(200, response.getStatus()); + assertEquals("application/xml", response.getHeaders().get("Content-type")); } @Test public void testObeysAcceptHeaderWhenWtParamNotProvided() throws Exception { - final var httpClient = getRawClient(); - final var listCollRequest = getListCollectionsRequest(); - listCollRequest.addHeader("Accept", "application/xml"); + final HttpClient httpClient = getRawClient(); + final String url = getListCollectionsUrl(); - final var response = httpClient.execute(listCollRequest); + final var response = + httpClient.newRequest(url).headers(h -> h.add("Accept", "application/xml")).send(); - assertEquals(200, response.getStatusLine().getStatusCode()); - assertEquals("application/xml", response.getFirstHeader("Content-type").getValue()); + assertEquals(200, response.getStatus()); + assertEquals("application/xml", response.getHeaders().get("Content-type")); } @Test public void testRespondsWithJsonWhenWtAndAcceptAreMissing() throws Exception { - final var httpClient = getRawClient(); - final var listCollRequest = getListCollectionsRequest(); + final HttpClient httpClient = getRawClient(); + final String url = getListCollectionsUrl(); - final var response = httpClient.execute(listCollRequest); + final var response = httpClient.GET(url); - assertEquals(200, response.getStatusLine().getStatusCode()); - assertEquals("application/json", response.getFirstHeader("Content-type").getValue()); + assertEquals(200, response.getStatus()); + assertEquals("application/json", response.getHeaders().get("Content-type")); } private HttpClient getRawClient() { - return ((CloudLegacySolrClient) cluster.getSolrClient()).getHttpClient(); + return cluster.getRandomJetty(random()).getSolrClient().getHttpClient(); } - private HttpRequestBase getListCollectionsRequest() { + private String getListCollectionsUrl() { final var v2BaseUrl = cluster.getJettySolrRunner(0).getBaseURLV2().toString(); - final var listCollUrl = v2BaseUrl + "/collections"; - return new HttpGet(listCollUrl); + return v2BaseUrl + "/collections"; } @Test diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/ClusterPropsAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/ClusterPropsAPITest.java index b4e5e87a6803..2484b67bfe32 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/api/ClusterPropsAPITest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/api/ClusterPropsAPITest.java @@ -21,17 +21,12 @@ import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.not; -import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.List; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.entity.StringEntity; -import org.apache.solr.client.solrj.apache.HttpClientUtil; -import org.apache.solr.client.solrj.apache.HttpSolrClient; +import java.util.Map; import org.apache.solr.cloud.SolrCloudTestCase; import org.apache.solr.common.util.Utils; +import org.eclipse.jetty.client.StringRequestContent; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -39,7 +34,6 @@ public class ClusterPropsAPITest extends SolrCloudTestCase { - private URL baseUrl; private String baseUrlV2ClusterProps; private static final String testClusterProperty = "ext.test"; @@ -75,7 +69,6 @@ public static void setupCluster() throws Exception { public void setUp() throws Exception { super.setUp(); - baseUrl = cluster.getJettySolrRunner(0).getBaseUrl(); baseUrlV2ClusterProps = cluster.getJettySolrRunner(0).getBaseURLV2().toString() + "/cluster/properties"; } @@ -88,109 +81,121 @@ public void tearDown() throws Exception { @Test public void testClusterPropertyOpsAllGood() throws Exception { - try (HttpSolrClient client = new HttpSolrClient.Builder(baseUrl.toString()).build()) { - // List Properties, confirm the test property does not exist - // This ignores eventually existing other properties - Object o = - HttpClientUtil.executeGET( - client.getHttpClient(), baseUrlV2ClusterProps, Utils.JSONCONSUMER); - assertNotNull(o); - @SuppressWarnings("unchecked") - List initProperties = (List) getObjectByPath(o, true, "clusterProperties"); - assertThat(initProperties, not(hasItem(testClusterProperty))); - - // Create a single cluster property - String path = baseUrlV2ClusterProps + "/" + testClusterProperty; - HttpPut httpPut = new HttpPut(path); - httpPut.setHeader("Content-Type", "application/json"); - httpPut.setEntity(new StringEntity("{\"value\":\"" + testClusterPropertyValue + "\"}")); - o = - HttpClientUtil.executeHttpMethod( - client.getHttpClient(), path, Utils.JSONCONSUMER, httpPut); - assertNotNull(o); - - // List Properties, this time there should be the just added property - o = - HttpClientUtil.executeGET( - client.getHttpClient(), baseUrlV2ClusterProps, Utils.JSONCONSUMER); - assertNotNull(o); - @SuppressWarnings("unchecked") - List updatedProperties = (List) getObjectByPath(o, true, "clusterProperties"); - assertThat(updatedProperties, hasItem(testClusterProperty)); - - // Fetch Cluster Property - // Same path as used in the Create step above - o = HttpClientUtil.executeGET(client.getHttpClient(), path, Utils.JSONCONSUMER); - assertNotNull(o); - assertEquals(testClusterProperty, (String) getObjectByPath(o, true, "clusterProperty/name")); - assertEquals( - testClusterPropertyValue, (String) getObjectByPath(o, true, "clusterProperty/value")); - - // Delete Cluster Property - // Same path as used in the Create step above - HttpDelete httpDelete = new HttpDelete(path); - o = - HttpClientUtil.executeHttpMethod( - client.getHttpClient(), path, Utils.JSONCONSUMER, httpDelete); - assertNotNull(o); - - // List Properties, the test property should be gone - o = - HttpClientUtil.executeGET( - client.getHttpClient(), baseUrlV2ClusterProps, Utils.JSONCONSUMER); - assertNotNull(o); - @SuppressWarnings("unchecked") - List clearedProperties = (List) getObjectByPath(o, true, "clusterProperties"); - assertThat(clearedProperties, not(hasItem(testClusterProperty))); - } + var httpClient = cluster.getJettySolrRunner(0).getSolrClient().getHttpClient(); + // List Properties, confirm the test property does not exist + // This ignores eventually existing other properties + var response = httpClient.GET(baseUrlV2ClusterProps); + assertEquals(200, response.getStatus()); + var o = (Map) Utils.fromJSONString(response.getContentAsString()); + assertNotNull(o); + @SuppressWarnings("unchecked") + List initProperties = (List) getObjectByPath(o, true, "clusterProperties"); + assertThat(initProperties, not(hasItem(testClusterProperty))); + + // Create a single cluster property + String path = baseUrlV2ClusterProps + "/" + testClusterProperty; + response = + httpClient + .newRequest(path) + .method("PUT") + .body( + new StringRequestContent( + "application/json", + "{\"value\":\"" + testClusterPropertyValue + "\"}", + StandardCharsets.UTF_8)) + .send(); + assertEquals(200, response.getStatus()); + o = (Map) Utils.fromJSON(response.getContent()); + assertNotNull(o); + + // List Properties, this time there should be the just added property + response = httpClient.GET(baseUrlV2ClusterProps); + assertEquals(200, response.getStatus()); + o = (Map) Utils.fromJSONString(response.getContentAsString()); + assertNotNull(o); + @SuppressWarnings("unchecked") + List updatedProperties = (List) getObjectByPath(o, true, "clusterProperties"); + assertThat(updatedProperties, hasItem(testClusterProperty)); + + // Fetch Cluster Property + // Same path as used in the Create step above + response = httpClient.GET(path); + assertEquals(200, response.getStatus()); + o = (Map) Utils.fromJSONString(response.getContentAsString()); + assertNotNull(o); + assertEquals(testClusterProperty, (String) getObjectByPath(o, true, "clusterProperty/name")); + assertEquals( + testClusterPropertyValue, (String) getObjectByPath(o, true, "clusterProperty/value")); + + // Delete Cluster Property + // Same path as used in the Create step above + response = httpClient.newRequest(path).method("DELETE").send(); + assertEquals(200, response.getStatus()); + o = (Map) Utils.fromJSONString(response.getContentAsString()); + assertNotNull(o); + + // List Properties, the test property should be gone + response = httpClient.GET(baseUrlV2ClusterProps); + assertEquals(200, response.getStatus()); + o = (Map) Utils.fromJSONString(response.getContentAsString()); + assertNotNull(o); + @SuppressWarnings("unchecked") + List clearedProperties = (List) getObjectByPath(o, true, "clusterProperties"); + assertThat(clearedProperties, not(hasItem(testClusterProperty))); } @Test public void testClusterPropertyNestedBulkSet() throws Exception { - try (HttpSolrClient client = new HttpSolrClient.Builder(baseUrl.toString()).build()) { - // Create a single cluster property using the Bulk/Nested set ClusterProp API - HttpPut httpPut = new HttpPut(baseUrlV2ClusterProps); - httpPut.setHeader("Content-Type", "application/json"); - httpPut.setEntity(new StringEntity(testClusterPropertyBulkAndNestedValues)); - Object o = - HttpClientUtil.executeHttpMethod( - client.getHttpClient(), baseUrlV2ClusterProps, Utils.JSONCONSUMER, httpPut); - assertNotNull(o); - - // Fetch Cluster Property checking the not-nested property set above - String path = baseUrlV2ClusterProps + "/" + testClusterProperty; - o = HttpClientUtil.executeGET(client.getHttpClient(), path, Utils.JSONCONSUMER); - assertNotNull(o); - assertEquals(testClusterProperty, (String) getObjectByPath(o, true, "clusterProperty/name")); - assertEquals( - testClusterPropertyValue, (String) getObjectByPath(o, true, "clusterProperty/value")); - - // Fetch Cluster Property checking the nested property set above - path = baseUrlV2ClusterProps + "/" + "defaults"; - o = HttpClientUtil.executeGET(client.getHttpClient(), path, Utils.JSONCONSUMER); - assertNotNull(o); - assertEquals("defaults", (String) getObjectByPath(o, true, "clusterProperty/name")); - assertEquals(4L, getObjectByPath(o, true, "clusterProperty/value/collection/numShards")); - - // Clean up to leave the state unchanged - HttpDelete httpDelete = new HttpDelete(path); - HttpClientUtil.executeHttpMethod( - client.getHttpClient(), path, Utils.JSONCONSUMER, httpDelete); - path = baseUrlV2ClusterProps + "/" + testClusterProperty; - httpDelete = new HttpDelete(path); - HttpClientUtil.executeHttpMethod( - client.getHttpClient(), path, Utils.JSONCONSUMER, httpDelete); - } + var httpClient = cluster.getJettySolrRunner(0).getSolrClient().getHttpClient(); + // Create a single cluster property using the Bulk/Nested set ClusterProp API + var response = + httpClient + .newRequest(baseUrlV2ClusterProps) + .method("PUT") + .body( + new StringRequestContent( + "application/json", + testClusterPropertyBulkAndNestedValues, + StandardCharsets.UTF_8)) + .send(); + assertEquals(200, response.getStatus()); + var o = (Map) Utils.fromJSONString(response.getContentAsString()); + assertNotNull(o); + + // Fetch Cluster Property checking the not-nested property set above + String path = baseUrlV2ClusterProps + "/" + testClusterProperty; + response = httpClient.GET(path); + assertEquals(200, response.getStatus()); + o = (Map) Utils.fromJSONString(response.getContentAsString()); + assertNotNull(o); + assertEquals(testClusterProperty, (String) getObjectByPath(o, true, "clusterProperty/name")); + assertEquals( + testClusterPropertyValue, (String) getObjectByPath(o, true, "clusterProperty/value")); + + // Fetch Cluster Property checking the nested property set above + path = baseUrlV2ClusterProps + "/" + "defaults"; + response = httpClient.GET(path); + assertEquals(200, response.getStatus()); + o = (Map) Utils.fromJSONString(response.getContentAsString()); + assertNotNull(o); + assertEquals("defaults", (String) getObjectByPath(o, true, "clusterProperty/name")); + assertEquals(4L, getObjectByPath(o, true, "clusterProperty/value/collection/numShards")); + + // Clean up to leave the state unchanged + response = httpClient.newRequest(path).method("DELETE").send(); + assertEquals(200, response.getStatus()); + + path = baseUrlV2ClusterProps + "/" + testClusterProperty; + response = httpClient.newRequest(path).method("DELETE").send(); + assertEquals(200, response.getStatus()); } @Test public void testClusterPropertyFetchNonExistentProperty() throws Exception { - try (HttpSolrClient client = new HttpSolrClient.Builder(baseUrl.toString()).build()) { - // Fetch Cluster Property that doesn't exist - String path = baseUrlV2ClusterProps + "/ext.clusterPropThatDoesNotExist"; - HttpGet fetchClusterPropertyGet = new HttpGet(path); - HttpResponse httpResponse = client.getHttpClient().execute(fetchClusterPropertyGet); - assertEquals(404, httpResponse.getStatusLine().getStatusCode()); - } + var httpClient = cluster.getJettySolrRunner(0).getSolrClient().getHttpClient(); + // Fetch Cluster Property that doesn't exist + String path = baseUrlV2ClusterProps + "/ext.clusterPropThatDoesNotExist"; + var response = httpClient.GET(path); + assertEquals(404, response.getStatus()); } } diff --git a/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java b/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java index ecfaf52451a8..723b4f681e48 100644 --- a/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java @@ -25,13 +25,9 @@ import java.nio.file.Path; import java.util.Map; import java.util.Set; -import org.apache.http.client.HttpClient; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.apache.HttpClientUtil; -import org.apache.solr.client.solrj.apache.HttpSolrClient; import org.apache.solr.cloud.MiniSolrCloudCluster; -import org.apache.solr.common.util.Utils; import org.apache.solr.core.CoreContainer; import org.apache.solr.core.NodeConfig; import org.apache.solr.core.SolrCore; @@ -39,6 +35,7 @@ import org.apache.solr.embedded.JettySolrRunner; import org.apache.solr.util.SolrMetricTestUtils; import org.apache.solr.util.TestHarness; +import org.eclipse.jetty.client.HttpClient; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -127,7 +124,8 @@ public void testZkMetrics() throws Exception { } try (SolrClient solrClient = j.newClient()) { - HttpClient httpClient = ((HttpSolrClient) solrClient).getHttpClient(); + assertNotNull(solrClient); + HttpClient httpClient = j.getSolrClient().getHttpClient(); var initialChildrenFetched = SolrMetricTestUtils.getCounterDatapoint( reader, "solr_zk_cumulative_children_fetched", baseLabels) @@ -141,10 +139,7 @@ public void testZkMetrics() throws Exception { .getValue(); // Send GET request to trigger some metrics - HttpClientUtil.executeGET( - httpClient, - j.getBaseURLV2() + "/cluster/zookeeper/children/live_nodes", - Utils.JSONCONSUMER); + httpClient.GET(j.getBaseURLV2() + "/cluster/zookeeper/children/live_nodes"); var childrenFetched = SolrMetricTestUtils.getCounterDatapoint( diff --git a/solr/core/src/test/org/apache/solr/pkg/TestPackages.java b/solr/core/src/test/org/apache/solr/pkg/TestPackages.java index 96d5f86b28a9..9f32d698b19b 100644 --- a/solr/core/src/test/org/apache/solr/pkg/TestPackages.java +++ b/solr/core/src/test/org/apache/solr/pkg/TestPackages.java @@ -25,8 +25,10 @@ import static org.apache.solr.filestore.TestDistribFileStore.readFile; import static org.apache.solr.filestore.TestDistribFileStore.uploadKey; +import java.io.ByteArrayInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Collections; @@ -46,8 +48,6 @@ import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.apache.HttpClientUtil; -import org.apache.solr.client.solrj.apache.HttpSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.GenericSolrRequest; import org.apache.solr.client.solrj.request.RequestWriter; @@ -65,6 +65,7 @@ import org.apache.solr.common.params.MapSolrParams; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.util.JavaBinCodec; import org.apache.solr.common.util.ReflectMapWriter; import org.apache.solr.common.util.Utils; import org.apache.solr.core.SolrCore; @@ -82,6 +83,8 @@ import org.apache.solr.util.LogLevel; import org.apache.solr.util.plugin.SolrCoreAware; import org.apache.zookeeper.data.Stat; +import org.eclipse.jetty.client.ContentResponse; +import org.eclipse.jetty.client.HttpClient; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -530,15 +533,16 @@ private void executeReq( Utils.InputStreamConsumer parser, Map expected) throws Exception { - try (HttpSolrClient client = (HttpSolrClient) jetty.newClient()) { - TestDistribFileStore.assertResponseValues( - 10, - () -> - NavigableObject.wrap( - HttpClientUtil.executeGET( - client.getHttpClient(), jetty.getBaseUrl() + uri, parser)), - expected); - } + HttpClient httpClient = jetty.getSolrClient().getHttpClient(); + TestDistribFileStore.assertResponseValues( + 10, + () -> { + ContentResponse rsp = httpClient.GET(jetty.getBaseUrl() + uri); + try (InputStream is = new ByteArrayInputStream(rsp.getContent())) { + return NavigableObject.wrap(parser.accept(is)); + } + }, + expected); } private void verifyComponent( @@ -686,11 +690,9 @@ public void testAPI() throws Exception { new Callable() { @Override public NavigableObject call() throws Exception { - try (HttpSolrClient solrClient = (HttpSolrClient) jetty.newClient()) { - return (NavigableObject) - HttpClientUtil.executeGET( - solrClient.getHttpClient(), path, Utils.JAVABINCONSUMER); - } + HttpClient solrClient = jetty.getSolrClient().getHttpClient(); + byte[] bytes = solrClient.GET(path).getContent(); + return (NavigableObject) new JavaBinCodec().unmarshal(bytes); } }, Map.of( diff --git a/solr/core/src/test/org/apache/solr/response/TestErrorResponseStackTrace.java b/solr/core/src/test/org/apache/solr/response/TestErrorResponseStackTrace.java index 21e08e162c37..5271a4e502c4 100644 --- a/solr/core/src/test/org/apache/solr/response/TestErrorResponseStackTrace.java +++ b/solr/core/src/test/org/apache/solr/response/TestErrorResponseStackTrace.java @@ -18,16 +18,14 @@ import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import org.apache.commons.codec.CharEncoding; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.SolrTestCaseJ4.SuppressSSL; import org.apache.solr.client.solrj.RemoteSolrException; -import org.apache.solr.client.solrj.apache.HttpClientUtil; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.response.json.JsonMapResponseParser; import org.apache.solr.common.params.ModifiableSolrParams; @@ -74,29 +72,26 @@ public static void setupSolrHome() throws Exception { public void testFullStackTrace() throws Exception { final String url = solrTestRule.getBaseUrl().toString() + "/collection1/withError?q=*:*&wt=json"; - final HttpGet get = new HttpGet(url); - var client = HttpClientUtil.createClient(null); - try (CloseableHttpResponse responseRaw = client.execute(get)) { + var httpClient = solrTestRule.getJetty().getSolrClient().getHttpClient(); + var responseRaw = httpClient.GET(url); - assertEquals(500, responseRaw.getStatusLine().getStatusCode()); - NamedList response = - new JsonMapResponseParser() - .processResponse(responseRaw.getEntity().getContent(), CharEncoding.UTF_8); + assertEquals(500, responseRaw.getStatus()); + NamedList response = + new JsonMapResponseParser() + .processResponse( + new ByteArrayInputStream(responseRaw.getContent()), StandardCharsets.UTF_8.name()); - assertEquals(500L, response._get("error/code")); - assertEquals("java.lang.RuntimeException", response._get("error/errorClass")); - assertEquals("Stacktrace should be populated.", response._get("error/msg")); - assertTrue( - ((String) response._get("error/trace/stackTrace[0]")) - .contains("org.apache.solr.response.TestErrorResponseStackTrace$ErrorComponent")); - assertEquals("java.io.IOException", response._get("error/trace/causedBy/errorClass")); - assertEquals("This is the cause", response._get("error/trace/causedBy/msg")); - assertTrue( - ((String) response._get("error/trace/causedBy/trace/stackTrace[0]")) - .contains("org.apache.solr.response.TestErrorResponseStackTrace$ErrorComponent")); - } finally { - HttpClientUtil.close(client); - } + assertEquals(500L, response._get("error/code")); + assertEquals("java.lang.RuntimeException", response._get("error/errorClass")); + assertEquals("Stacktrace should be populated.", response._get("error/msg")); + assertTrue( + ((String) response._get("error/trace/stackTrace[0]")) + .contains("org.apache.solr.response.TestErrorResponseStackTrace$ErrorComponent")); + assertEquals("java.io.IOException", response._get("error/trace/causedBy/errorClass")); + assertEquals("This is the cause", response._get("error/trace/causedBy/msg")); + assertTrue( + ((String) response._get("error/trace/causedBy/trace/stackTrace[0]")) + .contains("org.apache.solr.response.TestErrorResponseStackTrace$ErrorComponent")); } @Test diff --git a/solr/core/src/test/org/apache/solr/schema/TestCloudSchemaless.java b/solr/core/src/test/org/apache/solr/schema/TestCloudSchemaless.java index 3528d548e8f5..3cdc8be26e45 100644 --- a/solr/core/src/test/org/apache/solr/schema/TestCloudSchemaless.java +++ b/solr/core/src/test/org/apache/solr/schema/TestCloudSchemaless.java @@ -31,7 +31,6 @@ import org.apache.solr.common.SolrInputDocument; import org.apache.solr.util.BaseTestHarness; import org.eclipse.jetty.ee10.servlet.ServletHolder; -import org.junit.After; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,13 +44,6 @@ public class TestCloudSchemaless extends AbstractFullDistribZkTestBase { private static final String SUCCESS_XPATH = "/response/lst[@name='responseHeader']/int[@name='status'][.='0']"; - @Override - @After - public void tearDown() throws Exception { - super.tearDown(); - closeRestTestHarnesses(); - } - public TestCloudSchemaless() { schemaString = "schema-add-schema-fields-update-processor.xml"; sliceCount = 4; diff --git a/solr/core/src/test/org/apache/solr/search/TestCoordinatorRole.java b/solr/core/src/test/org/apache/solr/search/TestCoordinatorRole.java index 914c409ceb6e..3dbe061559fb 100644 --- a/solr/core/src/test/org/apache/solr/search/TestCoordinatorRole.java +++ b/solr/core/src/test/org/apache/solr/search/TestCoordinatorRole.java @@ -33,10 +33,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.stream.Collectors; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.apache.HttpSolrClient; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.jetty.HttpJettySolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; @@ -621,22 +618,14 @@ public void testConfigset() throws Exception { // However using solr client would drop cache response header, hence we need to use the // underlying httpClient which has SSL correctly configured - try (HttpSolrClient solrClient = - new HttpSolrClient.Builder(coordinatorJetty.getBaseUrl().toString()).build()) { - HttpResponse response = - solrClient - .getHttpClient() - .execute(new HttpGet(coordinatorJetty.getBaseUrl() + "/c1/select?q=*:*")); - // conf1 has no cache-control - assertNull(response.getFirstHeader("cache-control")); - - response = - solrClient - .getHttpClient() - .execute(new HttpGet(coordinatorJetty.getBaseUrl() + "/c2/select?q=*:*")); - // conf2 has cache-control defined - assertTrue(response.getFirstHeader("cache-control").getValue().contains("max-age=30")); - } + var httpClient = coordinatorJetty.getSolrClient().getHttpClient(); + var response = httpClient.GET(coordinatorJetty.getBaseUrl() + "/c1/select?q=*:*"); + // conf1 has no cache-control + assertNull(response.getHeaders().get("cache-control")); + + response = httpClient.GET(coordinatorJetty.getBaseUrl() + "/c2/select?q=*:*"); + // conf2 has cache-control defined + assertTrue(response.getHeaders().get("cache-control").contains("max-age=30")); } finally { cluster.shutdown(); } @@ -900,40 +889,29 @@ public void testCoreReload() throws Exception { System.clearProperty(NodeRoles.NODE_ROLES_PROP); } - try (HttpSolrClient coordinatorClient = - new HttpSolrClient.Builder(coordinatorJetty.getBaseUrl().toString()).build()) { - HttpResponse response = - coordinatorClient - .getHttpClient() - .execute( - new HttpGet( - coordinatorJetty.getBaseUrl() - + "/c1/select?q:*:*")); // make a call so the synthetic core would be - // created - assertEquals(200, response.getStatusLine().getStatusCode()); - // conf1 has no cache-control - assertNull(response.getFirstHeader("cache-control")); - - // now update conf1 - cluster.uploadConfigSet(configset("cache-control"), "conf1"); - - response = - coordinatorClient - .getHttpClient() - .execute( - new HttpGet( - coordinatorJetty.getBaseUrl() - + "/admin/cores?core=.sys.COORDINATOR-COLL-conf1_core&action=reload")); - assertEquals(200, response.getStatusLine().getStatusCode()); - - response = - coordinatorClient - .getHttpClient() - .execute(new HttpGet(coordinatorJetty.getBaseUrl() + "/c1/select?q:*:*")); - assertEquals(200, response.getStatusLine().getStatusCode()); - // now the response should show cache-control - assertTrue(response.getFirstHeader("cache-control").getValue().contains("max-age=30")); - } + var httpClient = coordinatorJetty.getSolrClient().getHttpClient(); + var response = + httpClient.GET( + coordinatorJetty.getBaseUrl() + + "/c1/select?q:*:*"); // make a call so the synthetic core would be + // created + assertEquals(200, response.getStatus()); + // conf1 has no cache-control + assertNull(response.getHeaders().get("cache-control")); + + // now update conf1 + cluster.uploadConfigSet(configset("cache-control"), "conf1"); + + response = + httpClient.GET( + coordinatorJetty.getBaseUrl() + + "/admin/cores?core=.sys.COORDINATOR-COLL-conf1_core&action=reload"); + assertEquals(200, response.getStatus()); + + response = httpClient.GET(coordinatorJetty.getBaseUrl() + "/c1/select?q:*:*"); + assertEquals(200, response.getStatus()); + // now the response should show cache-control + assertTrue(response.getHeaders().get("cache-control").contains("max-age=30")); } finally { cluster.shutdown(); } diff --git a/solr/core/src/test/org/apache/solr/security/BaseTestRuleBasedAuthorizationPlugin.java b/solr/core/src/test/org/apache/solr/security/BaseTestRuleBasedAuthorizationPlugin.java index ae58ff1d67ab..9cfa057b4dfa 100644 --- a/solr/core/src/test/org/apache/solr/security/BaseTestRuleBasedAuthorizationPlugin.java +++ b/solr/core/src/test/org/apache/solr/security/BaseTestRuleBasedAuthorizationPlugin.java @@ -32,7 +32,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.http.auth.BasicUserPrincipal; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.params.MapSolrParams; import org.apache.solr.common.params.SolrParams; @@ -818,7 +817,7 @@ AuthorizationContext getMockContext(Map values) { @Override public Principal getUserPrincipal() { Object userPrincipal = values.get("userPrincipal"); - return userPrincipal == null ? null : new BasicUserPrincipal(String.valueOf(userPrincipal)); + return userPrincipal == null ? null : new SimplePrincipal(String.valueOf(userPrincipal)); } @Override diff --git a/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java b/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java index eb970d03f1aa..2ef080c6ef16 100644 --- a/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java @@ -21,17 +21,12 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.TimeUnit; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ByteArrayEntity; import org.apache.solr.cli.CLITestHelper; import org.apache.solr.cli.StatusTool; import org.apache.solr.client.solrj.RemoteSolrException; @@ -39,7 +34,6 @@ import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; -import org.apache.solr.client.solrj.apache.HttpClientUtil; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.GenericSolrRequest; import org.apache.solr.client.solrj.request.QueryRequest; @@ -59,12 +53,13 @@ import org.apache.solr.common.params.MapSolrParams; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; -import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.TimeSource; import org.apache.solr.common.util.Utils; import org.apache.solr.embedded.JettySolrRunner; import org.apache.solr.util.LogLevel; import org.apache.solr.util.TimeOut; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.StringRequestContent; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -103,300 +98,296 @@ public void testBasicAuth() throws Exception { authzPrefix = "/____v2/cluster/security/authorization"; } - NamedList rsp; - HttpClient cl = null; - try { - cl = HttpClientUtil.createClient(null); - - JettySolrRunner randomJetty = cluster.getRandomJetty(random()); - String baseUrl = randomJetty.getBaseUrl().toString(); - verifySecurityStatus(cl, baseUrl + authcPrefix, "/errorMessages", null, 20); - zkClient().setData("/security.json", STD_CONF.replace("'", "\"").getBytes(UTF_8)); - verifySecurityStatus( - cl, baseUrl + authcPrefix, "authentication/class", "solr.BasicAuthPlugin", 20); - - randomJetty.stop(); - - cluster.waitForJettyToStop(randomJetty); + final JettySolrRunner randomJetty = cluster.getRandomJetty(random()); + HttpClient httpClient = randomJetty.getSolrClient().getHttpClient(); // refetch after restart + String baseUrl = randomJetty.getBaseUrl().toString(); // refetch after restart + verifySecurityStatus(httpClient, baseUrl + authcPrefix, "/errorMessages", null, 20); + zkClient().setData("/security.json", STD_CONF.replace("'", "\"").getBytes(UTF_8)); + verifySecurityStatus( + httpClient, baseUrl + authcPrefix, "authentication/class", "solr.BasicAuthPlugin", 20); - randomJetty.start(); + randomJetty.stop(); - cluster.waitForAllNodes(30); + cluster.waitForJettyToStop(randomJetty); - cluster.waitForActiveCollection(COLLECTION, 3, 3); + randomJetty.start(); - baseUrl = randomJetty.getBaseUrl().toString(); - verifySecurityStatus( - cl, baseUrl + authcPrefix, "authentication/class", "solr.BasicAuthPlugin", 20); + cluster.waitForAllNodes(30); - assertAuthMetricsMinimums(1, 0, 1, 0, 0, 0); - assertPkiAuthMetricsMinimums(0, 0, 0, 0, 0, 0); - - String command = "{\n" + "'set-user': {'harry':'HarryIsCool'}\n" + "}"; + cluster.waitForActiveCollection(COLLECTION, 3, 3); - final SolrRequest genericReq; - if (isUseV2Api) { - genericReq = - new V2Request.Builder("/cluster/security/authentication") - .withMethod(SolrRequest.METHOD.POST) - .build(); - } else { - GenericSolrRequest genericSolrRequest = - new GenericSolrRequest( - SolrRequest.METHOD.POST, authcPrefix, SolrRequest.SolrRequestType.ADMIN); - genericSolrRequest.setContentWriter( - new StringPayloadContentWriter(command, CommonParams.JSON_MIME)); - genericReq = genericSolrRequest; - } + httpClient = randomJetty.getSolrClient().getHttpClient(); // Get fresh client after restart + baseUrl = randomJetty.getBaseUrl().toString(); + verifySecurityStatus( + httpClient, baseUrl + authcPrefix, "authentication/class", "solr.BasicAuthPlugin", 20); - // avoid bad connection races due to shutdown - final var httpClient = ((CloudLegacySolrClient) cluster.getSolrClient()).getHttpClient(); - httpClient.getConnectionManager().closeExpiredConnections(); - httpClient.getConnectionManager().closeIdleConnections(1, TimeUnit.MILLISECONDS); + assertAuthMetricsMinimums(1, 0, 1, 0, 0, 0); + assertPkiAuthMetricsMinimums(0, 0, 0, 0, 0, 0); - RemoteSolrException exp = - expectThrows( - RemoteSolrException.class, - () -> { - cluster.getSolrClient().request(genericReq); - }); - assertEquals(401, exp.code()); - assertAuthMetricsMinimums(2, 0, 2, 0, 0, 0); - assertPkiAuthMetricsMinimums(0, 0, 0, 0, 0, 0); - - command = "{\n" + "'set-user': {'harry':'HarryIsUberCool'}\n" + "}"; - - HttpPost httpPost = new HttpPost(baseUrl + authcPrefix); - setAuthorizationHeader(httpPost, makeBasicAuthHeader("solr", "SolrRocks")); - httpPost.setEntity(new ByteArrayEntity(command.getBytes(UTF_8))); - httpPost.addHeader("Content-Type", "application/json; charset=UTF-8"); - verifySecurityStatus(cl, baseUrl + authcPrefix, "authentication.enabled", "true", 20); - HttpResponse r = cl.execute(httpPost); - int statusCode = r.getStatusLine().getStatusCode(); - HttpClientUtil.consumeFully(r.getEntity()); - assertEquals("proper_cred sent, but access denied", 200, statusCode); - assertPkiAuthMetricsMinimums(0, 0, 0, 0, 0, 0); - assertAuthMetricsMinimums(4, 1, 3, 0, 0, 0); - - baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); - - verifySecurityStatus( - cl, baseUrl + authcPrefix, "authentication/credentials/harry", NOT_NULL_PREDICATE, 20); - command = "{\n" + "'set-user-role': {'harry':'admin'}\n" + "}"; - - executeCommand(baseUrl + authzPrefix, cl, command, "solr", "SolrRocks"); - assertAuthMetricsMinimums(5, 2, 3, 0, 0, 0); - - baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); - verifySecurityStatus( - cl, baseUrl + authzPrefix, "authorization/user-role/harry", NOT_NULL_PREDICATE, 20); - - executeCommand( - baseUrl + authzPrefix, - cl, - Utils.toJSONString( - singletonMap( - "set-permission", Map.of("collection", "x", "path", "/update/*", "role", "dev"))), - "harry", - "HarryIsUberCool"); - - verifySecurityStatus( - cl, baseUrl + authzPrefix, "authorization/permissions[1]/collection", "x", 20); - assertAuthMetricsMinimums(8, 3, 5, 0, 0, 0); - - executeCommand( - baseUrl + authzPrefix, - cl, - Utils.toJSONString( - singletonMap( - "set-permission", Map.of("name", "collection-admin-edit", "role", "admin"))), - "harry", - "HarryIsUberCool"); - verifySecurityStatus( - cl, - baseUrl + authzPrefix, - "authorization/permissions[2]/name", - "collection-admin-edit", - 20); - assertAuthMetricsMinimums(10, 4, 6, 0, 0, 0); - - CollectionAdminRequest.Reload reload = CollectionAdminRequest.reloadCollection(COLLECTION); - - try (SolrClient solrClient = getHttpSolrClient(baseUrl)) { - expectThrows(RemoteSolrException.class, () -> solrClient.request(reload)); - reload.setMethod(SolrRequest.METHOD.POST); - expectThrows(RemoteSolrException.class, () -> solrClient.request(reload)); - } - cluster - .getSolrClient() - .request( - CollectionAdminRequest.reloadCollection(COLLECTION) - .setBasicAuthCredentials("harry", "HarryIsUberCool")); - - expectThrows( - RemoteSolrException.class, - () -> { - cluster - .getSolrClient() - .request( - CollectionAdminRequest.reloadCollection(COLLECTION) - .setBasicAuthCredentials("harry", "Cool12345")); - }); - assertAuthMetricsMinimums(14, 5, 8, 1, 0, 0); - - executeCommand( - baseUrl + authzPrefix, - cl, - "{set-permission : { name : update , role : admin}}", - "harry", - "HarryIsUberCool"); - - UpdateRequest del = new UpdateRequest().deleteByQuery("*:*"); - del.setBasicAuthCredentials("harry", "HarryIsUberCool"); - del.setCommitWithin(10); - del.process(cluster.getSolrClient(), COLLECTION); - - // Test for SOLR-12514. Create a new jetty . This jetty does not have the collection. - // Make a request to that jetty and it should fail - JettySolrRunner aNewJetty = cluster.startJettySolrRunner(); - SolrClient aNewClient = aNewJetty.newClient(); - UpdateRequest delQuery = null; - delQuery = new UpdateRequest().deleteByQuery("*:*"); - delQuery.setBasicAuthCredentials("harry", "HarryIsUberCool"); - delQuery.process(aNewClient, COLLECTION); // this should succeed - try { - RemoteSolrException e = - expectThrows( - RemoteSolrException.class, - () -> { - new UpdateRequest().deleteByQuery("*:*").process(aNewClient, COLLECTION); - }); - assertTrue(e.getMessage(), e.getMessage().contains("Authentication failed")); - } finally { - aNewClient.close(); - cluster.stopJettySolrRunner(aNewJetty); - } + String command = "{\n" + "'set-user': {'harry':'HarryIsCool'}\n" + "}"; - addDocument("harry", "HarryIsUberCool", "id", "4"); - - executeCommand( - baseUrl + authcPrefix, - cl, - "{set-property : { blockUnknown: true}}", - "harry", - "HarryIsUberCool"); - verifySecurityStatus( - cl, - baseUrl + authcPrefix, - "authentication/blockUnknown", - "true", - 20, - "harry", - "HarryIsUberCool"); - verifySecurityStatus(cl, baseUrl + "/admin/info/key", "key", NOT_NULL_PREDICATE, 20); - assertAuthMetricsMinimums(17, 8, 8, 1, 0, 0); - - String[] toolArgs = new String[] {"status", "--solr-url", baseUrl}; - int res = CLITestHelper.runTool(toolArgs, StatusTool.class); - if (res == 0) { - fail("Request should have failed because of missing auth"); - } + final SolrRequest genericReq; + if (isUseV2Api) { + genericReq = + new V2Request.Builder("/cluster/security/authentication") + .withMethod(SolrRequest.METHOD.POST) + .build(); + } else { + GenericSolrRequest genericSolrRequest = + new GenericSolrRequest( + SolrRequest.METHOD.POST, authcPrefix, SolrRequest.SolrRequestType.ADMIN); + genericSolrRequest.setContentWriter( + new StringPayloadContentWriter(command, CommonParams.JSON_MIME)); + genericReq = genericSolrRequest; + } - SolrParams params = new MapSolrParams(Collections.singletonMap("q", "*:*")); - // Query that fails due to missing credentials - exp = + // avoid bad connection races due to shutdown + final var apacheHttpClient = ((CloudLegacySolrClient) cluster.getSolrClient()).getHttpClient(); + apacheHttpClient.getConnectionManager().closeExpiredConnections(); + apacheHttpClient.getConnectionManager().closeIdleConnections(1, TimeUnit.MILLISECONDS); + + RemoteSolrException exp = + expectThrows( + RemoteSolrException.class, + () -> { + cluster.getSolrClient().request(genericReq); + }); + assertEquals(401, exp.code()); + assertAuthMetricsMinimums(2, 0, 2, 0, 0, 0); + assertPkiAuthMetricsMinimums(0, 0, 0, 0, 0, 0); + + command = "{\n" + "'set-user': {'harry':'HarryIsUberCool'}\n" + "}"; + + verifySecurityStatus(httpClient, baseUrl + authcPrefix, "authentication.enabled", "true", 20); + var response = + httpClient + .POST(baseUrl + authcPrefix) + .headers(h1 -> h1.add("Authorization", makeBasicAuthHeader("solr", "SolrRocks"))) + .body(new StringRequestContent("application/json", command, UTF_8)) + .send(); + assertEquals("proper_cred sent, but access denied", 200, response.getStatus()); + + assertPkiAuthMetricsMinimums(0, 0, 0, 0, 0, 0); + assertAuthMetricsMinimums(4, 1, 3, 0, 0, 0); + + baseUrl = cluster.getBaseUrl(random()); + + verifySecurityStatus( + httpClient, + baseUrl + authcPrefix, + "authentication/credentials/harry", + NOT_NULL_PREDICATE, + 20); + command = "{\n" + "'set-user-role': {'harry':'admin'}\n" + "}"; + + executeCommand(httpClient, baseUrl + authzPrefix, command, "solr", "SolrRocks"); + assertAuthMetricsMinimums(5, 2, 3, 0, 0, 0); + + baseUrl = cluster.getBaseUrl(random()); + verifySecurityStatus( + httpClient, baseUrl + authzPrefix, "authorization/user-role/harry", NOT_NULL_PREDICATE, 20); + + executeCommand( + httpClient, + baseUrl + authzPrefix, + Utils.toJSONString( + singletonMap( + "set-permission", Map.of("collection", "x", "path", "/update/*", "role", "dev"))), + "harry", + "HarryIsUberCool"); + + verifySecurityStatus( + httpClient, baseUrl + authzPrefix, "authorization/permissions[1]/collection", "x", 20); + assertAuthMetricsMinimums(8, 3, 5, 0, 0, 0); + + executeCommand( + httpClient, + baseUrl + authzPrefix, + Utils.toJSONString( + singletonMap( + "set-permission", Map.of("name", "collection-admin-edit", "role", "admin"))), + "harry", + "HarryIsUberCool"); + verifySecurityStatus( + httpClient, + baseUrl + authzPrefix, + "authorization/permissions[2]/name", + "collection-admin-edit", + 20); + assertAuthMetricsMinimums(10, 4, 6, 0, 0, 0); + + CollectionAdminRequest.Reload reload = CollectionAdminRequest.reloadCollection(COLLECTION); + + try (var solrClient2 = getHttpSolrClient(baseUrl)) { + expectThrows(RemoteSolrException.class, () -> solrClient2.request(reload)); + reload.setMethod(SolrRequest.METHOD.POST); + expectThrows(RemoteSolrException.class, () -> solrClient2.request(reload)); + } + cluster + .getSolrClient() + .request( + CollectionAdminRequest.reloadCollection(COLLECTION) + .setBasicAuthCredentials("harry", "HarryIsUberCool")); + + expectThrows( + RemoteSolrException.class, + () -> { + cluster + .getSolrClient() + .request( + CollectionAdminRequest.reloadCollection(COLLECTION) + .setBasicAuthCredentials("harry", "Cool12345")); + }); + assertAuthMetricsMinimums(14, 5, 8, 1, 0, 0); + + executeCommand( + httpClient, + baseUrl + authzPrefix, + "{set-permission : { name : update , role : admin}}", + "harry", + "HarryIsUberCool"); + + UpdateRequest del = new UpdateRequest().deleteByQuery("*:*"); + del.setBasicAuthCredentials("harry", "HarryIsUberCool"); + del.setCommitWithin(10); + del.process(cluster.getSolrClient(), COLLECTION); + + // Test for SOLR-12514. Create a new jetty . This jetty does not have the collection. + // Make a request to that jetty and it should fail + JettySolrRunner aNewJetty = cluster.startJettySolrRunner(); + SolrClient aNewClient = aNewJetty.newClient(); + UpdateRequest delQuery = null; + delQuery = new UpdateRequest().deleteByQuery("*:*"); + delQuery.setBasicAuthCredentials("harry", "HarryIsUberCool"); + delQuery.process(aNewClient, COLLECTION); // this should succeed + try { + RemoteSolrException e = expectThrows( RemoteSolrException.class, () -> { - cluster.getSolrClient().query(COLLECTION, params); + new UpdateRequest().deleteByQuery("*:*").process(aNewClient, COLLECTION); }); - assertEquals(401, exp.code()); - assertAuthMetricsMinimums(19, 8, 8, 1, 2, 0); - assertPkiAuthMetricsMinimums(3, 3, 0, 0, 0, 0); - - // Query that succeeds - final var req = new QueryRequest(params); - req.setBasicAuthCredentials("harry", "HarryIsUberCool"); - cluster.getSolrClient().request(req, COLLECTION); - - assertAuthMetricsMinimums(20, 8, 8, 1, 2, 0); - assertPkiAuthMetricsMinimums(10, 10, 0, 0, 0, 0); - - addDocument("harry", "HarryIsUberCool", "id", "5"); - assertAuthMetricsMinimums(23, 11, 9, 1, 2, 0); - assertPkiAuthMetricsMinimums(14, 14, 0, 0, 0, 0); - - // Reindex collection depends on streaming request that needs to authenticate against new - // collection - CollectionAdminRequest.ReindexCollection reindexReq = - CollectionAdminRequest.reindexCollection(COLLECTION); - reindexReq.setBasicAuthCredentials("harry", "HarryIsUberCool"); - cluster.getSolrClient().request(reindexReq, COLLECTION); - assertAuthMetricsMinimums(24, 12, 9, 1, 2, 0); - assertPkiAuthMetricsMinimums(15, 15, 0, 0, 0, 0); - - // Validate forwardCredentials - assertEquals( - 1, - executeQuery(params("q", "id:5"), "harry", "HarryIsUberCool").getResults().getNumFound()); - assertAuthMetricsMinimums(25, 13, 9, 1, 2, 0); - assertPkiAuthMetricsMinimums(19, 19, 0, 0, 0, 0); - executeCommand( - baseUrl + authcPrefix, - cl, - "{set-property : { forwardCredentials: true}}", - "harry", - "HarryIsUberCool"); - verifySecurityStatus( - cl, - baseUrl + authcPrefix, - "authentication/forwardCredentials", - "true", - 20, - "harry", - "HarryIsUberCool"); - assertEquals( - 1, - executeQuery(params("q", "id:5"), "harry", "HarryIsUberCool").getResults().getNumFound()); - assertAuthMetricsMinimums(32, 20, 9, 1, 2, 0); - assertPkiAuthMetricsMinimums(19, 19, 0, 0, 0, 0); - - // This succeeds with auth enabled - CollectionAdminRequest.createCollection("c123", "conf", 3, 1) - .setBasicAuthCredentials("harry", "HarryIsUberCool") - .process(cluster.getSolrClient()); - cluster.waitForActiveCollection("c123", 3, 3); - - // SOLR-17644 - // Test Collection creation when replica placement plugin and basic auth are enabled - PluginMeta plugin = new PluginMeta(); - plugin.name = PlacementPluginFactory.PLUGIN_NAME; - plugin.klass = MinimizeCoresPlacementFactory.class.getName(); - V2Request v2Request = - new V2Request.Builder("/cluster/plugin") - .forceV2(true) - .POST() - .withPayload(singletonMap("add", plugin)) - .build(); - v2Request.setBasicAuthCredentials("harry", "HarryIsUberCool"); - v2Request.process(cluster.getSolrClient()); - - CollectionAdminRequest.createCollection("c456", "conf", 3, 1) - .setBasicAuthCredentials("harry", "HarryIsUberCool") - .process(cluster.getSolrClient()); - cluster.waitForActiveCollection("c456", 3, 3); - - executeCommand( - baseUrl + authcPrefix, - cl, - "{set-property : { blockUnknown: false}}", - "harry", - "HarryIsUberCool"); + assertTrue(e.getMessage(), e.getMessage().contains("Authentication failed")); } finally { - if (cl != null) { - HttpClientUtil.close(cl); - } + aNewClient.close(); + cluster.stopJettySolrRunner(aNewJetty); } + + addDocument("harry", "HarryIsUberCool", "id", "4"); + + executeCommand( + httpClient, + baseUrl + authcPrefix, + "{set-property : { blockUnknown: true}}", + "harry", + "HarryIsUberCool"); + verifySecurityStatus( + httpClient, + baseUrl + authcPrefix, + "authentication/blockUnknown", + "true", + 20, + "harry", + "HarryIsUberCool"); + verifySecurityStatus(httpClient, baseUrl + "/admin/info/key", "key", NOT_NULL_PREDICATE, 20); + assertAuthMetricsMinimums(17, 8, 8, 1, 0, 0); + + String[] toolArgs = new String[] {"status", "--solr-url", baseUrl}; + int res = CLITestHelper.runTool(toolArgs, StatusTool.class); + if (res == 0) { + fail("Request should have failed because of missing auth"); + } + + SolrParams params = new MapSolrParams(Collections.singletonMap("q", "*:*")); + // Query that fails due to missing credentials + exp = + expectThrows( + RemoteSolrException.class, + () -> { + cluster.getSolrClient().query(COLLECTION, params); + }); + assertEquals(401, exp.code()); + assertAuthMetricsMinimums(19, 8, 8, 1, 2, 0); + assertPkiAuthMetricsMinimums(3, 3, 0, 0, 0, 0); + + // Query that succeeds + new QueryRequest(params) + .setBasicAuthCredentials("harry", "HarryIsUberCool") + .process(cluster.getSolrClient(), COLLECTION); + + assertAuthMetricsMinimums(20, 8, 8, 1, 2, 0); + assertPkiAuthMetricsMinimums(10, 10, 0, 0, 0, 0); + + addDocument("harry", "HarryIsUberCool", "id", "5"); + assertAuthMetricsMinimums(23, 11, 9, 1, 2, 0); + assertPkiAuthMetricsMinimums(14, 14, 0, 0, 0, 0); + + // Reindex collection depends on streaming request that needs to authenticate against new + // collection + CollectionAdminRequest.ReindexCollection reindexReq = + CollectionAdminRequest.reindexCollection(COLLECTION); + reindexReq.setBasicAuthCredentials("harry", "HarryIsUberCool"); + cluster.getSolrClient().request(reindexReq, COLLECTION); + assertAuthMetricsMinimums(24, 12, 9, 1, 2, 0); + assertPkiAuthMetricsMinimums(15, 15, 0, 0, 0, 0); + + // Validate forwardCredentials + assertEquals( + 1, + executeQuery(params("q", "id:5"), "harry", "HarryIsUberCool").getResults().getNumFound()); + assertAuthMetricsMinimums(25, 13, 9, 1, 2, 0); + assertPkiAuthMetricsMinimums(19, 19, 0, 0, 0, 0); + executeCommand( + httpClient, + baseUrl + authcPrefix, + "{set-property : { forwardCredentials: true}}", + "harry", + "HarryIsUberCool"); + verifySecurityStatus( + httpClient, + baseUrl + authcPrefix, + "authentication/forwardCredentials", + "true", + 20, + "harry", + "HarryIsUberCool"); + assertEquals( + 1, + executeQuery(params("q", "id:5"), "harry", "HarryIsUberCool").getResults().getNumFound()); + assertAuthMetricsMinimums(32, 20, 9, 1, 2, 0); + assertPkiAuthMetricsMinimums(19, 19, 0, 0, 0, 0); + + // This succeeds with auth enabled + CollectionAdminRequest.createCollection("c123", "conf", 3, 1) + .setBasicAuthCredentials("harry", "HarryIsUberCool") + .process(cluster.getSolrClient()); + cluster.waitForActiveCollection("c123", 3, 3); + + // SOLR-17644 + // Test Collection creation when replica placement plugin and basic auth are enabled + PluginMeta plugin = new PluginMeta(); + plugin.name = PlacementPluginFactory.PLUGIN_NAME; + plugin.klass = MinimizeCoresPlacementFactory.class.getName(); + V2Request v2Request = + new V2Request.Builder("/cluster/plugin") + .forceV2(true) + .POST() + .withPayload(singletonMap("add", plugin)) + .build(); + v2Request.setBasicAuthCredentials("harry", "HarryIsUberCool"); + v2Request.process(cluster.getSolrClient()); + + CollectionAdminRequest.createCollection("c456", "conf", 3, 1) + .setBasicAuthCredentials("harry", "HarryIsUberCool") + .process(cluster.getSolrClient()); + cluster.waitForActiveCollection("c456", 3, 3); + + executeCommand( + httpClient, + baseUrl + authcPrefix, + "{set-property : { blockUnknown: false}}", + "harry", + "HarryIsUberCool"); } private void assertAuthMetricsMinimums( @@ -448,7 +439,8 @@ private void addDocument(String user, String pass, String... fields) } public static void executeCommand( - String url, HttpClient cl, String payload, String user, String pwd) throws Exception { + HttpClient httpClient, String url, String jsonBody, String user, String pwd) + throws Exception { // HACK: work around for SOLR-13464... // @@ -458,18 +450,15 @@ public static void executeCommand( final Set> initialPlugins = getAuthPluginsInUseForCluster(url).entrySet(); - HttpPost httpPost; - HttpResponse r; - httpPost = new HttpPost(url); - setAuthorizationHeader(httpPost, makeBasicAuthHeader(user, pwd)); - httpPost.setEntity(new ByteArrayEntity(payload.getBytes(UTF_8))); - httpPost.addHeader("Content-Type", "application/json; charset=UTF-8"); - r = cl.execute(httpPost); - String response = new String(r.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8); - assertEquals( - "Non-200 response code. Response was " + response, 200, r.getStatusLine().getStatusCode()); - assertFalse("Response contained errors: " + response, response.contains("errorMessages")); - HttpClientUtil.consumeFully(r.getEntity()); + var rsp = + httpClient + .POST(url) + .headers(h1 -> h1.add("Authorization", makeBasicAuthHeader(user, pwd))) + .body(new StringRequestContent("application/json", jsonBody, UTF_8)) + .send(); + String rspStr = rsp.getContentAsString(); + assertEquals("Non-200 response code. Response was " + rspStr, 200, rsp.getStatus()); + assertFalse("Response contained errors: " + rspStr, rspStr.contains("errorMessages")); // HACK (continued)... final TimeOut timeout = new TimeOut(30, TimeUnit.SECONDS, TimeSource.NANO_TIME); diff --git a/solr/core/src/test/org/apache/solr/security/BasicAuthStandaloneTest.java b/solr/core/src/test/org/apache/solr/security/BasicAuthStandaloneTest.java index 6b290aac6873..1f06eecd21a4 100644 --- a/solr/core/src/test/org/apache/solr/security/BasicAuthStandaloneTest.java +++ b/solr/core/src/test/org/apache/solr/security/BasicAuthStandaloneTest.java @@ -26,23 +26,15 @@ import java.nio.file.Path; import java.util.Base64; import java.util.Collections; -import java.util.Properties; -import org.apache.http.Header; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.message.AbstractHttpMessage; -import org.apache.http.message.BasicHeader; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.apache.HttpClientUtil; import org.apache.solr.common.params.MapSolrParams; import org.apache.solr.common.util.Utils; -import org.apache.solr.embedded.JettyConfig; import org.apache.solr.embedded.JettySolrRunner; import org.apache.solr.handler.admin.SecurityConfHandler; import org.apache.solr.handler.admin.SecurityConfHandlerLocalForTesting; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.StringRequestContent; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -65,7 +57,6 @@ public void setUp() throws Exception { instance.setUp(); jetty = createAndStartJetty(instance); securityConfHandler = new SecurityConfHandlerLocalForTesting(jetty.getCoreContainer()); - HttpClientUtil.clearRequestInterceptors(); // Clear out any old Authorization headers } @Override @@ -84,10 +75,10 @@ public void testBasicAuth() throws Exception { String authcPrefix = "/admin/authentication"; String authzPrefix = "/admin/authorization"; - HttpClient httpClient = null; + HttpClient httpClient; SolrClient solrClient = null; try { - httpClient = HttpClientUtil.createClient(null); + httpClient = jetty.getSolrClient().getHttpClient(); String baseUrl = buildUrl(jetty.getLocalPort()); solrClient = getHttpSolrClient(baseUrl); @@ -141,8 +132,7 @@ public void testBasicAuth() throws Exception { httpClient, baseUrl + authzPrefix, "authorization/permissions[2]/role", "solr", 20); } } finally { - if (httpClient != null) { - HttpClientUtil.close(httpClient); + if (solrClient != null) { solrClient.close(); } } @@ -155,7 +145,7 @@ static void doHttpPost( } static void doHttpPost( - HttpClient cl, + HttpClient httpClient, String url, String jsonCommand, String basicUser, @@ -163,40 +153,48 @@ static void doHttpPost( int expectStatusCode) throws IOException { doHttpPostWithHeader( - cl, url, jsonCommand, getBasicAuthHeader(basicUser, basicPass), expectStatusCode); + httpClient, + url, + jsonCommand, + "Authorization", + encodeBasicAuthHeaderIfNotNull(basicUser, basicPass), + expectStatusCode); } static void doHttpPostWithHeader( - HttpClient cl, String url, String jsonCommand, Header header, int expectStatusCode) + HttpClient httpClient, + String url, + String jsonCommand, + String headerName, + String headerValue, + int expectStatusCode) throws IOException { - HttpPost httpPost = new HttpPost(url); - httpPost.setHeader(header); - httpPost.setEntity(new ByteArrayEntity(jsonCommand.replace("'", "\"").getBytes(UTF_8))); - httpPost.addHeader("Content-Type", "application/json; charset=UTF-8"); - HttpResponse r = cl.execute(httpPost); - int statusCode = r.getStatusLine().getStatusCode(); - HttpClientUtil.consumeFully(r.getEntity()); - assertEquals("proper_cred sent, but access denied", expectStatusCode, statusCode); - } - - private static Header getBasicAuthHeader(String user, String pwd) { - String userPass = user + ":" + pwd; - String encoded = Base64.getEncoder().encodeToString(userPass.getBytes(UTF_8)); - return new BasicHeader("Authorization", "Basic " + encoded); + try { + var rsp = + httpClient + .POST(url) + .headers(h -> h.add(headerName, headerValue)) + .body( + new StringRequestContent( + "application/json", jsonCommand.replace("'", "\""), UTF_8)) + .send(); + int statusCode = rsp.getStatus(); + assertEquals("proper_cred sent, but access denied", expectStatusCode, statusCode); + } catch (Exception e) { + throw new IOException(e); + } } - public static void setBasicAuthHeader(AbstractHttpMessage httpMsg, String user, String pwd) { - final Header basicAuthHeader = getBasicAuthHeader(user, pwd); - httpMsg.setHeader(basicAuthHeader); - if (log.isInfoEnabled()) { - log.info("Added Basic Auth security Header {}", basicAuthHeader.getValue()); + private static String encodeBasicAuthHeaderIfNotNull(String user, String pwd) { + if (user == null && pwd == null) { + return null; } + String userPass = user + ":" + pwd; + return "Basic " + Base64.getEncoder().encodeToString(userPass.getBytes(UTF_8)); } static JettySolrRunner createAndStartJetty(SolrInstance instance) throws Exception { - JettySolrRunner jetty = - new JettySolrRunner( - instance.getHomeDir().toString(), new Properties(), JettyConfig.builder().build()); + var jetty = new JettySolrRunner(instance.getHomeDir().toString(), 0); jetty.start(); return jetty; } diff --git a/solr/core/src/test/org/apache/solr/security/MockAuthenticationPlugin.java b/solr/core/src/test/org/apache/solr/security/MockAuthenticationPlugin.java index 91de2be20654..ff0bd7b8c09e 100644 --- a/solr/core/src/test/org/apache/solr/security/MockAuthenticationPlugin.java +++ b/solr/core/src/test/org/apache/solr/security/MockAuthenticationPlugin.java @@ -27,7 +27,6 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; -import org.apache.http.auth.BasicUserPrincipal; public class MockAuthenticationPlugin extends AuthenticationPlugin { static Predicate predicate; @@ -63,7 +62,7 @@ protected void forward( String user, HttpServletRequest req, ServletResponse rsp, FilterChain chain) throws IOException, ServletException { if (user != null) { - final Principal p = new BasicUserPrincipal(user); + final Principal p = new SimplePrincipal(user); req = wrapWithPrincipal(req, p); } chain.doFilter(req, rsp); diff --git a/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java b/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java index 8a9c2ca92056..9cb8d774989a 100644 --- a/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java +++ b/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java @@ -31,22 +31,14 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.security.Principal; -import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.function.Predicate; import java.util.stream.Collectors; -import org.apache.http.Header; -import org.apache.http.HttpHeaders; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.message.BasicHeader; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.apache.HttpClientUtil; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.util.CommandOperation; @@ -54,6 +46,7 @@ import org.apache.solr.embedded.JettySolrRunner; import org.apache.solr.handler.admin.SecurityConfHandler; import org.apache.solr.handler.admin.SecurityConfHandlerLocalForTesting; +import org.eclipse.jetty.client.HttpClient; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -75,7 +68,6 @@ public void setUp() throws Exception { instance.setUp(); jetty = createAndStartJetty(instance); securityConfHandler = new SecurityConfHandlerLocalForTesting(jetty.getCoreContainer()); - HttpClientUtil.clearRequestInterceptors(); // Clear out any old Authorization headers } @Override @@ -96,7 +88,7 @@ public void testMultiAuthEditAPI() throws Exception { HttpClient httpClient = null; SolrClient solrClient = null; try { - httpClient = HttpClientUtil.createClient(null); + httpClient = jetty.getSolrClient().getHttpClient(); String baseUrl = buildUrl(jetty.getLocalPort()); solrClient = getHttpSolrClient(baseUrl); @@ -248,11 +240,7 @@ public void testMultiAuthEditAPI() throws Exception { command = "{\n" + "'set-property': { 'mock': { 'blockUnknown':false } }\n" + "}"; doHttpPostWithHeader( - httpClient, - baseUrl + authcPrefix, - command, - new BasicHeader("Authorization", "mock foo"), - 200); + httpClient, baseUrl + authcPrefix, command, "Authorization", "mock foo", 200); verifySecurityStatus( httpClient, baseUrl + authcPrefix, @@ -262,9 +250,6 @@ public void testMultiAuthEditAPI() throws Exception { user, pass); } finally { - if (httpClient != null) { - HttpClientUtil.close(httpClient); - } if (solrClient != null) { solrClient.close(); } @@ -279,7 +264,7 @@ public void testMultiAuthXBasicLookup() throws Exception { HttpClient httpClient = null; SolrClient solrClient = null; try { - httpClient = HttpClientUtil.createClient(null); + httpClient = jetty.getSolrClient().getHttpClient(); String baseUrl = buildUrl(jetty.getLocalPort()); solrClient = getHttpSolrClient(baseUrl); @@ -306,9 +291,6 @@ public void testMultiAuthXBasicLookup() throws Exception { // verify that clients can still use "Basic" scheme with xBasic scheme configured in MultiAuth doHttpPost(httpClient, baseUrl + authcPrefix, command, user, pass, 200); } finally { - if (httpClient != null) { - HttpClientUtil.close(httpClient); - } if (solrClient != null) { solrClient.close(); } @@ -324,7 +306,7 @@ public void testMultiAuthWithBasicAndXBasic() throws Exception { HttpClient httpClient = null; SolrClient solrClient = null; try { - httpClient = HttpClientUtil.createClient(null); + httpClient = jetty.getSolrClient().getHttpClient(); String baseUrl = buildUrl(jetty.getLocalPort()); solrClient = getHttpSolrClient(baseUrl); @@ -356,9 +338,6 @@ public void testMultiAuthWithBasicAndXBasic() throws Exception { // configuration should return 401 as it resolves with the plugin that uses "basic" as scheme doHttpPost(httpClient, baseUrl + authcPrefix, command, xUser, pass, 401); } finally { - if (httpClient != null) { - HttpClientUtil.close(httpClient); - } if (solrClient != null) { solrClient.close(); } @@ -373,7 +352,7 @@ public void testMultiAuthWithSinglePlugin() throws Exception { HttpClient httpClient = null; SolrClient solrClient = null; try { - httpClient = HttpClientUtil.createClient(null); + httpClient = jetty.getSolrClient().getHttpClient(); String baseUrl = buildUrl(jetty.getLocalPort()); solrClient = getHttpSolrClient(baseUrl); @@ -400,9 +379,6 @@ public void testMultiAuthWithSinglePlugin() throws Exception { // verify that a single plugin configuration is allowed and works doHttpPost(httpClient, baseUrl + authcPrefix, command, user, pass, 200); } finally { - if (httpClient != null) { - HttpClientUtil.close(httpClient); - } if (solrClient != null) { solrClient.close(); } @@ -417,7 +393,7 @@ public void testMultiAuthWithBasicAndMockPlugin() throws Exception { HttpClient httpClient = null; SolrClient solrClient = null; try { - httpClient = HttpClientUtil.createClient(null); + httpClient = jetty.getSolrClient().getHttpClient(); String baseUrl = buildUrl(jetty.getLocalPort()); solrClient = getHttpSolrClient(baseUrl); @@ -444,9 +420,6 @@ public void testMultiAuthWithBasicAndMockPlugin() throws Exception { // verify that the basic auth plugin works and is looked up as expected doHttpPost(httpClient, baseUrl + authcPrefix, command, user, pass, 200); } finally { - if (httpClient != null) { - HttpClientUtil.close(httpClient); - } if (solrClient != null) { solrClient.close(); } @@ -455,10 +428,9 @@ public void testMultiAuthWithBasicAndMockPlugin() throws Exception { @Test public void testMultiAuthWithBasicPluginAndAjax() throws Exception { - HttpClient httpClient = null; SolrClient solrClient = null; try { - httpClient = HttpClientUtil.createClient(null); + var httpClient = jetty.getSolrClient().getHttpClient(); String baseUrl = buildUrl(jetty.getLocalPort()); solrClient = getHttpSolrClient(baseUrl); @@ -475,52 +447,49 @@ public void testMultiAuthWithBasicPluginAndAjax() throws Exception { securityConfHandler.securityConfEdited(); // Pretend to send unauthorized AJAX request - HttpGet httpGet = new HttpGet(baseUrl + CommonParams.SYSTEM_INFO_PATH); - httpGet.addHeader(new BasicHeader("X-Requested-With", "XMLHttpRequest")); - - HttpResponse response = httpClient.execute(httpGet); - assertEquals( - "Unauthorized response was expected", 401, response.getStatusLine().getStatusCode()); - - // Only first plugin is expected as response, which is also xBasic if BasicAuthPlugin - Header[] headers = response.getHeaders(HttpHeaders.WWW_AUTHENTICATE); - List actualSchemes = Arrays.stream(headers).map(Header::getValue).toList(); - - // Only the first scheme is expected for AJAX-Requests - assertEquals("Only one scheme was expected", 1, actualSchemes.size()); - - // In case of BasicAuthPlugin, xBasic should be returned if AJAX request sent and handled by - // BasicAuthPlugin - String expectedScheme = "xBasic realm=\"solr\""; - assertEquals( - "Mapped xBasic challenge expected from first plugin which is BasicAuthPlugin", - expectedScheme, - actualSchemes.getFirst()); - } finally { - if (httpClient != null) { - HttpClientUtil.close(httpClient); + try { + var response = + httpClient + .newRequest(baseUrl + CommonParams.SYSTEM_INFO_PATH) + .headers(h -> h.add("X-Requested-With", "XMLHttpRequest")) + .send(); + assertEquals("Unauthorized response was expected", 401, response.getStatus()); + + // Only first plugin is expected as response, which is also xBasic if BasicAuthPlugin + List actualSchemes = response.getHeaders().getValuesList("WWW-Authenticate"); + + // Only the first scheme is expected for AJAX-Requests + assertEquals("Only one scheme was expected", 1, actualSchemes.size()); + + // In case of BasicAuthPlugin, xBasic should be returned if AJAX request sent and handled by + // BasicAuthPlugin + String expectedScheme = "xBasic realm=\"solr\""; + assertEquals( + "Mapped xBasic challenge expected from first plugin which is BasicAuthPlugin", + expectedScheme, + actualSchemes.getFirst()); + } catch (Exception e) { + throw new RuntimeException(e); } + } finally { if (solrClient != null) { solrClient.close(); } } } - private int doHttpGetAnonymous(HttpClient cl, String url) throws IOException { - HttpGet httpPost = new HttpGet(url); - HttpResponse r = cl.execute(httpPost); - int statusCode = r.getStatusLine().getStatusCode(); - HttpClientUtil.consumeFully(r.getEntity()); - return statusCode; + private int doHttpGetAnonymous(HttpClient httpClient, String url) throws IOException { + try { + return httpClient.GET(url).getStatus(); + } catch (Exception e) { + throw new IOException(e); + } } private void verifyWWWAuthenticateHeaders(HttpClient httpClient, String baseUrl) throws Exception { - HttpGet httpGet = new HttpGet(baseUrl + CommonParams.SYSTEM_INFO_PATH); - HttpResponse response = httpClient.execute(httpGet); - Header[] headers = response.getHeaders(HttpHeaders.WWW_AUTHENTICATE); - List actualSchemes = - Arrays.stream(headers).map(Header::getValue).collect(Collectors.toList()); + var response = httpClient.GET(baseUrl + CommonParams.SYSTEM_INFO_PATH); + List actualSchemes = response.getHeaders().getValuesList("WWW-Authenticate"); List expectedSchemes = generateExpectedSchemes(); actualSchemes.sort(String.CASE_INSENSITIVE_ORDER); diff --git a/solr/core/src/test/org/apache/solr/security/PKIAuthenticationIntegrationTest.java b/solr/core/src/test/org/apache/solr/security/PKIAuthenticationIntegrationTest.java index fbb0cd88c7b0..5e82c858a22c 100644 --- a/solr/core/src/test/org/apache/solr/security/PKIAuthenticationIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/security/PKIAuthenticationIntegrationTest.java @@ -23,14 +23,13 @@ import java.security.Principal; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.http.client.HttpClient; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.cloud.SolrCloudAuthTestCase; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.util.Utils; import org.apache.solr.embedded.JettySolrRunner; +import org.eclipse.jetty.client.HttpClient; import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; @@ -65,7 +64,7 @@ public static void setupCluster() throws Exception { @Test public void testPkiAuth() throws Exception { - HttpClient httpClient = ((CloudLegacySolrClient) cluster.getSolrClient()).getHttpClient(); + HttpClient httpClient = cluster.getRandomJetty(random()).getSolrClient().getHttpClient(); for (JettySolrRunner jetty : cluster.getJettySolrRunners()) { String baseUrl = jetty.getBaseUrl().toString(); verifySecurityStatus( diff --git a/solr/core/src/test/org/apache/solr/security/TestAuthorizationFramework.java b/solr/core/src/test/org/apache/solr/security/TestAuthorizationFramework.java index b1d90c142186..a74ab603e8b6 100644 --- a/solr/core/src/test/org/apache/solr/security/TestAuthorizationFramework.java +++ b/solr/core/src/test/org/apache/solr/security/TestAuthorizationFramework.java @@ -22,17 +22,13 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.util.EntityUtils; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; -import org.apache.solr.client.solrj.apache.HttpClientUtil; import org.apache.solr.cloud.AbstractFullDistribZkTestBase; import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.util.Utils; import org.apache.zookeeper.CreateMode; +import org.eclipse.jetty.client.HttpClient; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -64,7 +60,7 @@ public void authorizationFrameworkTest() throws Exception { waitForThingsToLevelOut(10, TimeUnit.SECONDS); String baseUrl = jettys.get(0).getBaseUrl().toString(); verifySecurityStatus( - ((CloudLegacySolrClient) cloudClient).getHttpClient(), + jettys.get(0).getSolrClient().getHttpClient(), baseUrl + "/admin/authorization", "authorization/class", s -> MockAuthorizationPlugin.class.getName().equals(s), @@ -89,15 +85,13 @@ public void distribTearDown() throws Exception { } public static void verifySecurityStatus( - HttpClient cl, String url, String objPath, Predicate expected, int count) + HttpClient httpClient, String url, String objPath, Predicate expected, int count) throws Exception { String s = null; List hierarchy = StrUtils.splitSmart(objPath, '/'); for (int i = 0; i < count; i++) { - HttpGet get = new HttpGet(url); - s = - EntityUtils.toString( - cl.execute(get, HttpClientUtil.createNewHttpClientRequestContext()).getEntity()); + var response = httpClient.GET(url); + s = response.getContentAsString(); Map m = (Map) Utils.fromJSONString(s); Object actual = Utils.getObjectByPath(m, true, hierarchy); diff --git a/solr/core/src/test/org/apache/solr/security/TestExternalRoleRuleBasedAuthorizationPlugin.java b/solr/core/src/test/org/apache/solr/security/TestExternalRoleRuleBasedAuthorizationPlugin.java index 8102a6a6fa6d..cf0c0dc1e230 100644 --- a/solr/core/src/test/org/apache/solr/security/TestExternalRoleRuleBasedAuthorizationPlugin.java +++ b/solr/core/src/test/org/apache/solr/security/TestExternalRoleRuleBasedAuthorizationPlugin.java @@ -23,7 +23,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import org.apache.http.auth.BasicUserPrincipal; /** * Tests {@link ExternalRoleRuleBasedAuthorizationPlugin} through simulating principals with roles @@ -63,7 +62,7 @@ public Principal getUserPrincipal() { ? null : principals.get(userPrincipal) != null ? principals.get(userPrincipal) - : new BasicUserPrincipal(userPrincipal); + : new SimplePrincipal(userPrincipal); } }; } diff --git a/solr/core/src/test/org/apache/solr/security/TestPKIAuthenticationPlugin.java b/solr/core/src/test/org/apache/solr/security/TestPKIAuthenticationPlugin.java index 890b9de75db4..f5d79ffddea3 100644 --- a/solr/core/src/test/org/apache/solr/security/TestPKIAuthenticationPlugin.java +++ b/solr/core/src/test/org/apache/solr/security/TestPKIAuthenticationPlugin.java @@ -35,11 +35,9 @@ import java.security.PublicKey; import java.time.Instant; import java.util.Base64; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicReference; -import org.apache.http.Header; -import org.apache.http.HttpHeaders; -import org.apache.http.auth.BasicUserPrincipal; -import org.apache.http.message.BasicHttpRequest; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.metrics.SolrMetricsContext; @@ -47,6 +45,7 @@ import org.apache.solr.request.SolrRequestInfo; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.util.CryptoKeys; +import org.eclipse.jetty.http.HttpHeader; import org.junit.Test; import org.mockito.ArgumentMatchers; @@ -79,7 +78,7 @@ boolean isSolrThread() { } final AtomicReference principal = new AtomicReference<>(); - final AtomicReference
header = new AtomicReference<>(); + final AtomicReference headerValue = new AtomicReference<>(); final AtomicReference wrappedRequestByFilter = new AtomicReference<>(); final FilterChain filterChain = @@ -94,7 +93,7 @@ boolean isSolrThread() { String headerKey; HttpServletRequest mockReq; MockPKIAuthenticationPlugin mock; - BasicHttpRequest request; + Map headers; @Override public void setUp() throws Exception { @@ -102,7 +101,7 @@ public void setUp() throws Exception { assumeWorkingMockito(); principal.set(null); - header.set(null); + headerValue.set(null); wrappedRequestByFilter.set(null); if (random().nextBoolean()) { @@ -115,10 +114,10 @@ public void setUp() throws Exception { System.setProperty(PKIAuthenticationPlugin.ACCEPT_VERSIONS, "v1,v2"); } - mockReq = createMockRequest(header); + mockReq = createMockRequest(headerValue); mock = new MockPKIAuthenticationPlugin(nodeName); mockMetrics(mock); - request = new BasicHttpRequest("GET", "http://localhost:56565"); + headers = new HashMap<>(); } private static void mockMetrics(MockPKIAuthenticationPlugin mock) { @@ -144,9 +143,9 @@ public void testBasicRequest() throws Exception { solrQueryRequestBase.setUserPrincipalName(username); mock.solrRequestInfo = new SolrRequestInfo(solrQueryRequestBase, new SolrQueryResponse()); mockSetHeaderOnRequest(); - header.set(request.getFirstHeader(headerKey)); - assertNotNull(header.get()); - assertTrue(header.get().getValue().startsWith(nodeName)); + headerValue.set(headers.get(headerKey)); + assertNotNull(headerValue.get()); + assertTrue(headerValue.get().startsWith(nodeName)); assertTrue(mock.authenticate(mockReq, null, filterChain)); assertNotNull(wrappedRequestByFilter.get()); @@ -156,7 +155,7 @@ public void testBasicRequest() throws Exception { } private void mockSetHeaderOnRequest() { - mock.setHeader((k, v) -> request.setHeader(k, v)); + mock.setHeader((k, v) -> headers.put(k, v)); } public void testSuperUser() throws Exception { @@ -180,9 +179,9 @@ PublicKey fetchPublicKeyFromRemote(String ignored) { // Setup regular superuser request mock.solrRequestInfo = null; mockSetHeaderOnRequest(); - header.set(request.getFirstHeader(headerKey)); - assertNotNull(header.get()); - assertTrue(header.get().getValue().startsWith(nodeName)); + headerValue.set(headers.get(headerKey)); + assertNotNull(headerValue.get()); + assertTrue(headerValue.get().startsWith(nodeName)); assertTrue(mock.authenticate(mockReq, null, filterChain)); assertNotNull(wrappedRequestByFilter.get()); @@ -204,7 +203,7 @@ public void testProtocolMismatch() throws Exception { mock = new MockPKIAuthenticationPlugin(nodeName); mockMetrics(mock); - principal.set(new BasicUserPrincipal("solr")); + principal.set(new SimplePrincipal("solr")); mock.solrRequestInfo = new SolrRequestInfo(solrQueryRequestBase, new SolrQueryResponse()); mockSetHeaderOnRequest(); @@ -213,7 +212,8 @@ public void testProtocolMismatch() throws Exception { assertFalse( "Should have failed authentication", mock.authenticate(mockReq, response, filterChain)); - verify(response).setHeader(HttpHeaders.WWW_AUTHENTICATE, PKIAuthenticationPlugin.HEADER_V2); + verify(response) + .setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), PKIAuthenticationPlugin.HEADER_V2); verify(response).sendError(ArgumentMatchers.eq(401), anyString()); assertNull( @@ -303,14 +303,13 @@ public void testParseCipherInvalidKeyExample() { base64Cipher, CryptoKeys.deserializeX509PublicKey(publicKey), true)); } - private HttpServletRequest createMockRequest(final AtomicReference
header) { + private HttpServletRequest createMockRequest(final AtomicReference headerValue) { HttpServletRequest mockReq = mock(HttpServletRequest.class); when(mockReq.getHeader(any(String.class))) .then( invocation -> { if (headerKey.equals(invocation.getArgument(0))) { - if (header.get() == null) return null; - return header.get().getValue(); + return headerValue.get(); } else return null; }); when(mockReq.getRequestURI()).thenReturn("/collection1/select"); diff --git a/solr/core/src/test/org/apache/solr/servlet/CacheHeaderTest.java b/solr/core/src/test/org/apache/solr/servlet/CacheHeaderTest.java index 57045b49a9a8..a3ee69b0910c 100644 --- a/solr/core/src/test/org/apache/solr/servlet/CacheHeaderTest.java +++ b/solr/core/src/test/org/apache/solr/servlet/CacheHeaderTest.java @@ -17,14 +17,15 @@ package org.apache.solr.servlet; import java.nio.file.Path; -import java.util.Date; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.Properties; -import org.apache.http.Header; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.client.utils.DateUtils; import org.apache.solr.common.util.SuppressForbidden; import org.apache.solr.embedded.JettyConfig; +import org.eclipse.jetty.client.ContentResponse; +import org.eclipse.jetty.http.HttpHeader; import org.junit.BeforeClass; import org.junit.Test; @@ -57,195 +58,218 @@ public static void beforeTest() throws Exception { @Test public void testCacheVetoException() throws Exception { - HttpRequestBase m = getSelectMethod("GET", "q", "xyz_ignore_exception:solr", "qt", "standard"); + String url = getSelectUrl("q", "xyz_ignore_exception:solr", "qt", "standard"); // We force an exception from Solr. This should emit "no-cache" HTTP headers - HttpResponse response = getHttpClient().execute(m); - assertNotEquals(200, response.getStatusLine().getStatusCode()); + ContentResponse response = getHttpClient().GET(url); + assertNotEquals(200, response.getStatus()); checkVetoHeaders(response); } @SuppressForbidden(reason = "Needs currentTimeMillis to check against expiry headers from Solr") - protected void checkVetoHeaders(HttpResponse response) { - Header head = response.getFirstHeader("Cache-Control"); + protected void checkVetoHeaders(ContentResponse response) { + String head = response.getHeaders().get(HttpHeader.CACHE_CONTROL); assertNotNull("We got no Cache-Control header", head); assertTrue( - "We got no no-cache in the Cache-Control header [" + head + "]", - head.getValue().contains("no-cache")); + "We got no no-cache in the Cache-Control header [" + head + "]", head.contains("no-cache")); assertTrue( - "We got no no-store in the Cache-Control header [" + head + "]", - head.getValue().contains("no-store")); + "We got no no-store in the Cache-Control header [" + head + "]", head.contains("no-store")); - head = response.getFirstHeader("Pragma"); + head = response.getHeaders().get(HttpHeader.PRAGMA); assertNotNull("We got no Pragma header", head); - assertEquals("no-cache", head.getValue()); + assertEquals("no-cache", head); } @Override protected void doLastModified(String method) throws Exception { // We do a first request to get the last modified // This must result in a 200 OK response - HttpRequestBase get = getSelectMethod(method); - HttpResponse response = getHttpClient().execute(get); + String url = getSelectUrl(); + ContentResponse response = getHttpClient().newRequest(url).method(method).send(); checkResponseBody(method, response); - assertEquals( - "Got no response code 200 in initial request", - 200, - response.getStatusLine().getStatusCode()); + assertEquals("Got no response code 200 in initial request", 200, response.getStatus()); - Header head = response.getFirstHeader("Last-Modified"); + String head = response.getHeaders().get(HttpHeader.LAST_MODIFIED); assertNotNull("We got no Last-Modified header", head); - Date lastModified = DateUtils.parseDate(head.getValue()); + ZonedDateTime lastModified = ZonedDateTime.parse(head, DateTimeFormatter.RFC_1123_DATE_TIME); // If-Modified-Since tests - get = getSelectMethod(method); - get.addHeader("If-Modified-Since", DateUtils.formatDate(new Date())); - - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers( + h -> + h.add( + HttpHeader.IF_MODIFIED_SINCE, + DateTimeFormatter.RFC_1123_DATE_TIME.format( + Instant.now().atZone(ZoneOffset.UTC)))) + .send(); checkResponseBody(method, response); - assertEquals( - "Expected 304 NotModified response with current date", - 304, - response.getStatusLine().getStatusCode()); - - get = getSelectMethod(method); - get.addHeader( - "If-Modified-Since", DateUtils.formatDate(new Date(lastModified.getTime() - 10000))); - response = getHttpClient().execute(get); + assertEquals("Expected 304 NotModified response with current date", 304, response.getStatus()); + + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers( + h -> + h.add( + HttpHeader.IF_MODIFIED_SINCE, + DateTimeFormatter.RFC_1123_DATE_TIME.format(lastModified.minusSeconds(10)))) + .send(); checkResponseBody(method, response); assertEquals( - "Expected 200 OK response with If-Modified-Since in the past", - 200, - response.getStatusLine().getStatusCode()); + "Expected 200 OK response with If-Modified-Since in the past", 200, response.getStatus()); // If-Unmodified-Since tests - get = getSelectMethod(method); - get.addHeader( - "If-Unmodified-Since", DateUtils.formatDate(new Date(lastModified.getTime() - 10000))); - - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers( + h -> + h.add( + HttpHeader.IF_UNMODIFIED_SINCE, + DateTimeFormatter.RFC_1123_DATE_TIME.format(lastModified.minusSeconds(10)))) + .send(); checkResponseBody(method, response); assertEquals( "Expected 412 Precondition failed with If-Unmodified-Since in the past", 412, - response.getStatusLine().getStatusCode()); - - get = getSelectMethod(method); - get.addHeader("If-Unmodified-Since", DateUtils.formatDate(new Date())); - response = getHttpClient().execute(get); + response.getStatus()); + + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers( + h -> + h.add( + HttpHeader.IF_UNMODIFIED_SINCE, + DateTimeFormatter.RFC_1123_DATE_TIME.format( + Instant.now().atZone(ZoneOffset.UTC)))) + .send(); checkResponseBody(method, response); assertEquals( "Expected 200 OK response with If-Unmodified-Since and current date", 200, - response.getStatusLine().getStatusCode()); + response.getStatus()); } // test ETag @Override protected void doETag(String method) throws Exception { - HttpRequestBase get = getSelectMethod(method); - HttpResponse response = getHttpClient().execute(get); + String url = getSelectUrl(); + ContentResponse response = getHttpClient().newRequest(url).method(method).send(); checkResponseBody(method, response); - assertEquals( - "Got no response code 200 in initial request", - 200, - response.getStatusLine().getStatusCode()); + assertEquals("Got no response code 200 in initial request", 200, response.getStatus()); - Header head = response.getFirstHeader("ETag"); + String head = response.getHeaders().get(HttpHeader.ETAG); assertNotNull("We got no ETag in the response", head); - assertTrue( - "Not a valid ETag", head.getValue().startsWith("\"") && head.getValue().endsWith("\"")); + assertTrue("Not a valid ETag", head.startsWith("\"") && head.endsWith("\"")); - String etag = head.getValue(); + String etag = head; // If-None-Match tests // we set a non-matching ETag - get = getSelectMethod(method); - get.addHeader("If-None-Match", "\"xyz123456\""); - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers(h -> h.add(HttpHeader.IF_NONE_MATCH, "\"xyz123456\"")) + .send(); checkResponseBody(method, response); assertEquals( "If-None-Match: Got no response code 200 in response to non matching ETag", 200, - response.getStatusLine().getStatusCode()); + response.getStatus()); // now we set matching ETags - get = getSelectMethod(method); - get.addHeader("If-None-Match", "\"xyz1223\""); - get.addHeader("If-None-Match", "\"1231323423\", \"1211211\", " + etag); - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers( + h -> { + h.add(HttpHeader.IF_NONE_MATCH, "\"xyz1223\""); + h.add(HttpHeader.IF_NONE_MATCH, "\"1231323423\", \"1211211\", " + etag); + }) + .send(); checkResponseBody(method, response); - assertEquals( - "If-None-Match: Got no response 304 to matching ETag", - 304, - response.getStatusLine().getStatusCode()); + assertEquals("If-None-Match: Got no response 304 to matching ETag", 304, response.getStatus()); // we now set the special star ETag - get = getSelectMethod(method); - get.addHeader("If-None-Match", "*"); - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers(h -> h.add(HttpHeader.IF_NONE_MATCH, "*")) + .send(); checkResponseBody(method, response); - assertEquals( - "If-None-Match: Got no response 304 for star ETag", - 304, - response.getStatusLine().getStatusCode()); + assertEquals("If-None-Match: Got no response 304 for star ETag", 304, response.getStatus()); // If-Match tests // we set a non-matching ETag - get = getSelectMethod(method); - get.addHeader("If-Match", "\"xyz123456\""); - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers(h -> h.add(HttpHeader.IF_MATCH, "\"xyz123456\"")) + .send(); checkResponseBody(method, response); assertEquals( "If-Match: Got no response code 412 in response to non matching ETag", 412, - response.getStatusLine().getStatusCode()); + response.getStatus()); // now we set matching ETags - get = getSelectMethod(method); - get.addHeader("If-Match", "\"xyz1223\""); - get.addHeader("If-Match", "\"1231323423\", \"1211211\", " + etag); - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers( + h -> { + h.add(HttpHeader.IF_MATCH, "\"xyz1223\""); + h.add(HttpHeader.IF_MATCH, "\"1231323423\", \"1211211\", " + etag); + }) + .send(); checkResponseBody(method, response); - assertEquals( - "If-Match: Got no response 200 to matching ETag", - 200, - response.getStatusLine().getStatusCode()); + assertEquals("If-Match: Got no response 200 to matching ETag", 200, response.getStatus()); // now we set the special star ETag - get = getSelectMethod(method); - get.addHeader("If-Match", "*"); - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers(h -> h.add(HttpHeader.IF_MATCH, "*")) + .send(); checkResponseBody(method, response); - assertEquals( - "If-Match: Got no response 200 to star ETag", - 200, - response.getStatusLine().getStatusCode()); + assertEquals("If-Match: Got no response 200 to star ETag", 200, response.getStatus()); } @Override protected void doCacheControl(String method) throws Exception { + String url = getSelectUrl(); if ("POST".equals(method)) { - HttpRequestBase m = getSelectMethod(method); - HttpResponse response = getHttpClient().execute(m); + ContentResponse response = getHttpClient().POST(url).send(); checkResponseBody(method, response); - Header head = response.getFirstHeader("Cache-Control"); + String head = response.getHeaders().get(HttpHeader.CACHE_CONTROL); assertNull("We got a cache-control header in response to POST", head); - head = response.getFirstHeader("Expires"); + head = response.getHeaders().get(HttpHeader.EXPIRES); assertNull("We got an Expires header in response to POST", head); } else { - HttpRequestBase m = getSelectMethod(method); - HttpResponse response = getHttpClient().execute(m); + ContentResponse response = getHttpClient().newRequest(url).method(method).send(); checkResponseBody(method, response); - Header head = response.getFirstHeader("Cache-Control"); + String head = response.getHeaders().get(HttpHeader.CACHE_CONTROL); assertNotNull("We got no cache-control header", head); - head = response.getFirstHeader("Expires"); + head = response.getHeaders().get(HttpHeader.EXPIRES); assertNotNull("We got no Expires header in response", head); } } diff --git a/solr/core/src/test/org/apache/solr/servlet/CacheHeaderTestBase.java b/solr/core/src/test/org/apache/solr/servlet/CacheHeaderTestBase.java index be2cf9631465..3b6a331970bc 100644 --- a/solr/core/src/test/org/apache/solr/servlet/CacheHeaderTestBase.java +++ b/solr/core/src/test/org/apache/solr/servlet/CacheHeaderTestBase.java @@ -16,21 +16,10 @@ */ package org.apache.solr.servlet; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpHead; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.client.solrj.apache.HttpSolrClient; import org.apache.solr.util.SolrJettyTestRule; +import org.eclipse.jetty.client.ContentResponse; +import org.eclipse.jetty.client.HttpClient; import org.junit.ClassRule; import org.junit.Test; @@ -38,51 +27,36 @@ public abstract class CacheHeaderTestBase extends SolrTestCaseJ4 { @ClassRule public static SolrJettyTestRule solrTestRule = new SolrJettyTestRule(); - protected HttpRequestBase getSelectMethod(String method, String... params) { - HttpRequestBase m = null; + protected String getSelectUrl(String... params) { + StringBuilder sb = new StringBuilder(); + sb.append(solrTestRule.getBaseUrl()); + sb.append("/"); + sb.append(DEFAULT_TEST_COLLECTION_NAME); + sb.append("/select?"); - ArrayList qparams = new ArrayList<>(); if (params.length == 0) { - qparams.add(new BasicNameValuePair("q", "solr")); - qparams.add(new BasicNameValuePair("qt", "standard")); - } - for (int i = 0; i < params.length / 2; i++) { - qparams.add(new BasicNameValuePair(params[i * 2], params[i * 2 + 1])); - } - - URI uri = - URI.create( - solrTestRule.getBaseUrl() - + "/" - + DEFAULT_TEST_COLLECTION_NAME - + "/select?" - + URLEncodedUtils.format(qparams, StandardCharsets.UTF_8)); - - if ("GET".equals(method)) { - m = new HttpGet(uri); - } else if ("HEAD".equals(method)) { - m = new HttpHead(uri); - } else if ("POST".equals(method)) { - m = new HttpPost(uri); + sb.append("q=solr&qt=standard"); + } else { + for (int i = 0; i < params.length / 2; i++) { + if (i > 0) sb.append("&"); + sb.append(params[i * 2]); + sb.append("="); + sb.append(params[i * 2 + 1]); + } } - return m; + return sb.toString(); } protected HttpClient getHttpClient() { - HttpSolrClient client = (HttpSolrClient) solrTestRule.getSolrClient(); - return client.getHttpClient(); + return solrTestRule.getJetty().getSolrClient().getHttpClient(); } - protected void checkResponseBody(String method, HttpResponse resp) throws Exception { - String responseBody = ""; - - if (resp.getEntity() != null) { - responseBody = EntityUtils.toString(resp.getEntity()); - } + protected void checkResponseBody(String method, ContentResponse resp) throws Exception { + String responseBody = resp.getContentAsString(); if ("GET".equals(method)) { - switch (resp.getStatusLine().getStatusCode()) { + switch (resp.getStatus()) { case 200: assertTrue( "Response body was empty for method " + method, @@ -100,7 +74,7 @@ protected void checkResponseBody(String method, HttpResponse resp) throws Except break; default: System.err.println(responseBody); - assertEquals("Unknown request response", 0, resp.getStatusLine().getStatusCode()); + assertEquals("Unknown request response", 0, resp.getStatus()); } } if ("HEAD".equals(method)) { diff --git a/solr/core/src/test/org/apache/solr/servlet/HideStackTraceTest.java b/solr/core/src/test/org/apache/solr/servlet/HideStackTraceTest.java index 0a0986292be0..29059c742933 100644 --- a/solr/core/src/test/org/apache/solr/servlet/HideStackTraceTest.java +++ b/solr/core/src/test/org/apache/solr/servlet/HideStackTraceTest.java @@ -21,12 +21,8 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.util.EntityUtils; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.SolrTestCaseJ4.SuppressSSL; -import org.apache.solr.client.solrj.apache.HttpClientUtil; import org.apache.solr.common.util.EnvUtils; import org.apache.solr.handler.component.ResponseBuilder; import org.apache.solr.handler.component.SearchComponent; @@ -142,18 +138,13 @@ public void testHideStackTrace() throws Exception { // } final String url = solrTestRule.getBaseUrl() + "/collection1/withError?q=*:*&wt=json"; - final HttpGet get = new HttpGet(url); - var client = HttpClientUtil.createClient(null); - try (CloseableHttpResponse response = client.execute(get)) { - - assertEquals(500, response.getStatusLine().getStatusCode()); - String responseJson = EntityUtils.toString(response.getEntity()); - assertFalse(responseJson.contains("\"trace\"")); - assertFalse( - responseJson.contains("org.apache.solr.servlet.HideStackTraceTest$ErrorComponent")); - } finally { - HttpClientUtil.close(client); - } + var httpClient = solrTestRule.getJetty().getSolrClient().getHttpClient(); + var response = httpClient.GET(url); + + assertEquals(500, response.getStatus()); + String responseJson = response.getContentAsString(); + assertFalse(responseJson.contains("\"trace\"")); + assertFalse(responseJson.contains("org.apache.solr.servlet.HideStackTraceTest$ErrorComponent")); } public static class ErrorComponent extends SearchComponent { diff --git a/solr/core/src/test/org/apache/solr/servlet/NoCacheHeaderTest.java b/solr/core/src/test/org/apache/solr/servlet/NoCacheHeaderTest.java index 409367cbf1c5..2a596454a78e 100644 --- a/solr/core/src/test/org/apache/solr/servlet/NoCacheHeaderTest.java +++ b/solr/core/src/test/org/apache/solr/servlet/NoCacheHeaderTest.java @@ -17,12 +17,11 @@ package org.apache.solr.servlet; import java.nio.file.Path; -import java.util.Date; -import org.apache.http.Header; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.client.utils.DateUtils; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import org.apache.solr.common.util.SuppressForbidden; +import org.eclipse.jetty.client.ContentResponse; +import org.eclipse.jetty.http.HttpHeader; import org.junit.BeforeClass; import org.junit.Test; @@ -71,129 +70,155 @@ public void testCacheControl() throws Exception { protected void doLastModified(String method) throws Exception { // We do a first request to get the last modified // This must result in a 200 OK response - HttpRequestBase get = getSelectMethod(method); - HttpResponse response = getHttpClient().execute(get); + String url = getSelectUrl(); + ContentResponse response = getHttpClient().newRequest(url).method(method).send(); checkResponseBody(method, response); - assertEquals( - "Got no response code 200 in initial request", - 200, - response.getStatusLine().getStatusCode()); + assertEquals("Got no response code 200 in initial request", 200, response.getStatus()); - Header head = response.getFirstHeader("Last-Modified"); + String head = response.getHeaders().get(HttpHeader.LAST_MODIFIED); assertNull("We got a Last-Modified header", head); // If-Modified-Since tests - get = getSelectMethod(method); - get.addHeader("If-Modified-Since", DateUtils.formatDate(new Date())); - - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers( + h -> + h.add( + HttpHeader.IF_MODIFIED_SINCE, + DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now()))) + .send(); checkResponseBody(method, response); assertEquals( "Expected 200 with If-Modified-Since header. We should never get a 304 here", 200, - response.getStatusLine().getStatusCode()); - - get = getSelectMethod(method); - get.addHeader( - "If-Modified-Since", DateUtils.formatDate(new Date(System.currentTimeMillis() - 10000))); - response = getHttpClient().execute(get); + response.getStatus()); + + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers( + h -> + h.add( + HttpHeader.IF_MODIFIED_SINCE, + DateTimeFormatter.RFC_1123_DATE_TIME.format( + ZonedDateTime.now().minusSeconds(10)))) + .send(); checkResponseBody(method, response); assertEquals( "Expected 200 with If-Modified-Since header. We should never get a 304 here", 200, - response.getStatusLine().getStatusCode()); + response.getStatus()); // If-Unmodified-Since tests - get = getSelectMethod(method); - get.addHeader( - "If-Unmodified-Since", DateUtils.formatDate(new Date(System.currentTimeMillis() - 10000))); - - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers( + h -> + h.add( + HttpHeader.IF_UNMODIFIED_SINCE, + DateTimeFormatter.RFC_1123_DATE_TIME.format( + ZonedDateTime.now().minusSeconds(10)))) + .send(); checkResponseBody(method, response); assertEquals( "Expected 200 with If-Unmodified-Since header. We should never get a 304 here", 200, - response.getStatusLine().getStatusCode()); - - get = getSelectMethod(method); - get.addHeader("If-Unmodified-Since", DateUtils.formatDate(new Date())); - response = getHttpClient().execute(get); + response.getStatus()); + + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers( + h -> + h.add( + HttpHeader.IF_UNMODIFIED_SINCE, + DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now()))) + .send(); checkResponseBody(method, response); assertEquals( "Expected 200 with If-Unmodified-Since header. We should never get a 304 here", 200, - response.getStatusLine().getStatusCode()); + response.getStatus()); } // test ETag @Override protected void doETag(String method) throws Exception { - HttpRequestBase get = getSelectMethod(method); - HttpResponse response = getHttpClient().execute(get); + String url = getSelectUrl(); + ContentResponse response = getHttpClient().newRequest(url).method(method).send(); checkResponseBody(method, response); - assertEquals( - "Got no response code 200 in initial request", - 200, - response.getStatusLine().getStatusCode()); + assertEquals("Got no response code 200 in initial request", 200, response.getStatus()); - Header head = response.getFirstHeader("ETag"); + String head = response.getHeaders().get(HttpHeader.ETAG); assertNull("We got an ETag in the response", head); // If-None-Match tests // we set a non-matching ETag - get = getSelectMethod(method); - get.addHeader("If-None-Match", "\"xyz123456\""); - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers(h -> h.add(HttpHeader.IF_NONE_MATCH, "\"xyz123456\"")) + .send(); checkResponseBody(method, response); assertEquals( "If-None-Match: Got no response code 200 in response to non matching ETag", 200, - response.getStatusLine().getStatusCode()); + response.getStatus()); // we now set the special star ETag - get = getSelectMethod(method); - get.addHeader("If-None-Match", "*"); - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers(h -> h.add(HttpHeader.IF_NONE_MATCH, "*")) + .send(); checkResponseBody(method, response); - assertEquals( - "If-None-Match: Got no response 200 for star ETag", - 200, - response.getStatusLine().getStatusCode()); + assertEquals("If-None-Match: Got no response 200 for star ETag", 200, response.getStatus()); // If-Match tests // we set a non-matching ETag - get = getSelectMethod(method); - get.addHeader("If-Match", "\"xyz123456\""); - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers(h -> h.add(HttpHeader.IF_MATCH, "\"xyz123456\"")) + .send(); checkResponseBody(method, response); assertEquals( "If-Match: Got no response code 200 in response to non matching ETag", 200, - response.getStatusLine().getStatusCode()); + response.getStatus()); // now we set the special star ETag - get = getSelectMethod(method); - get.addHeader("If-Match", "*"); - response = getHttpClient().execute(get); + response = + getHttpClient() + .newRequest(url) + .method(method) + .headers(h -> h.add(HttpHeader.IF_MATCH, "*")) + .send(); checkResponseBody(method, response); - assertEquals( - "If-Match: Got no response 200 to star ETag", - 200, - response.getStatusLine().getStatusCode()); + assertEquals("If-Match: Got no response 200 to star ETag", 200, response.getStatus()); } @Override protected void doCacheControl(String method) throws Exception { - HttpRequestBase m = getSelectMethod(method); - HttpResponse response = getHttpClient().execute(m); + String url = getSelectUrl(); + ContentResponse response = getHttpClient().newRequest(url).method(method).send(); checkResponseBody(method, response); - Header head = response.getFirstHeader("Cache-Control"); + String head = response.getHeaders().get(HttpHeader.CACHE_CONTROL); assertNull("We got a cache-control header in response", head); - head = response.getFirstHeader("Expires"); + head = response.getHeaders().get(HttpHeader.EXPIRES); assertNull("We got an Expires header in response", head); } } diff --git a/solr/core/src/test/org/apache/solr/servlet/ResponseHeaderTest.java b/solr/core/src/test/org/apache/solr/servlet/ResponseHeaderTest.java index 37b8df1870a1..fa05e5732a46 100644 --- a/solr/core/src/test/org/apache/solr/servlet/ResponseHeaderTest.java +++ b/solr/core/src/test/org/apache/solr/servlet/ResponseHeaderTest.java @@ -16,17 +16,10 @@ */ package org.apache.solr.servlet; -import java.io.IOException; -import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import org.apache.http.Header; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.client.solrj.apache.HttpClientUtil; import org.apache.solr.handler.component.ResponseBuilder; import org.apache.solr.handler.component.SearchComponent; import org.apache.solr.util.SolrJettyTestRule; @@ -57,26 +50,17 @@ public static void beforeTest() throws Exception { } @Test - public void testHttpResponse() throws IOException { - URI uri = URI.create(solrTestRule.getBaseUrl() + "/collection1/withHeaders?q=*:*"); - HttpGet httpGet = new HttpGet(uri); - CloseableHttpClient httpClient = HttpClientUtil.createClient(null); - try { - HttpResponse response = httpClient.execute(httpGet); - Header[] headers = response.getAllHeaders(); - boolean containsWarningHeader = false; - for (Header header : headers) { - if ("Warning".equals(header.getName())) { - containsWarningHeader = true; - assertEquals("This is a test warning", header.getValue()); - break; - } - } - assertTrue("Expected header not found", containsWarningHeader); - - } finally { - HttpClientUtil.close(httpClient); + public void testHttpResponse() throws Exception { + String url = solrTestRule.getBaseUrl() + "/collection1/withHeaders?q=*:*"; + var httpClient = solrTestRule.getJetty().getSolrClient().getHttpClient(); + var response = httpClient.GET(url); + var headers = response.getHeaders(); + boolean containsWarningHeader = false; + if (headers.contains("Warning")) { + containsWarningHeader = true; + assertEquals("This is a test warning", headers.get("Warning")); } + assertTrue("Expected header not found", containsWarningHeader); } public static class ComponentThatAddsHeader extends SearchComponent { diff --git a/solr/core/src/test/org/apache/solr/servlet/SecurityHeadersTest.java b/solr/core/src/test/org/apache/solr/servlet/SecurityHeadersTest.java index b426717505d5..58c19ff6cce1 100644 --- a/solr/core/src/test/org/apache/solr/servlet/SecurityHeadersTest.java +++ b/solr/core/src/test/org/apache/solr/servlet/SecurityHeadersTest.java @@ -16,15 +16,9 @@ */ package org.apache.solr.servlet; -import java.net.URI; import java.util.Arrays; import java.util.Map; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; import org.apache.lucene.tests.util.LuceneTestCase.AwaitsFix; -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.apache.HttpSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.cloud.SolrCloudTestCase; import org.apache.solr.common.params.SolrParams; @@ -67,20 +61,20 @@ public void testHeaders() throws Exception { // it shouldn't matter what node our lone replica/core wound up on, headers should be the // same... for (JettySolrRunner jetty : cluster.getJettySolrRunners()) { - try (SolrClient solrClient = jetty.newClient()) { - final HttpClient client = ((HttpSolrClient) solrClient).getHttpClient(); + var httpClient = jetty.getSolrClient().getHttpClient(); - // path shouldn't matter -- even if bogus / 404 - for (String path : Arrays.asList("/select", "/bogus")) { - final HttpResponse resp = - client.execute( - new HttpGet(URI.create(jetty.getBaseUrl().toString() + "/" + COLLECTION + path))); + // path shouldn't matter -- even if bogus / 404 + for (String path : Arrays.asList("/select", "/bogus")) { + var resp = httpClient.GET(jetty.getBaseUrl().toString() + "/" + COLLECTION + path); - for (Map.Entry entry : EXPECTED_HEADERS) { - // these exact arrays (of 1 element each) should be *ALL* of the header instances... - // no more, no less. - assertEquals(entry.getValue(), resp.getHeaders(entry.getKey())); - } + for (Map.Entry entry : EXPECTED_HEADERS) { + // these exact arrays (of 1 element each) should be *ALL* of the header instances... + // no more, no less. + String[] expectedValues = entry.getValue(); + String headerName = entry.getKey(); + var actualHeaders = resp.getHeaders().getValuesList(headerName); + assertEquals( + "Header " + headerName + " mismatch", Arrays.asList(expectedValues), actualHeaders); } } } diff --git a/solr/modules/jwt-auth/build.gradle b/solr/modules/jwt-auth/build.gradle index 80cb694fb3ac..89f4f1a4ac71 100644 --- a/solr/modules/jwt-auth/build.gradle +++ b/solr/modules/jwt-auth/build.gradle @@ -66,6 +66,4 @@ dependencies { testImplementation libs.squareup.okhttp3.mockwebserver testImplementation libs.squareup.okhttp3.okhttp testRuntimeOnly libs.netty.codechttp - testImplementation libs.apache.httpcomponents.httpclient - testImplementation libs.apache.httpcomponents.httpcore } diff --git a/solr/modules/jwt-auth/gradle.lockfile b/solr/modules/jwt-auth/gradle.lockfile index 519c53f94d5d..a723e721364a 100644 --- a/solr/modules/jwt-auth/gradle.lockfile +++ b/solr/modules/jwt-auth/gradle.lockfile @@ -41,7 +41,7 @@ com.squareup.okio:okio-jvm:3.16.0=jarValidation,testCompileClasspath,testRuntime com.squareup.okio:okio:3.16.0=jarValidation,testCompileClasspath,testRuntimeClasspath com.tdunning:t-digest:3.3=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-cli:commons-cli:1.10.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -commons-codec:commons-codec:1.19.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath +commons-codec:commons-codec:1.19.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-io:commons-io:2.20.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath @@ -100,8 +100,8 @@ org.apache.commons:commons-math3:3.6.1=jarValidation,runtimeClasspath,runtimeLib org.apache.curator:curator-client:5.9.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath org.apache.curator:curator-framework:5.9.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath org.apache.curator:curator-test:5.9.0=jarValidation,testRuntimeClasspath -org.apache.httpcomponents:httpclient:4.5.14=jarValidation,testCompileClasspath,testRuntimeClasspath -org.apache.httpcomponents:httpcore:4.4.16=jarValidation,testCompileClasspath,testRuntimeClasspath +org.apache.httpcomponents:httpclient:4.5.14=jarValidation,testRuntimeClasspath +org.apache.httpcomponents:httpcore:4.4.16=jarValidation,testRuntimeClasspath org.apache.httpcomponents:httpmime:4.5.14=jarValidation,testRuntimeClasspath org.apache.logging.log4j:log4j-1.2-api:2.25.3=solrPlatformLibs org.apache.logging.log4j:log4j-api:2.25.3=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath diff --git a/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginIntegrationTest.java b/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginIntegrationTest.java index 22f0850f70fa..d480bd7ead6a 100644 --- a/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginIntegrationTest.java +++ b/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginIntegrationTest.java @@ -48,16 +48,8 @@ import no.nav.security.mock.oauth2.http.MockWebServerWrapper; import no.nav.security.mock.oauth2.token.DefaultOAuth2TokenCallback; import okhttp3.mockwebserver.MockWebServer; -import org.apache.http.HttpHeaders; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.entity.ContentType; -import org.apache.http.impl.client.CloseableHttpClient; import org.apache.lucene.tests.mockfile.FilterPath; import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.client.solrj.apache.HttpClientUtil; import org.apache.solr.cloud.MiniSolrCloudCluster; import org.apache.solr.cloud.SolrCloudAuthTestCase; import org.apache.solr.common.SolrException; @@ -68,6 +60,8 @@ import org.apache.solr.util.CryptoKeys; import org.apache.solr.util.RTimer; import org.apache.solr.util.TimeOut; +import org.eclipse.jetty.client.BytesRequestContent; +import org.eclipse.jetty.client.HttpClient; import org.jose4j.jwk.PublicJsonWebKey; import org.jose4j.jwk.RsaJsonWebKey; import org.jose4j.jwk.RsaJwkGenerator; @@ -216,8 +210,10 @@ public void testMetrics() throws Exception { if (isUseV2Api) { authcPrefix = "/____v2/cluster/security/authentication"; } - String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString(); - CloseableHttpClient cl = HttpClientUtil.createClient(null); + + JettySolrRunner randomJetty = cluster.getRandomJetty(random()); + String baseUrl = randomJetty.getBaseUrl().toString(); + var httpClient = randomJetty.getSolrClient().getHttpClient(); String COLLECTION = "jwtColl"; createCollection(cluster, COLLECTION); @@ -225,21 +221,23 @@ public void testMetrics() throws Exception { // Missing token getAndFail(baseUrl + "/" + COLLECTION + "/query?q=*:*", null); assertAuthMetricsMinimums(2, 1, 0, 0, 1, 0); - executeCommand(baseUrl + authcPrefix, cl, "{set-property : { blockUnknown: false}}", jws); + executeCommand( + httpClient, baseUrl + authcPrefix, "{set-property : { blockUnknown: false}}", jws); verifySecurityStatus( - cl, + httpClient, baseUrl + authcPrefix, "authentication/blockUnknown", "false", 20, getBearerAuthHeader(jws)); // Pass through - verifySecurityStatus(cl, baseUrl + "/admin/info/key", "key", NOT_NULL_PREDICATE, 20); + verifySecurityStatus(httpClient, baseUrl + "/admin/info/key", "key", NOT_NULL_PREDICATE, 20); // Now succeeds since blockUnknown=false get(baseUrl + "/" + COLLECTION + "/query?q=*:*", null); - executeCommand(baseUrl + authcPrefix, cl, "{set-property : { blockUnknown: true}}", null); + executeCommand( + httpClient, baseUrl + authcPrefix, "{set-property : { blockUnknown: true}}", null); verifySecurityStatus( - cl, + httpClient, baseUrl + authcPrefix, "authentication/blockUnknown", "true", @@ -287,8 +285,6 @@ public void testMetrics() throws Exception { .intValue()); assertAuthMetricsMinimums(11, 11, 0, 0, 0, 0); assertPkiAuthMetricsMinimums(4, 4, 0, 0, 0, 0); - - HttpClientUtil.close(cl); } /** @@ -491,7 +487,7 @@ private Pair post(String url, String json, String token) throws URL createUrl = URI.create(url).toURL(); HttpURLConnection con = (HttpURLConnection) createUrl.openConnection(); con.setRequestMethod("POST"); - con.setRequestProperty(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType()); + con.setRequestProperty("Content-Type", "application/json"); if (token != null) con.setRequestProperty("Authorization", "Bearer " + token); con.setDoOutput(true); @@ -526,8 +522,8 @@ private void createCollection(MiniSolrCloudCluster myCluster, String collectionN myCluster.waitForActiveCollection(collectionName, 2, 2); } - private void executeCommand(String url, HttpClient cl, String payload, JsonWebSignature jws) - throws Exception { + private void executeCommand( + HttpClient httpClient, String url, String payload, JsonWebSignature jws) throws Exception { // HACK: work around for SOLR-13464... // @@ -537,18 +533,17 @@ private void executeCommand(String url, HttpClient cl, String payload, JsonWebSi final Set> initialPlugins = getAuthPluginsInUseForCluster(url).entrySet(); - HttpPost httpPost; - HttpResponse r; - httpPost = new HttpPost(url); - if (jws != null) setAuthorizationHeader(httpPost, "Bearer " + jws.getCompactSerialization()); - httpPost.setEntity(new ByteArrayEntity(payload.getBytes(UTF_8))); - httpPost.addHeader("Content-Type", "application/json; charset=UTF-8"); - r = cl.execute(httpPost); - String response = new String(r.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8); - assertEquals( - "Non-200 response code. Response was " + response, 200, r.getStatusLine().getStatusCode()); + String authHeaderValue = jws != null ? "Bearer " + jws.getCompactSerialization() : null; + var rsp = + httpClient + .POST(url) + .headers(h1 -> h1.add("Authorization", authHeaderValue)) + .body( + new BytesRequestContent("application/json; charset=UTF-8", payload.getBytes(UTF_8))) + .send(); + String response = rsp.getContentAsString(); + assertEquals("Non-200 response code. Response was " + response, 200, rsp.getStatus()); assertFalse("Response contained errors: " + response, response.contains("errorMessages")); - HttpClientUtil.consumeFully(r.getEntity()); // HACK (continued)... final TimeOut timeout = new TimeOut(30, TimeUnit.SECONDS, TimeSource.NANO_TIME); diff --git a/solr/solrj/build.gradle b/solr/solrj/build.gradle index fbf02869a2b6..f893d21bcab6 100644 --- a/solr/solrj/build.gradle +++ b/solr/solrj/build.gradle @@ -37,9 +37,6 @@ dependencies { compileOnly libs.stephenc.jcip.annotations - testImplementation libs.apache.httpcomponents.httpclient - testImplementation libs.apache.httpcomponents.httpcore - testImplementation project(':solr:test-framework') testImplementation project(':solr:core') testImplementation project(':solr:solrj') diff --git a/solr/solrj/gradle.lockfile b/solr/solrj/gradle.lockfile index 363bc0de923d..382aa1cce0b4 100644 --- a/solr/solrj/gradle.lockfile +++ b/solr/solrj/gradle.lockfile @@ -37,7 +37,7 @@ com.j256.simplemagic:simplemagic:1.17=jarValidation,testRuntimeClasspath com.jayway.jsonpath:json-path:2.9.0=jarValidation,testRuntimeClasspath com.tdunning:t-digest:3.3=jarValidation,testRuntimeClasspath commons-cli:commons-cli:1.10.0=jarValidation,testRuntimeClasspath -commons-codec:commons-codec:1.19.0=jarValidation,testCompileClasspath,testRuntimeClasspath +commons-codec:commons-codec:1.19.0=jarValidation,testRuntimeClasspath commons-io:commons-io:2.20.0=jarValidation,testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,testRuntimeClasspath @@ -89,8 +89,8 @@ org.apache.commons:commons-math3:3.6.1=jarValidation,testRuntimeClasspath org.apache.curator:curator-client:5.9.0=jarValidation,testCompileClasspath,testRuntimeClasspath org.apache.curator:curator-framework:5.9.0=jarValidation,testCompileClasspath,testRuntimeClasspath org.apache.curator:curator-test:5.9.0=jarValidation,testRuntimeClasspath -org.apache.httpcomponents:httpclient:4.5.14=jarValidation,testCompileClasspath,testRuntimeClasspath -org.apache.httpcomponents:httpcore:4.4.16=jarValidation,testCompileClasspath,testRuntimeClasspath +org.apache.httpcomponents:httpclient:4.5.14=jarValidation,testRuntimeClasspath +org.apache.httpcomponents:httpcore:4.4.16=jarValidation,testRuntimeClasspath org.apache.httpcomponents:httpmime:4.5.14=jarValidation,testRuntimeClasspath org.apache.logging.log4j:log4j-api:2.25.3=jarValidation,testRuntimeClasspath org.apache.logging.log4j:log4j-core:2.25.3=jarValidation,testRuntimeClasspath diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java index 4b0a1f286bed..50cf5879a8f0 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java @@ -17,6 +17,7 @@ package org.apache.solr.client.solrj; import static org.apache.solr.common.params.UpdateParams.ASSUME_CONTENT_TYPE; +import static org.apache.solr.common.util.Utils.fromJSONString; import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.core.StringContains.containsString; @@ -50,6 +51,7 @@ import org.apache.solr.client.solrj.request.AbstractUpdateRequest; import org.apache.solr.client.solrj.request.AbstractUpdateRequest.ACTION; import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest; +import org.apache.solr.client.solrj.request.GenericSolrRequest; import org.apache.solr.client.solrj.request.LukeRequest; import org.apache.solr.client.solrj.request.MultiContentWriterRequest; import org.apache.solr.client.solrj.request.QueryRequest; @@ -1023,6 +1025,39 @@ public void testMultiContentStreamRequest() throws Exception { assertEquals(5, rsp.getResults().getNumFound()); } + @Test + public void testArbitraryJsonIndexing() throws Exception { + try (SolrClient client = getSolrClient()) { + client.deleteByQuery("*:*"); + client.commit(); + assertNumFound("*:*", 0); // make sure it got in + + // two docs, one with uniqueKey, another without it + String json = "{\"id\":\"abc1\", \"name\": \"name1\"} {\"name\" : \"name2\"}"; + var request = + new GenericSolrRequest( + SolrRequest.METHOD.POST, "/update/json/docs", SolrRequest.SolrRequestType.UPDATE) + .setRequiresCollection(true) + .withContent(json.getBytes(StandardCharsets.UTF_8), "application/json"); + client.request(request); + client.commit(); + QueryResponse rsp = getSolrClient().query(new SolrQuery("*:*")); + assertEquals(2, rsp.getResults().getNumFound()); + + SolrDocument doc = rsp.getResults().get(0); + String src = (String) doc.getFieldValue("_src_"); + @SuppressWarnings({"rawtypes"}) + Map m = (Map) fromJSONString(src); + assertEquals("abc1", m.get("id")); + assertEquals("name1", m.get("name")); + + doc = rsp.getResults().get(1); + src = (String) doc.getFieldValue("_src_"); + m = (Map) fromJSONString(src); + assertEquals("name2", m.get("name")); + } + } + @Test public void testLukeHandler() throws Exception { SolrClient client = getSolrClient(); diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExceptionTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExceptionTest.java deleted file mode 100644 index 5189fdb85770..000000000000 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExceptionTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.solr.client.solrj; - -import java.util.concurrent.TimeUnit; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.solr.SolrTestCase; -import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.client.solrj.apache.HttpClientUtil; -import org.apache.solr.client.solrj.apache.HttpSolrClient; -import org.apache.solr.client.solrj.request.SolrQuery; -import org.junit.Test; - -/** - * @since solr 1.3 - */ -public class SolrExceptionTest extends SolrTestCase { - - @Test - public void testSolrException() throws Throwable { - // test a connection to a solr server that probably doesn't exist - // this is a very simple test and most of the test should be considered verified - // if the compiler won't let you by without the try/catch - boolean gotExpectedError = false; - CloseableHttpClient httpClient = null; - try { - // switched to a local address to avoid going out on the net, ns lookup issues, etc. - // set a 1ms timeout to let the connection fail faster. - httpClient = HttpClientUtil.createClient(null); - try (SolrClient client = - new HttpSolrClient.Builder("http://" + SolrTestCaseJ4.DEAD_HOST_1 + "/solr/") - .withHttpClient(httpClient) - .withConnectionTimeout(1, TimeUnit.MILLISECONDS) - .build()) { - SolrQuery query = new SolrQuery("test123"); - client.query(query); - } - httpClient.close(); - } catch (SolrServerException sse) { - gotExpectedError = true; - /* - assertTrue(UnknownHostException.class == sse.getRootCause().getClass() - //If one is using OpenDNS, then you don't get UnknownHostException, instead you get back that the query couldn't execute - || (sse.getRootCause().getClass() == SolrException.class && ((SolrException) sse.getRootCause()).code() == 302 && sse.getMessage().equals("Error executing query"))); - */ - } finally { - if (httpClient != null) HttpClientUtil.close(httpClient); - } - assertTrue(gotExpectedError); - } -} 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 94565fc756b9..a2d5dfc18ec0 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 @@ -16,7 +16,6 @@ */ package org.apache.solr.client.solrj; -import java.io.ByteArrayInputStream; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -26,25 +25,22 @@ import java.util.List; import java.util.Properties; import org.apache.commons.io.file.PathUtils; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.InputStreamEntity; -import org.apache.solr.client.solrj.apache.HttpClientUtil; -import org.apache.solr.client.solrj.apache.HttpSolrClient; +import org.apache.solr.client.solrj.jetty.HttpJettySolrClient; import org.apache.solr.client.solrj.request.JavaBinRequestWriter; import org.apache.solr.client.solrj.response.JavaBinResponseParser; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrDocument; import org.apache.solr.util.ExternalPaths; +import org.eclipse.jetty.client.ContentResponse; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.StringRequestContent; import org.junit.BeforeClass; import org.junit.Test; public class SolrSchemalessExampleTest extends SolrExampleTestsBase { protected HttpClient getHttpClient() { - HttpSolrClient client = (HttpSolrClient) getSolrClient(); - return client.getHttpClient(); + return solrTestRule.getJetty().getSolrClient().getHttpClient(); } @BeforeClass @@ -80,15 +76,12 @@ public void testArbitraryJsonIndexing() throws Exception { // two docs, one with uniqueKey, another without it String json = "{\"id\":\"abc1\", \"name\": \"name1\"} {\"name\" : \"name2\"}"; HttpClient httpClient = getHttpClient(); - HttpPost post = - new HttpPost(solrTestRule.getBaseUrl() + "/" + DEFAULT_TEST_CORENAME + "/update/json/docs"); - post.setHeader("Content-Type", "application/json"); - post.setEntity( - new InputStreamEntity(new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)), -1)); - HttpResponse response = - httpClient.execute(post, HttpClientUtil.createNewHttpClientRequestContext()); - HttpClientUtil.consumeFully(response.getEntity()); - assertEquals(200, response.getStatusLine().getStatusCode()); + ContentResponse response = + httpClient + .POST(solrTestRule.getBaseUrl() + "/" + DEFAULT_TEST_CORENAME + "/update/json/docs") + .body(new StringRequestContent("application/json", json)) + .send(); + assertEquals(200, response.getStatus()); client.commit(); assertNumFound("*:*", 2); } @@ -109,13 +102,12 @@ public void testFieldMutating() throws Exception { + "{\"p.q\" : \"name\"}" + "{\"a&b\" : \"name\"}"; HttpClient httpClient = getHttpClient(); - HttpPost post = - new HttpPost(solrTestRule.getBaseUrl() + "/" + DEFAULT_TEST_CORENAME + "/update/json/docs"); - post.setHeader("Content-Type", "application/json"); - post.setEntity( - new InputStreamEntity(new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)), -1)); - HttpResponse response = httpClient.execute(post); - assertEquals(200, response.getStatusLine().getStatusCode()); + ContentResponse response = + httpClient + .POST(solrTestRule.getBaseUrl() + "/" + DEFAULT_TEST_CORENAME + "/update/json/docs") + .body(new StringRequestContent("application/json", json)) + .send(); + assertEquals(200, response.getStatus()); client.commit(); List expected = Arrays.asList("name_one", "name__two", "first-second", "a_b", "p_q", "p.q", "x_y"); @@ -129,10 +121,9 @@ public void testFieldMutating() throws Exception { @Override public SolrClient createNewSolrClient() { - HttpSolrClient.Builder httpSolrClientBuilder = - new HttpSolrClient.Builder(solrTestRule.getBaseUrl()) - .withDefaultCollection(DEFAULT_TEST_COLLECTION_NAME) - .allowMultiPartPost(random().nextBoolean()); + var httpSolrClientBuilder = + new HttpJettySolrClient.Builder(solrTestRule.getBaseUrl()) + .withDefaultCollection(DEFAULT_TEST_COLLECTION_NAME); if (random().nextBoolean()) { httpSolrClientBuilder .withRequestWriter(new JavaBinRequestWriter()) diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/SolrExampleJettyTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/SolrExampleJettyTest.java index a35cda753111..d19350e17d60 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/SolrExampleJettyTest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/SolrExampleJettyTest.java @@ -16,89 +16,19 @@ */ package org.apache.solr.client.solrj.embedded; -import static org.apache.solr.common.util.Utils.fromJSONString; - -import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; -import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.InputStreamEntity; import org.apache.solr.SolrTestCaseJ4.SuppressSSL; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrExampleTests; -import org.apache.solr.client.solrj.apache.HttpClientUtil; -import org.apache.solr.client.solrj.apache.HttpSolrClient; import org.apache.solr.client.solrj.request.SolrQuery; import org.apache.solr.client.solrj.response.QueryResponse; -import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrInputDocument; import org.junit.Test; -/** - * TODO? perhaps use: http://docs.codehaus.org/display/JETTY/ServletTester rather then open a real - * connection? - */ @SuppressSSL(bugUrl = "https://issues.apache.org/jira/browse/SOLR-5776") public class SolrExampleJettyTest extends SolrExampleTests { - @Test - public void testBadSetup() { - String url = "http" + (isSSLMode() ? "s" : "") + "://127.0.0.1/?core=xxx"; - // This test does NOT fail for HttpJettySolrClient - expectThrows(Exception.class, () -> new HttpSolrClient.Builder(url).build()); - } - - @Test - public void testArbitraryJsonIndexing() throws Exception { - // For making raw requests... - HttpClient httpClient = HttpClientUtil.createClient(null); - try (SolrClient client = getSolrClient()) { - client.deleteByQuery("*:*"); - client.commit(); - assertNumFound("*:*", 0); // make sure it got in - - // two docs, one with uniqueKey, another without it - String json = "{\"id\":\"abc1\", \"name\": \"name1\"} {\"name\" : \"name2\"}"; - HttpPost post = - new HttpPost( - getRandomizedUpdateUri(solrTestRule.getBaseUrl() + "/" + DEFAULT_TEST_CORENAME)); - post.setHeader("Content-Type", "application/json"); - post.setEntity( - new InputStreamEntity( - new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)), -1)); - HttpResponse response = - httpClient.execute(post, HttpClientUtil.createNewHttpClientRequestContext()); - assertEquals(200, response.getStatusLine().getStatusCode()); - client.commit(); - QueryResponse rsp = getSolrClient().query(new SolrQuery("*:*")); - assertEquals(2, rsp.getResults().getNumFound()); - - SolrDocument doc = rsp.getResults().get(0); - String src = (String) doc.getFieldValue("_src_"); - @SuppressWarnings({"rawtypes"}) - Map m = (Map) fromJSONString(src); - assertEquals("abc1", m.get("id")); - assertEquals("name1", m.get("name")); - - doc = rsp.getResults().get(1); - src = (String) doc.getFieldValue("_src_"); - m = (Map) fromJSONString(src); - assertEquals("name2", m.get("name")); - } finally { - HttpClientUtil.close(httpClient); - } - } - - private String getRandomizedUpdateUri(String baseUrl) { - return random().nextBoolean() - ? baseUrl.replace("/collection1", "/____v2/cores/collection1/update") - : baseUrl + "/update/json/docs"; - } - @Test public void testUtf8PerfDegradation() throws Exception { SolrInputDocument doc = new SolrInputDocument(); 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 e80c60242a7f..87ebb9f5b142 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 @@ -36,14 +36,12 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeoutException; -import org.apache.http.impl.client.CloseableHttpClient; import org.apache.lucene.tests.util.TestUtil; import org.apache.solr.client.solrj.RemoteSolrException; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; -import org.apache.solr.client.solrj.apache.HttpClientUtil; +import org.apache.solr.client.solrj.jetty.CloudJettySolrClient; import org.apache.solr.client.solrj.jetty.HttpJettySolrClient; import org.apache.solr.client.solrj.request.AbstractUpdateRequest; import org.apache.solr.client.solrj.request.CollectionAdminRequest; @@ -923,18 +921,16 @@ public void testWrongZkChrootTest() throws IOException { } @Test - public void customHttpClientTest() throws IOException { - CloseableHttpClient client = HttpClientUtil.createClient(null); - try (CloudSolrClient solrClient = - new RandomizingCloudSolrClientBuilder( - Collections.singletonList(cluster.getZkServer().getZkAddress()), Optional.empty()) - .withHttpClient(client) - .build()) { - - assertSame(((CloudLegacySolrClient) solrClient).getLbClient().getHttpClient(), client); - - } finally { - HttpClientUtil.close(client); + public void customHttpClientTest() throws Exception { + String baseUrl = cluster.getJettySolrRunners().get(0).getBaseUrl().toString(); + try (HttpJettySolrClient httpClient = new HttpJettySolrClient.Builder(baseUrl).build()) { + try (CloudSolrClient cloudClient = + new CloudJettySolrClient.Builder(Collections.singletonList(baseUrl)) + .withHttpClient(httpClient) + .build()) { + // Verify the CloudJettySolrClient uses the provided HttpJettySolrClient + assertSame(((CloudJettySolrClient) cloudClient).getHttpClient(), httpClient); + } } } diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientCacheTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientCacheTest.java index 55d170ce6529..521bfd0f0bef 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientCacheTest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientCacheTest.java @@ -44,7 +44,6 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.function.Supplier; -import org.apache.http.NoHttpResponseException; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; @@ -120,7 +119,7 @@ public DocCollection get() { return new SocketException("TEST"); } if (i == 3) { - return new NoHttpResponseException("TEST"); + return new ConnectException("TEST"); } return okResponse; }); diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientTestBase.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientTestBase.java index b9d76b80133c..ad1228662737 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientTestBase.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientTestBase.java @@ -663,4 +663,22 @@ protected void testAsyncExceptionBase() throws Exception { assertTrue(ee.getMessage(), ee.getMessage().contains("mime type")); } } + + // formerly SolrExceptionTest.testSolrException + public void testConnectionToNonExistentServer() throws Exception { + // test a connection to a solr server that probably doesn't exist + // this is a very simple test and most of the test should be considered verified + // if the compiler won't let you by without the try/catch + + // test a connection to a solr server that probably doesn't exist + // set a 1ms timeout to let the connection fail faster + boolean gotExpectedError = false; + try (var client = builder("http://" + DEAD_HOST_1 + "/solr/", 1, 1000).build()) { + SolrQuery query = new SolrQuery("test123"); + client.query(query); + } catch (SolrServerException sse) { + gotExpectedError = true; + } + assertTrue(gotExpectedError); + } } diff --git a/solr/test-framework/build.gradle b/solr/test-framework/build.gradle index 181c809e8199..4833ffd1603c 100644 --- a/solr/test-framework/build.gradle +++ b/solr/test-framework/build.gradle @@ -79,6 +79,8 @@ dependencies { implementation libs.jakarta.servlet.api implementation libs.eclipse.jetty.server + implementation libs.eclipse.jetty.client + implementation libs.eclipse.jetty.http implementation libs.eclipse.jetty.session api libs.eclipse.jetty.ee10.servlet implementation libs.eclipse.jetty.util @@ -103,6 +105,4 @@ dependencies { exclude group: "commons-codec", module: "commons-codec" exclude group: "commons-logging", module: "commons-logging" }) - implementation libs.apache.httpcomponents.httpclient - implementation libs.apache.httpcomponents.httpcore } diff --git a/solr/test-framework/gradle.lockfile b/solr/test-framework/gradle.lockfile index 18e2d4850626..f16734e7b021 100644 --- a/solr/test-framework/gradle.lockfile +++ b/solr/test-framework/gradle.lockfile @@ -125,7 +125,7 @@ org.eclipse.jetty:jetty-alpn-client:12.0.27=apiHelper,compileClasspath,jarValida org.eclipse.jetty:jetty-alpn-java-client:12.0.27=apiHelper,jarValidation,runtimeClasspath,testRuntimeClasspath org.eclipse.jetty:jetty-alpn-java-server:12.0.27=jarValidation,runtimeClasspath,testRuntimeClasspath org.eclipse.jetty:jetty-alpn-server:12.0.27=compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-client:12.0.27=apiHelper,jarValidation,runtimeClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-client:12.0.27=apiHelper,compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath org.eclipse.jetty:jetty-http:12.0.27=apiHelper,compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath org.eclipse.jetty:jetty-io:12.0.27=apiHelper,compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath org.eclipse.jetty:jetty-rewrite:12.0.27=compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 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 3ff7e74aaa29..ca7677a7e787 100644 --- a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java +++ b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java @@ -69,7 +69,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import javax.xml.xpath.XPathExpressionException; -import org.apache.http.client.HttpClient; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.tests.analysis.MockAnalyzer; import org.apache.lucene.tests.analysis.MockTokenizer; @@ -2559,18 +2558,6 @@ private void randomizeCloudSolrClient() { } } - /** - * This method creates a HttpClient from a URL. - * - *

WARNING: if you use this method, the HttpClient returned is tracked by - * ObjectReleaseTracker. Your test will fail if you do not pass the HttpClient - * to {@link HttpClientUtil#close(HttpClient)} when you are done with it. - */ - @Deprecated // We are migrating away from Apache HttpClient. - public static HttpClient getHttpClient(String url) { - return new HttpSolrClient.Builder(url).build().getHttpClient(); - } - /** * This method creates a basic HttpSolrClient. Tests that want to control the creation process * should use the {@link org.apache.solr.client.solrj.jetty.HttpJettySolrClient.Builder} class diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudAuthTestCase.java b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudAuthTestCase.java index 2555bdf31026..afbe6becb8c0 100644 --- a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudAuthTestCase.java +++ b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudAuthTestCase.java @@ -24,7 +24,6 @@ import io.prometheus.metrics.model.snapshots.DataPointSnapshot; import io.prometheus.metrics.model.snapshots.HistogramSnapshot; import io.prometheus.metrics.model.snapshots.Labels; -import java.io.IOException; import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.Arrays; @@ -35,13 +34,6 @@ import java.util.Map; import java.util.Objects; import java.util.function.Predicate; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.message.AbstractHttpMessage; -import org.apache.http.message.BasicHeader; -import org.apache.http.util.EntityUtils; -import org.apache.solr.client.solrj.apache.HttpClientUtil; import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.util.Utils; import org.apache.solr.core.CoreContainer; @@ -50,6 +42,7 @@ import org.apache.solr.security.PKIAuthenticationPlugin; import org.apache.solr.util.SolrMetricTestUtils; import org.apache.solr.util.TimeOut; +import org.eclipse.jetty.client.HttpClient; import org.junit.BeforeClass; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -294,12 +287,13 @@ private static Map getMetricValues( } public static void verifySecurityStatus( - HttpClient cl, String url, String objPath, Object expected, int count) throws Exception { - verifySecurityStatus(cl, url, objPath, expected, count, (String) null); + HttpClient httpClient, String url, String objPath, Object expected, int count) + throws Exception { + verifySecurityStatus(httpClient, url, objPath, expected, count, (String) null); } public static void verifySecurityStatus( - HttpClient cl, + HttpClient httpClient, String url, String objPath, Object expected, @@ -307,29 +301,30 @@ public static void verifySecurityStatus( String user, String pwd) throws Exception { - verifySecurityStatus(cl, url, objPath, expected, count, makeBasicAuthHeader(user, pwd)); + verifySecurityStatus(httpClient, url, objPath, expected, count, makeBasicAuthHeader(user, pwd)); } @SuppressWarnings({"unchecked", "rawtypes"}) protected static void verifySecurityStatus( - HttpClient cl, String url, String objPath, Object expected, int count, String authHeader) - throws IOException, InterruptedException { + HttpClient httpClient, + String url, + String objPath, + Object expected, + int count, + String authHeader) + throws Exception { boolean success = false; String s = null; - List hierarchy = StrUtils.splitSmart(objPath, '/'); for (int i = 0; i < count; i++) { - HttpGet get = new HttpGet(url); - if (authHeader != null) setAuthorizationHeader(get, authHeader); - HttpResponse rsp = cl.execute(get); - s = EntityUtils.toString(rsp.getEntity()); + var rsp = httpClient.newRequest(url).headers(h -> h.add("Authorization", authHeader)).send(); + s = rsp.getContentAsString(); Map m = null; try { m = (Map) Utils.fromJSONString(s); } catch (Exception e) { fail("Invalid json " + s); } - HttpClientUtil.consumeFully(rsp.getEntity()); - Object actual = Utils.getObjectByPath(m, true, hierarchy); + Object actual = Utils.getObjectByPath(m, true, StrUtils.splitSmart(objPath, '/')); if (expected instanceof Predicate predicate) { if (predicate.test(actual)) { success = true; @@ -339,21 +334,18 @@ protected static void verifySecurityStatus( success = true; break; } + Thread.sleep(50); } assertTrue("No match for " + objPath + " = " + expected + ", full response = " + s, success); } protected static String makeBasicAuthHeader(String user, String pwd) { + if (user == null && pwd == null) return null; String userPass = user + ":" + pwd; return "Basic " + Base64.getEncoder().encodeToString(userPass.getBytes(UTF_8)); } - public static void setAuthorizationHeader(AbstractHttpMessage httpMsg, String headerString) { - httpMsg.setHeader(new BasicHeader("Authorization", headerString)); - log.info("Added Authorization Header {}", headerString); - } - /** * This helper method can be used by tests to monitor the current state of either * "authentication" or "authorization" plugins in use each node of the current diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java index b8512f56317d..6f14fda6d150 100644 --- a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java +++ b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java @@ -43,11 +43,8 @@ import org.apache.lucene.tests.util.LuceneTestCase; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.api.model.CoreStatusResponse; -import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.apache.CloudLegacySolrClient; -import org.apache.solr.client.solrj.apache.HttpSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.CoreAdminRequest; import org.apache.solr.common.cloud.CollectionStatePredicate; @@ -408,13 +405,8 @@ protected static Replica getRandomReplica(Slice slice, Predicate matchP */ protected static CoreStatusResponse.SingleCoreData getCoreStatus(Replica replica) throws IOException, SolrServerException { - JettySolrRunner jetty = cluster.getReplicaJetty(replica); - try (SolrClient client = - new HttpSolrClient.Builder(jetty.getBaseUrl().toString()) - .withHttpClient(((CloudLegacySolrClient) cluster.getSolrClient()).getHttpClient()) - .build()) { - return CoreAdminRequest.getCoreStatus(replica.getCoreName(), client); - } + var solrClient = cluster.getReplicaJetty(replica).getSolrClient(); + return CoreAdminRequest.getCoreStatus(replica.getCoreName(), solrClient); } protected CollectionAdminRequest.RequestStatusResponse waitForAsyncClusterRequest(