From 78b932ad63fb408d635a475fb05a61e829a4ab90 Mon Sep 17 00:00:00 2001 From: David Smiley Date: Thu, 2 Apr 2026 00:25:13 -0400 Subject: [PATCH 1/3] Remove tests for HttpSolrClient etc. Removes package org.apache.solr.client.solrj.apache in solr-test-framework's tests. They are deprecated anyway. Removing this code now helps us remove HttpSolrClient itself and do other migrations without needless work here. --- solr/test-framework/build.gradle | 2 - .../solrj/apache/BasicHttpSolrClientTest.java | 762 ----------- .../apache/CloudSolrClientBadInputTest.java | 66 - .../apache/CloudSolrClientBuilderTest.java | 121 -- .../CloudSolrClientMultiConstructorTest.java | 120 -- .../apache/CloudSolrClientRetryTest.java | 75 -- .../solrj/apache/CloudSolrClientTest.java | 1164 ----------------- ...oncurrentUpdateSolrClientBadInputTest.java | 116 -- ...ConcurrentUpdateSolrClientBuilderTest.java | 87 -- ...ntUpdateSolrClientMultiCollectionTest.java | 98 -- .../ConcurrentUpdateSolrClientTest.java | 389 ------ .../solrj/apache/ConnectionReuseTest.java | 237 ---- .../solrj/apache/HttpClientUtilTest.java | 232 ---- .../apache/HttpSolrClientBuilderTest.java | 97 -- .../apache/HttpSolrClientConPoolTest.java | 201 --- .../HttpSolrClientSSLAuthConPoolTest.java | 36 - .../apache/LBHttpSolrClientBuilderTest.java | 93 -- .../solrj/apache/LBHttpSolrClientTest.java | 69 - .../apache/SolrPortAwareCookieSpecTest.java | 153 --- 19 files changed, 4118 deletions(-) delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/BasicHttpSolrClientTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientBadInputTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientBuilderTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientMultiConstructorTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientRetryTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientBadInputTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientBuilderTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientMultiCollectionTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConnectionReuseTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpClientUtilTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpSolrClientBuilderTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpSolrClientConPoolTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpSolrClientSSLAuthConPoolTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/LBHttpSolrClientBuilderTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/LBHttpSolrClientTest.java delete mode 100644 solr/test-framework/src/test/org/apache/solr/client/solrj/apache/SolrPortAwareCookieSpecTest.java diff --git a/solr/test-framework/build.gradle b/solr/test-framework/build.gradle index a7bac2b63bd8..181c809e8199 100644 --- a/solr/test-framework/build.gradle +++ b/solr/test-framework/build.gradle @@ -105,6 +105,4 @@ dependencies { }) implementation libs.apache.httpcomponents.httpclient implementation libs.apache.httpcomponents.httpcore - - testImplementation libs.apache.commons.lang3 } diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/BasicHttpSolrClientTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/BasicHttpSolrClientTest.java deleted file mode 100644 index c7367bab551c..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/BasicHttpSolrClientTest.java +++ /dev/null @@ -1,762 +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.apache; - -import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP; - -import jakarta.servlet.http.Cookie; -import java.io.IOException; -import java.io.InputStream; -import java.lang.invoke.MethodHandles; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpException; -import org.apache.http.HttpRequest; -import org.apache.http.HttpRequestInterceptor; -import org.apache.http.HttpResponse; -import org.apache.http.client.CookieStore; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpRequestWrapper; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.cookie.CookieSpec; -import org.apache.http.impl.client.BasicCookieStore; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.cookie.BasicClientCookie; -import org.apache.http.protocol.HttpContext; -import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.client.api.util.SolrVersion; -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.SolrRequest.METHOD; -import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.request.JavaBinRequestWriter; -import org.apache.solr.client.solrj.request.QueryRequest; -import org.apache.solr.client.solrj.request.SolrQuery; -import org.apache.solr.client.solrj.request.UpdateRequest; -import org.apache.solr.client.solrj.request.XMLRequestWriter; -import org.apache.solr.client.solrj.response.JavaBinResponseParser; -import org.apache.solr.client.solrj.response.QueryResponse; -import org.apache.solr.client.solrj.response.XMLResponseParser; -import org.apache.solr.common.SolrException; -import org.apache.solr.common.SolrException.ErrorCode; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.common.params.CommonParams; -import org.apache.solr.common.params.ModifiableSolrParams; -import org.apache.solr.common.util.EnvUtils; -import org.apache.solr.common.util.NamedList; -import org.apache.solr.embedded.JettyConfig; -import org.apache.solr.util.ExternalPaths; -import org.apache.solr.util.ServletFixtures.DebugServlet; -import org.apache.solr.util.ServletFixtures.RedirectServlet; -import org.apache.solr.util.ServletFixtures.SlowServlet; -import org.apache.solr.util.ServletFixtures.SlowStreamServlet; -import org.apache.solr.util.SolrJettyTestRule; -import org.eclipse.jetty.ee10.servlet.ServletHolder; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class BasicHttpSolrClientTest extends SolrTestCaseJ4 { - - @ClassRule public static SolrJettyTestRule solrTestRule = new SolrJettyTestRule(); - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - private static final String UA_VERSION = SolrVersion.LATEST_STRING; - - @BeforeClass - public static void beforeTest() throws Exception { - JettyConfig jettyConfig = - JettyConfig.builder() - .withServlet(new ServletHolder(RedirectServlet.class), "/redirect/*") - .withServlet(new ServletHolder(SlowServlet.class), "/slow/*") - .withServlet(new ServletHolder(DebugServlet.class), "/debug/*") - .withServlet(new ServletHolder(SlowStreamServlet.class), "/slowStream/*") - .build(); - EnvUtils.setProperty( - ALLOW_PATHS_SYSPROP, ExternalPaths.SERVER_HOME.toAbsolutePath().toString()); - solrTestRule.startSolr(createTempDir(), new Properties(), jettyConfig); - solrTestRule.newCollection().withConfigSet(ExternalPaths.TECHPRODUCTS_CONFIGSET).create(); - } - - @Test - public void testTimeout() throws Exception { - SolrQuery q = new SolrQuery("*:*"); - final var queryRequest = new QueryRequest(q); - queryRequest.setPath("/slow/foo" + queryRequest.getPath()); - try (SolrClient client = - new HttpSolrClient.Builder(solrTestRule.getBaseUrl()) - .withConnectionTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS) - .withSocketTimeout(2000, TimeUnit.MILLISECONDS) - .build()) { - SolrServerException e = - expectThrows(SolrServerException.class, () -> queryRequest.process(client)); - assertTrue(e.getMessage().contains("Timeout")); - } - } - - /** - * test that SolrExceptions thrown by HttpSolrClient can correctly encapsulate http status codes - * even when not on the list of ErrorCodes solr may return. - */ - public void testSolrExceptionCodeNotFromSolr() throws IOException, SolrServerException { - final int status = 527; - assertEquals( - status - + " didn't generate an UNKNOWN error code, someone modified the list of valid ErrorCode's w/o changing this test to work a different way", - ErrorCode.UNKNOWN, - ErrorCode.getErrorCode(status)); - - try (SolrClient client = getHttpSolrClient(solrTestRule.getBaseUrl())) { - DebugServlet.setErrorCode(status); - SolrQuery q = new SolrQuery("foo"); - final var queryRequest = new QueryRequest(q); - queryRequest.setPath("/debug/foo" + queryRequest.getPath()); - SolrException e = expectThrows(SolrException.class, () -> queryRequest.process(client)); - assertEquals("Unexpected exception status code", status, e.code()); - } finally { - DebugServlet.clear(); - } - } - - @Test - public void testQuery() throws Exception { - DebugServlet.clear(); - final String debugPath = "/debug/foo"; - SolrQuery q = new SolrQuery("foo"); - q.setParam("a", "\u1234"); - final var queryRequest = new QueryRequest(q); - queryRequest.setPath(debugPath); - try (HttpSolrClient client = getHttpSolrClient(solrTestRule.getBaseUrl())) { - - expectThrows(RemoteSolrException.class, () -> queryRequest.process(client)); - - // default method - assertEquals("get", DebugServlet.lastMethod); - // agent - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - // default wt - assertEquals(1, DebugServlet.parameters.get(CommonParams.WT).length); - assertEquals("javabin", DebugServlet.parameters.get(CommonParams.WT)[0]); - // agent - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - // keepalive - assertEquals("keep-alive", DebugServlet.headers.get("connection")); - // content-type - assertNull(DebugServlet.headers.get("content-type")); - // param encoding - assertEquals(1, DebugServlet.parameters.get("a").length); - assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); - - // POST - DebugServlet.clear(); - queryRequest.setMethod(METHOD.POST); - expectThrows(RemoteSolrException.class, () -> queryRequest.process(client)); - - assertEquals("post", DebugServlet.lastMethod); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals(1, DebugServlet.parameters.get(CommonParams.WT).length); - assertEquals("javabin", DebugServlet.parameters.get(CommonParams.WT)[0]); - assertEquals(1, DebugServlet.parameters.get("a").length); - assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals("keep-alive", DebugServlet.headers.get("connection")); - assertEquals( - "application/x-www-form-urlencoded; charset=UTF-8", - DebugServlet.headers.get("content-type")); - - // PUT - DebugServlet.clear(); - queryRequest.setMethod(METHOD.PUT); - expectThrows(RemoteSolrException.class, () -> queryRequest.process(client)); - - assertEquals("put", DebugServlet.lastMethod); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals(1, DebugServlet.parameters.get(CommonParams.WT).length); - assertEquals("javabin", DebugServlet.parameters.get(CommonParams.WT)[0]); - assertEquals(1, DebugServlet.parameters.get("a").length); - assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals("keep-alive", DebugServlet.headers.get("connection")); - assertEquals( - "application/x-www-form-urlencoded; charset=UTF-8", - DebugServlet.headers.get("content-type")); - } - - // XML - try (HttpSolrClient client = - new HttpSolrClient.Builder(solrTestRule.getBaseUrl()) - .withResponseParser(new XMLResponseParser()) - .build()) { - // XML/GET - DebugServlet.clear(); - queryRequest.setMethod(METHOD.GET); // Reset to the default here after using 'PUT' above - expectThrows(RemoteSolrException.class, () -> queryRequest.process(client)); - - assertEquals("get", DebugServlet.lastMethod); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals(1, DebugServlet.parameters.get(CommonParams.WT).length); - assertEquals("xml", DebugServlet.parameters.get(CommonParams.WT)[0]); - assertEquals(1, DebugServlet.parameters.get("a").length); - assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals("keep-alive", DebugServlet.headers.get("connection")); - - // XML/POST - DebugServlet.clear(); - queryRequest.setMethod(METHOD.POST); - expectThrows(RemoteSolrException.class, () -> queryRequest.process(client)); - - assertEquals("post", DebugServlet.lastMethod); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals(1, DebugServlet.parameters.get(CommonParams.WT).length); - assertEquals("xml", DebugServlet.parameters.get(CommonParams.WT)[0]); - assertEquals(1, DebugServlet.parameters.get("a").length); - assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals("keep-alive", DebugServlet.headers.get("connection")); - assertEquals( - "application/x-www-form-urlencoded; charset=UTF-8", - DebugServlet.headers.get("content-type")); - - DebugServlet.clear(); - queryRequest.setMethod(METHOD.PUT); - expectThrows(RemoteSolrException.class, () -> queryRequest.process(client)); - - assertEquals("put", DebugServlet.lastMethod); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals(1, DebugServlet.parameters.get(CommonParams.WT).length); - assertEquals("xml", DebugServlet.parameters.get(CommonParams.WT)[0]); - assertEquals(1, DebugServlet.parameters.get("a").length); - assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals("keep-alive", DebugServlet.headers.get("connection")); - assertEquals( - "application/x-www-form-urlencoded; charset=UTF-8", - DebugServlet.headers.get("content-type")); - } - } - - @Test - public void testDelete() throws Exception { - DebugServlet.clear(); - final String debugPath = "/debug/foo"; - - try (HttpSolrClient client = getHttpSolrClient(solrTestRule.getBaseUrl())) { - final UpdateRequest deleteById = new UpdateRequest(); - deleteById.deleteById("id"); - deleteById.setPath(debugPath + deleteById.getPath()); - expectThrows(RemoteSolrException.class, () -> deleteById.process(client)); - - // default method - assertEquals("post", DebugServlet.lastMethod); - // agent - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - // default wt - assertEquals(1, DebugServlet.parameters.get(CommonParams.WT).length); - assertEquals("javabin", DebugServlet.parameters.get(CommonParams.WT)[0]); - // agent - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - // keepalive - assertEquals("keep-alive", DebugServlet.headers.get("connection")); - } - - // XML - try (HttpSolrClient client = - new HttpSolrClient.Builder(solrTestRule.getBaseUrl()) - .withResponseParser(new XMLResponseParser()) - .build()) { - final var deleteByQueryRequest = new UpdateRequest(); - deleteByQueryRequest.setPath(debugPath + deleteByQueryRequest.getPath()); - deleteByQueryRequest.deleteByQuery("*:*"); - deleteByQueryRequest.setCommitWithin(-1); - expectThrows(RemoteSolrException.class, () -> deleteByQueryRequest.process(client)); - - assertEquals("post", DebugServlet.lastMethod); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals(1, DebugServlet.parameters.get(CommonParams.WT).length); - assertEquals("xml", DebugServlet.parameters.get(CommonParams.WT)[0]); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals("keep-alive", DebugServlet.headers.get("connection")); - } - } - - @Test - public void testGetById() throws Exception { - DebugServlet.clear(); - try (SolrClient client = getHttpSolrClient(solrTestRule.getBaseUrl() + "/debug/foo")) { - Collection ids = Collections.singletonList("a"); - expectThrows(RemoteSolrException.class, () -> client.getById("a")); - expectThrows(RemoteSolrException.class, () -> client.getById(ids, null)); - expectThrows(RemoteSolrException.class, () -> client.getById("foo", "a")); - expectThrows(RemoteSolrException.class, () -> client.getById("foo", ids, null)); - } - } - - @Test - public void testUpdate() throws Exception { - DebugServlet.clear(); - final String debugPath = "/debug/foo"; - - try (HttpSolrClient client = getHttpSolrClient(solrTestRule.getBaseUrl())) { - UpdateRequest req = new UpdateRequest(); - req.add(new SolrInputDocument()); - req.setPath(debugPath + req.getPath()); - req.setParam("a", "\u1234"); - expectThrows(RemoteSolrException.class, () -> req.process(client)); - - // default method - assertEquals("post", DebugServlet.lastMethod); - // agent - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - // default wt - assertEquals(1, DebugServlet.parameters.get(CommonParams.WT).length); - assertEquals("javabin", DebugServlet.parameters.get(CommonParams.WT)[0]); - // content type - assertEquals("application/javabin", DebugServlet.headers.get("content-type")); - // parameter encoding - assertEquals(1, DebugServlet.parameters.get("a").length); - assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); - } - DebugServlet.clear(); - // XML response and writer - try (HttpSolrClient client = - new HttpSolrClient.Builder(solrTestRule.getBaseUrl()) - .withRequestWriter(new XMLRequestWriter()) - .withResponseParser(new XMLResponseParser()) - .build()) { - UpdateRequest req = new UpdateRequest(); - req.add(new SolrInputDocument()); - req.setPath(debugPath + req.getPath()); - req.setParam("a", "\u1234"); - - expectThrows(RemoteSolrException.class, () -> client.request(req)); - - assertEquals("post", DebugServlet.lastMethod); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals(1, DebugServlet.parameters.get(CommonParams.WT).length); - assertEquals("xml", DebugServlet.parameters.get(CommonParams.WT)[0]); - assertEquals("application/xml; charset=UTF-8", DebugServlet.headers.get("content-type")); - assertEquals(1, DebugServlet.parameters.get("a").length); - assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); - } - DebugServlet.clear(); - // javabin request - try (HttpSolrClient client = - new HttpSolrClient.Builder(solrTestRule.getBaseUrl()) - .withRequestWriter(new JavaBinRequestWriter()) - .withResponseParser(new JavaBinResponseParser()) - .build()) { - UpdateRequest req = new UpdateRequest(); - req.add(new SolrInputDocument()); - req.setPath(debugPath + req.getPath()); - req.setParam("a", "\u1234"); - - expectThrows(RemoteSolrException.class, () -> client.request(req)); - - assertEquals("post", DebugServlet.lastMethod); - assertEquals( - "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("user-agent")); - assertEquals(1, DebugServlet.parameters.get(CommonParams.WT).length); - assertEquals("javabin", DebugServlet.parameters.get(CommonParams.WT)[0]); - assertEquals("application/javabin", DebugServlet.headers.get("content-type")); - assertEquals(1, DebugServlet.parameters.get("a").length); - assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); - } - } - - @Test - public void testRedirect() throws Exception { - final String redirectPath = "/redirect/foo"; - SolrQuery q = new SolrQuery("*:*"); - final var queryRequest = new QueryRequest(q); - queryRequest.setPath(redirectPath + queryRequest.getPath()); - - // default for redirect is false. - try (HttpSolrClient client = new HttpSolrClient.Builder(solrTestRule.getBaseUrl()).build()) { - SolrServerException e = - expectThrows(SolrServerException.class, () -> queryRequest.process(client)); - assertTrue(e.getMessage().contains("redirect")); - } - - try (HttpSolrClient client = - new HttpSolrClient.Builder(solrTestRule.getBaseUrl()).withFollowRedirects(true).build()) { - // No exception expected - queryRequest.process(client); - } - - // And with explicit false: - try (HttpSolrClient client = - new HttpSolrClient.Builder(solrTestRule.getBaseUrl()).withFollowRedirects(false).build()) { - SolrServerException e = - expectThrows(SolrServerException.class, () -> queryRequest.process(client)); - assertTrue(e.getMessage().contains("redirect")); - } - } - - @Test - public void testCompression() throws Exception { - final String debugPath = "/debug/foo"; - final SolrQuery q = new SolrQuery("*:*"); - final var queryRequest = new QueryRequest(q); - queryRequest.setPath(debugPath + queryRequest.getPath()); - - try (SolrClient client = getHttpSolrClient(solrTestRule.getBaseUrl())) { - // verify request header gets set - DebugServlet.clear(); - expectThrows(RemoteSolrException.class, () -> queryRequest.process(client)); - assertNull(DebugServlet.headers.toString(), DebugServlet.headers.get("accept-encoding")); - } - - try (SolrClient client = - new HttpSolrClient.Builder(solrTestRule.getBaseUrl()).allowCompression(true).build()) { - try { - queryRequest.process(client); - } catch (RemoteSolrException ignored) { - } - assertNotNull(DebugServlet.headers.get("accept-encoding")); - } - - try (SolrClient client = - new HttpSolrClient.Builder(solrTestRule.getBaseUrl()).allowCompression(false).build()) { - try { - queryRequest.process(client); - } catch (RemoteSolrException ignored) { - } - } - assertNull(DebugServlet.headers.get("accept-encoding")); - - // verify server compresses output - HttpGet get = - new HttpGet( - solrTestRule.getBaseUrl() + "/" + DEFAULT_TEST_CORENAME + "/select?q=foo&wt=xml"); - get.setHeader("Accept-Encoding", "gzip"); - ModifiableSolrParams params = new ModifiableSolrParams(); - params.set(HttpClientUtil.PROP_ALLOW_COMPRESSION, true); - - RequestConfig config = RequestConfig.custom().setDecompressionEnabled(false).build(); - get.setConfig(config); - - CloseableHttpClient httpclient = HttpClientUtil.createClient(params); - HttpEntity entity = null; - try { - HttpResponse response = - httpclient.execute(get, HttpClientUtil.createNewHttpClientRequestContext()); - entity = response.getEntity(); - Header ceheader = entity.getContentEncoding(); - assertNotNull(Arrays.asList(response.getAllHeaders()).toString(), ceheader); - assertEquals("gzip", ceheader.getValue()); - } finally { - if (entity != null) { - entity.getContent().close(); - } - HttpClientUtil.close(httpclient); - } - - // verify compressed response can be handled - try (SolrClient client = - getHttpSolrClient(solrTestRule.getBaseUrl(), DEFAULT_TEST_COLLECTION_NAME)) { - QueryResponse response = client.query(new SolrQuery("foo")); - assertEquals(0, response.getStatus()); - } - } - - @Test - public void testCollectionParameters() throws IOException, SolrServerException { - - try (SolrClient client = getHttpSolrClient(solrTestRule.getBaseUrl())) { - SolrInputDocument doc = new SolrInputDocument(); - doc.addField("id", "collection"); - client.add("collection1", doc); - client.commit("collection1"); - - assertEquals( - 1, - client.query("collection1", new SolrQuery("id:collection")).getResults().getNumFound()); - } - - try (SolrClient client = getHttpSolrClient(solrTestRule.getBaseUrl(), DEFAULT_TEST_CORENAME)) { - assertEquals(1, client.query(new SolrQuery("id:collection")).getResults().getNumFound()); - } - } - - @Test - public void testGetRawStream() throws SolrServerException, IOException { - CloseableHttpClient httpClient = HttpClientUtil.createClient(null); - try (SolrClient solrClient = - new HttpSolrClient.Builder(solrTestRule.getBaseUrl()) - .withDefaultCollection(DEFAULT_TEST_CORENAME) - .withHttpClient(httpClient) - .withResponseParser(null) - .build(); ) { - - QueryRequest req = new QueryRequest(); - NamedList response = solrClient.request(req); - InputStream stream = (InputStream) response.get("stream"); - assertNotNull(stream); - stream.close(); - } finally { - HttpClientUtil.close(httpClient); - } - } - - /** An interceptor changing the request */ - HttpRequestInterceptor changeRequestInterceptor = - new HttpRequestInterceptor() { - - @Override - public void process(HttpRequest request, HttpContext context) - throws HttpException, IOException { - log.info("Intercepted params: {}", context); - - HttpRequestWrapper wrapper = (HttpRequestWrapper) request; - URIBuilder uribuilder = new URIBuilder(wrapper.getURI()); - uribuilder.addParameter("b", "\u4321"); - try { - wrapper.setURI(uribuilder.build()); - } catch (URISyntaxException ex) { - throw new HttpException("Invalid request URI", ex); - } - } - }; - - public static final String cookieName = "cookieName"; - public static final String cookieValue = "cookieValue"; - - /** An interceptor setting a cookie */ - HttpRequestInterceptor cookieSettingRequestInterceptor = - new HttpRequestInterceptor() { - @Override - public void process(HttpRequest request, HttpContext context) - throws HttpException, IOException { - BasicClientCookie cookie = new BasicClientCookie(cookieName, cookieValue); - cookie.setVersion(0); - cookie.setPath("/"); - cookie.setDomain(solrTestRule.getJetty().getBaseUrl().getHost()); - - CookieStore cookieStore = new BasicCookieStore(); - CookieSpec cookieSpec = new SolrPortAwareCookieSpecFactory().create(context); - // CookieSpec cookieSpec = registry.lookup(policy).create(context); - // Add the cookies to the request - List
headers = cookieSpec.formatCookies(Collections.singletonList(cookie)); - for (Header header : headers) { - request.addHeader(header); - } - context.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore); - } - }; - - /** - * Set cookies via interceptor Change the request via an interceptor Ensure cookies are actually - * set and that request is actually changed - */ - @Test - public void testInterceptors() { - DebugServlet.clear(); - HttpClientUtil.addRequestInterceptor(changeRequestInterceptor); - HttpClientUtil.addRequestInterceptor(cookieSettingRequestInterceptor); - - final String debugPath = "/debug/foo"; - try (SolrClient server = getHttpSolrClient(solrTestRule.getBaseUrl())) { - - SolrQuery q = new SolrQuery("foo"); - q.setParam("a", "\u1234"); - final var queryRequest = new QueryRequest(q); - queryRequest.setPath(debugPath + queryRequest.getPath()); - expectThrows( - Exception.class, - () -> { - queryRequest.setMethod(random().nextBoolean() ? METHOD.POST : METHOD.GET); - queryRequest.process(server); - }); - - // Assert cookies from UseContextCallback - assertNotNull(DebugServlet.cookies); - boolean foundCookie = false; - for (Cookie cookie : DebugServlet.cookies) { - if (cookieName.equals(cookie.getName()) && cookieValue.equals(cookie.getValue())) { - foundCookie = true; - break; - } - } - assertTrue(foundCookie); - - // Assert request changes by ChangeRequestCallback - assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); - assertEquals("\u4321", DebugServlet.parameters.get("b")[0]); - - } catch (IOException ex) { - throw new RuntimeException(ex); - } finally { - HttpClientUtil.removeRequestInterceptor(changeRequestInterceptor); - HttpClientUtil.removeRequestInterceptor(cookieSettingRequestInterceptor); - } - } - - private void setReqParamsOf(UpdateRequest req, String... keys) { - if (keys != null) { - for (String k : keys) { - req.setParam(k, k + "Value"); - } - } - } - - private void verifyServletState(HttpSolrClient client, SolrRequest request) { - // check query String - Iterator paramNames = request.getParams().getParameterNamesIterator(); - while (paramNames.hasNext()) { - String name = paramNames.next(); - String[] values = request.getParams().getParams(name); - if (values != null) { - for (String value : values) { - boolean shouldBeInQueryString = - client.getUrlParamNames().contains(name) - || (request.getQueryParams() != null && request.getQueryParams().contains(name)); - assertEquals( - shouldBeInQueryString, DebugServlet.queryString.contains(name + "=" + value)); - // in either case, it should be in the parameters - assertNotNull(DebugServlet.parameters.get(name)); - assertEquals(1, DebugServlet.parameters.get(name).length); - assertEquals(value, DebugServlet.parameters.get(name)[0]); - } - } - } - } - - @Test - public void testQueryString() throws Exception { - final String debugPath = "/debug/foo"; - HttpSolrClient.Builder builder = new HttpSolrClient.Builder(solrTestRule.getBaseUrl()); - try (HttpSolrClient client = - builder.withTheseParamNamesInTheUrl(Set.of("serverOnly")).build()) { - // test without request query params - DebugServlet.clear(); - UpdateRequest req = new UpdateRequest(); - req.setPath(debugPath + req.getPath()); - setReqParamsOf(req, "serverOnly", "notServer"); - expectThrows(RemoteSolrException.class, () -> client.request(req)); - verifyServletState(client, req); - } - try (HttpSolrClient client = builder.withTheseParamNamesInTheUrl(Set.of()).build()) { - // test without server query params - DebugServlet.clear(); - UpdateRequest req2 = new UpdateRequest(); - req2.setPath(debugPath + req2.getPath()); - req2.setQueryParams(Set.of("requestOnly")); - setReqParamsOf(req2, "requestOnly", "notRequest"); - expectThrows(RemoteSolrException.class, () -> client.request(req2)); - verifyServletState(client, req2); - } - try (HttpSolrClient client = - builder.withTheseParamNamesInTheUrl(Set.of("serverOnly", "both")).build()) { - // test with both request and server query params - DebugServlet.clear(); - UpdateRequest req3 = new UpdateRequest(); - req3.setPath(debugPath + req3.getPath()); - req3.setQueryParams(Set.of("requestOnly", "both")); - setReqParamsOf(req3, "serverOnly", "requestOnly", "both", "neither"); - expectThrows(RemoteSolrException.class, () -> client.request(req3)); - verifyServletState(client, req3); - } - try (HttpSolrClient client = - builder.withTheseParamNamesInTheUrl(Set.of("serverOnly", "both")).build()) { - // test with both request and server query params with single stream - DebugServlet.clear(); - UpdateRequest req4 = new UpdateRequest(); - req4.setPath(debugPath + req4.getPath()); - req4.add(new SolrInputDocument()); - req4.setQueryParams(Set.of("requestOnly", "both")); - setReqParamsOf(req4, "serverOnly", "requestOnly", "both", "neither"); - expectThrows(RemoteSolrException.class, () -> client.request(req4)); - // NOTE: single stream requests send all the params - // as part of the query string. So add "neither" to the request, - // so it passes the verification step. - req4.setQueryParams(Set.of("requestOnly", "both", "neither")); - verifyServletState(client, req4); - } - } - - @Test - @SuppressWarnings({"try"}) - public void testInvariantParams() throws IOException { - try (HttpSolrClient createdClient = - new HttpSolrClient.Builder() - .withBaseSolrUrl(solrTestRule.getBaseUrl()) - .withInvariantParams(SolrTestCaseJ4.params("param", "value")) - .build()) { - assertEquals("value", createdClient.getInvariantParams().get("param")); - } - - try (HttpSolrClient createdClient = - new HttpSolrClient.Builder() - .withBaseSolrUrl(solrTestRule.getBaseUrl()) - .withInvariantParams(SolrTestCaseJ4.params("fq", "fq1", "fq", "fq2")) - .build()) { - assertEquals(2, createdClient.getInvariantParams().getParams("fq").length); - } - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientBadInputTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientBadInputTest.java deleted file mode 100644 index ad591b386819..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientBadInputTest.java +++ /dev/null @@ -1,66 +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.apache; - -import java.util.ArrayList; -import java.util.List; -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.cloud.SolrCloudTestCase; -import org.junit.BeforeClass; -import org.junit.Test; - -public class CloudSolrClientBadInputTest extends SolrCloudTestCase { - private static final List NULL_STR_LIST = null; - private static final List EMPTY_STR_LIST = new ArrayList<>(); - private static final String ANY_COLLECTION = "ANY_COLLECTION"; - private static final int ANY_COMMIT_WITHIN_TIME = -1; - - @BeforeClass - public static void setupCluster() throws Exception { - configureCluster(1).configure(); - } - - @Test - public void testDeleteByIdReportsInvalidIdLists() throws Exception { - SolrClient client = cluster.getSolrClient(); - assertExceptionThrownWithMessageContaining( - IllegalArgumentException.class, - List.of("ids", "null"), - () -> { - client.deleteById(ANY_COLLECTION, NULL_STR_LIST); - }); - assertExceptionThrownWithMessageContaining( - IllegalArgumentException.class, - List.of("ids", "empty"), - () -> { - client.deleteById(ANY_COLLECTION, EMPTY_STR_LIST); - }); - assertExceptionThrownWithMessageContaining( - IllegalArgumentException.class, - List.of("ids", "null"), - () -> { - client.deleteById(ANY_COLLECTION, NULL_STR_LIST, ANY_COMMIT_WITHIN_TIME); - }); - assertExceptionThrownWithMessageContaining( - IllegalArgumentException.class, - List.of("ids", "empty"), - () -> { - client.deleteById(ANY_COLLECTION, EMPTY_STR_LIST, ANY_COMMIT_WITHIN_TIME); - }); - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientBuilderTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientBuilderTest.java deleted file mode 100644 index 9ff91933e949..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientBuilderTest.java +++ /dev/null @@ -1,121 +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.apache; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.TimeUnit; -import org.apache.solr.SolrTestCase; -import org.apache.solr.client.solrj.impl.CloudSolrClient; -import org.apache.solr.client.solrj.impl.ZkClientClusterStateProvider; -import org.junit.Test; - -public class CloudSolrClientBuilderTest extends SolrTestCase { - private static final String ANY_CHROOT = "/ANY_CHROOT"; - private static final String ANY_ZK_HOST = "ANY_ZK_HOST"; - private static final String ANY_OTHER_ZK_HOST = "ANY_OTHER_ZK_HOST"; - - @Test - public void testSingleZkHostSpecified() throws IOException { - try (CloudSolrClient createdClient = - new CloudSolrClient.Builder(Collections.singletonList(ANY_ZK_HOST), Optional.of(ANY_CHROOT)) - .build(); ) { - try (ZkClientClusterStateProvider zkClientClusterStateProvider = - ZkClientClusterStateProvider.from(createdClient)) { - final String clientZkHost = zkClientClusterStateProvider.getZkHost(); - assertTrue(clientZkHost.contains(ANY_ZK_HOST)); - } - } - } - - @Test - public void testSeveralZkHostsSpecifiedSingly() throws IOException { - final List zkHostList = new ArrayList<>(); - zkHostList.add(ANY_ZK_HOST); - zkHostList.add(ANY_OTHER_ZK_HOST); - try (CloudSolrClient createdClient = - new CloudSolrClient.Builder(zkHostList, Optional.of(ANY_CHROOT)).build()) { - try (ZkClientClusterStateProvider zkClientClusterStateProvider = - ZkClientClusterStateProvider.from(createdClient)) { - final String clientZkHost = zkClientClusterStateProvider.getZkHost(); - assertTrue(clientZkHost.contains(ANY_ZK_HOST)); - assertTrue(clientZkHost.contains(ANY_OTHER_ZK_HOST)); - } - } - } - - @Test - public void testSeveralZkHostsSpecifiedTogether() throws IOException { - final ArrayList zkHosts = new ArrayList<>(); - zkHosts.add(ANY_ZK_HOST); - zkHosts.add(ANY_OTHER_ZK_HOST); - try (CloudSolrClient createdClient = - new CloudSolrClient.Builder(zkHosts, Optional.of(ANY_CHROOT)).build()) { - try (ZkClientClusterStateProvider zkClientClusterStateProvider = - ZkClientClusterStateProvider.from(createdClient)) { - final String clientZkHost = zkClientClusterStateProvider.getZkHost(); - assertTrue(clientZkHost.contains(ANY_ZK_HOST)); - assertTrue(clientZkHost.contains(ANY_OTHER_ZK_HOST)); - } - } - } - - @Test - public void testByDefaultConfiguresClientToSendUpdatesOnlyToShardLeaders() throws IOException { - try (CloudSolrClient createdClient = - new CloudSolrClient.Builder(Collections.singletonList(ANY_ZK_HOST), Optional.of(ANY_CHROOT)) - .build()) { - assertTrue(createdClient.isUpdatesToLeaders()); - } - } - - @Test - public void testIsDirectUpdatesToLeadersOnlyDefault() throws IOException { - try (CloudSolrClient createdClient = - new CloudSolrClient.Builder(Collections.singletonList(ANY_ZK_HOST), Optional.of(ANY_CHROOT)) - .build()) { - assertFalse(createdClient.isDirectUpdatesToLeadersOnly()); - } - } - - @Test - @SuppressWarnings({"try"}) - public void test0Timeouts() throws IOException { - try (CloudSolrClient createdClient = - new CloudLegacySolrClient.Builder(Collections.singletonList(ANY_ZK_HOST), Optional.empty()) - .withSocketTimeout(0, TimeUnit.MILLISECONDS) - .withConnectionTimeout(0, TimeUnit.MILLISECONDS) - .build()) { - assertNotNull(createdClient); - } - } - - @Test - public void testDefaultCollectionPassedFromBuilderToClient() throws IOException { - try (CloudSolrClient createdClient = - new CloudLegacySolrClient.Builder( - Collections.singletonList(ANY_ZK_HOST), Optional.of(ANY_CHROOT)) - .withDefaultCollection("aCollection") - .build()) { - assertEquals("aCollection", createdClient.getDefaultCollection()); - } - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientMultiConstructorTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientMultiConstructorTest.java deleted file mode 100644 index 5ee728580b84..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientMultiConstructorTest.java +++ /dev/null @@ -1,120 +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.apache; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Optional; -import org.apache.lucene.tests.util.TestUtil; -import org.apache.solr.SolrTestCase; -import org.apache.solr.client.solrj.impl.CloudSolrClient; -import org.apache.solr.client.solrj.impl.ZkClientClusterStateProvider; -import org.junit.Test; - -public class CloudSolrClientMultiConstructorTest extends SolrTestCase { - - /* - * NOTE: If you only include one String argument, it will NOT use the - * constructor with the variable argument list, which is the one that - * we are testing here. - */ - Collection hosts; - - @Test - public void testZkConnecstionStringSetterWithValidChroot() throws IOException { - boolean setOrList = random().nextBoolean(); - int numOfZKServers = TestUtil.nextInt(random(), 1, 5); - boolean withChroot = random().nextBoolean(); - - final String chroot = "/mychroot"; - - StringBuilder sb = new StringBuilder(); - - if (setOrList) { - /* - A LinkedHashSet is required here for testing, or we can't guarantee - the order of entries in the final string. - */ - hosts = new LinkedHashSet<>(); - } else { - hosts = new ArrayList<>(); - } - - for (int i = 0; i < numOfZKServers; i++) { - String ZKString = "host" + i + ":2181"; - hosts.add(ZKString); - sb.append(ZKString); - if (i < numOfZKServers - 1) sb.append(","); - } - - String clientChroot = null; - if (withChroot) { - sb.append(chroot); - clientChroot = "/mychroot"; - } - - try (CloudSolrClient client = - (new CloudSolrClient.Builder(new ArrayList<>(hosts), Optional.ofNullable(clientChroot)) - .build())) { - try (ZkClientClusterStateProvider zkClientClusterStateProvider = - ZkClientClusterStateProvider.from(client)) { - assertEquals(sb.toString(), zkClientClusterStateProvider.getZkHost()); - } - } - } - - @Test - public void testZkConnectionStringConstructorWithValidChroot() throws IOException { - int numOfZKServers = TestUtil.nextInt(random(), 1, 5); - boolean withChroot = random().nextBoolean(); - - final String chroot = "/mychroot"; - - StringBuilder sb = new StringBuilder(); - - List hosts = new ArrayList<>(); - for (int i = 0; i < numOfZKServers; i++) { - String ZKString = "host" + i + ":2181"; - hosts.add(ZKString); - sb.append(ZKString); - if (i < numOfZKServers - 1) sb.append(","); - } - - if (withChroot) { - sb.append(chroot); - } - - final Optional chrootOption = - withChroot == false ? Optional.empty() : Optional.of(chroot); - try (var client = new CloudLegacySolrClient.Builder(hosts, chrootOption).build()) { - try (ZkClientClusterStateProvider zkClientClusterStateProvider = - ZkClientClusterStateProvider.from(client)) { - assertEquals(sb.toString(), zkClientClusterStateProvider.getZkHost()); - } - } - } - - @Test(expected = IllegalArgumentException.class) - public void testBadChroot() { - final List zkHosts = new ArrayList<>(); - zkHosts.add("host1:2181"); - new CloudSolrClient.Builder(zkHosts, Optional.of("foo")).build(); - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientRetryTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientRetryTest.java deleted file mode 100644 index 2ae18bce100b..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientRetryTest.java +++ /dev/null @@ -1,75 +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.apache; - -import org.apache.solr.client.solrj.impl.CloudSolrClient; -import org.apache.solr.client.solrj.request.CollectionAdminRequest; -import org.apache.solr.cloud.SolrCloudTestCase; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.util.SolrJMetricTestUtils; -import org.apache.solr.util.TestInjection; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; - -@Ignore("Apache HttpClient stuff will get deleted SOLR-16367") -public class CloudSolrClientRetryTest extends SolrCloudTestCase { - private static final int NODE_COUNT = 1; - - @BeforeClass - public static void setupCluster() throws Exception { - System.setProperty("metricsEnabled", "true"); - configureCluster(NODE_COUNT) - .addConfig( - "conf", - getFile("solrj") - .resolve("solr") - .resolve("configsets") - .resolve("streaming") - .resolve("conf")) - .configure(); - } - - @Test - public void testRetry() throws Exception { - String collectionName = "testRetry"; - CloudSolrClient solrClient = cluster.getSolrClient(); - CollectionAdminRequest.createCollection(collectionName, 1, 1).process(solrClient); - String prometheusMetric = - "solr_core_requests_total{category=\"UPDATE\",collection=\"testRetry\",core=\"testRetry_shard1_replica_n1\",handler=\"/update\",otel_scope_name=\"org.apache.solr\",replica_type=\"NRT\",shard=\"shard1\"}"; - solrClient.add(collectionName, new SolrInputDocument("id", "1")); - - assertEquals( - 1.0, SolrJMetricTestUtils.getPrometheusMetricValue(solrClient, prometheusMetric), 0.0); - - TestInjection.failUpdateRequests = "true:100"; - try { - expectThrows( - CloudSolrClient.RouteException.class, - "Expected an exception on the client when failure is injected during updates", - () -> { - solrClient.add(collectionName, new SolrInputDocument("id", "2")); - }); - } finally { - TestInjection.reset(); - } - - assertEquals( - 2.0, SolrJMetricTestUtils.getPrometheusMetricValue(solrClient, prometheusMetric), 0.0); - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientTest.java deleted file mode 100644 index 89d050dc4318..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/CloudSolrClientTest.java +++ /dev/null @@ -1,1164 +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.apache; - -import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST; - -import java.io.IOException; -import java.lang.invoke.MethodHandles; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -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.METHOD; -import org.apache.solr.client.solrj.SolrRequest.SolrRequestType; -import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.impl.CloudSolrClient; -import org.apache.solr.client.solrj.impl.LBSolrClient; -import org.apache.solr.client.solrj.impl.ZkClientClusterStateProvider; -import org.apache.solr.client.solrj.request.AbstractUpdateRequest; -import org.apache.solr.client.solrj.request.CollectionAdminRequest; -import org.apache.solr.client.solrj.request.GenericSolrRequest; -import org.apache.solr.client.solrj.request.QueryRequest; -import org.apache.solr.client.solrj.request.SolrQuery; -import org.apache.solr.client.solrj.request.UpdateRequest; -import org.apache.solr.client.solrj.request.V2Request; -import org.apache.solr.client.solrj.response.QueryResponse; -import org.apache.solr.client.solrj.response.RequestStatusState; -import org.apache.solr.client.solrj.response.SolrPingResponse; -import org.apache.solr.client.solrj.response.UpdateResponse; -import org.apache.solr.cloud.AbstractFullDistribZkTestBase; -import org.apache.solr.cloud.SolrCloudTestCase; -import org.apache.solr.common.SolrDocument; -import org.apache.solr.common.SolrDocumentList; -import org.apache.solr.common.SolrException; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.common.cloud.ClusterState; -import org.apache.solr.common.cloud.DocCollection; -import org.apache.solr.common.cloud.DocRouter; -import org.apache.solr.common.cloud.PerReplicaStates; -import org.apache.solr.common.cloud.PerReplicaStatesOps; -import org.apache.solr.common.cloud.Replica; -import org.apache.solr.common.cloud.Slice; -import org.apache.solr.common.cloud.ZkStateReader; -import org.apache.solr.common.params.CommonParams; -import org.apache.solr.common.params.ModifiableSolrParams; -import org.apache.solr.common.params.ShardParams; -import org.apache.solr.common.params.UpdateParams; -import org.apache.solr.common.util.IOUtils; -import org.apache.solr.common.util.NamedList; -import org.apache.solr.common.util.SimpleOrderedMap; -import org.apache.solr.common.util.URLUtil; -import org.apache.solr.embedded.JettySolrRunner; -import org.apache.solr.handler.admin.CollectionsHandler; -import org.apache.solr.handler.admin.ConfigSetsHandler; -import org.apache.solr.handler.admin.CoreAdminHandler; -import org.apache.solr.util.LogLevel; -import org.apache.solr.util.SolrJMetricTestUtils; -import org.hamcrest.Matchers; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** This test would be faster if we simulated the zk state instead. */ -@LogLevel( - "org.apache.solr.cloud.Overseer=INFO;org.apache.solr.common.cloud=INFO;org.apache.solr.cloud.api.collections=INFO;org.apache.solr.cloud.overseer=INFO") -@Ignore("Apache HttpClient stuff will get deleted SOLR-16367") -public class CloudSolrClientTest extends SolrCloudTestCase { - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - private static final String id = "id"; - - private static final int TIMEOUT = 30; - private static final int NODE_COUNT = 3; - - private static CloudSolrClient httpBasedCloudSolrClient = null; - - @BeforeClass - public static void setupCluster() throws Exception { - System.setProperty("metricsEnabled", "true"); - configureCluster(NODE_COUNT) - .addConfig( - "conf", - getFile("solrj") - .resolve("solr") - .resolve("configsets") - .resolve("streaming") - .resolve("conf")) - .configure(); - - final List solrUrls = new ArrayList<>(); - solrUrls.add(cluster.getJettySolrRunner(0).getBaseUrl().toString()); - httpBasedCloudSolrClient = new CloudLegacySolrClient.Builder(solrUrls).build(); - } - - @AfterClass - public static void tearDownAfterClass() throws Exception { - IOUtils.closeQuietly(httpBasedCloudSolrClient); - httpBasedCloudSolrClient = null; - - shutdownCluster(); - } - - /** Randomly return the cluster's ZK based CSC, or HttpClusterProvider based CSC. */ - private CloudSolrClient getRandomClient() { - return random().nextBoolean() ? cluster.getSolrClient() : httpBasedCloudSolrClient; - } - - @Test - public void testParallelUpdateQTime() throws Exception { - String COLLECTION = getSaferTestName(); - - CollectionAdminRequest.createCollection(COLLECTION, "conf", 2, 1) - .process(cluster.getSolrClient()); - cluster.waitForActiveCollection(COLLECTION, 2, 2); - UpdateRequest req = new UpdateRequest(); - for (int i = 0; i < 10; i++) { - SolrInputDocument doc = new SolrInputDocument(); - doc.addField("id", String.valueOf(TestUtil.nextInt(random(), 1000, 1100))); - req.add(doc); - } - UpdateResponse response = req.process(getRandomClient(), COLLECTION); - // See SOLR-6547, we just need to ensure that no exception is thrown here - assertTrue(response.getQTime() >= 0); - } - - @Test - public void testOverwriteOption() throws Exception { - - CollectionAdminRequest.createCollection("overwrite", "conf", 1, 1) - .processAndWait(cluster.getSolrClient(), TIMEOUT); - cluster.waitForActiveCollection("overwrite", 1, 1); - - new UpdateRequest() - .add("id", "0", "a_t", "hello1") - .add("id", "0", "a_t", "hello2") - .commit(cluster.getSolrClient(), "overwrite"); - - QueryResponse resp = cluster.getSolrClient().query("overwrite", new SolrQuery("*:*")); - assertEquals( - "There should be one document because overwrite=true", 1, resp.getResults().getNumFound()); - - new UpdateRequest() - .add(new SolrInputDocument(id, "1", "a_t", "hello1"), /* overwrite= */ false) - .add(new SolrInputDocument(id, "1", "a_t", "hello2"), false) - .commit(cluster.getSolrClient(), "overwrite"); - - resp = getRandomClient().query("overwrite", new SolrQuery("*:*")); - assertEquals( - "There should be 3 documents because there should be two id=1 docs due to overwrite=false", - 3, - resp.getResults().getNumFound()); - } - - @Test - public void testAliasHandling() throws Exception { - String COLLECTION = getSaferTestName(); - String COLLECTION2 = "2nd_collection"; - - CollectionAdminRequest.createCollection(COLLECTION, "conf", 2, 1) - .process(cluster.getSolrClient()); - cluster.waitForActiveCollection(COLLECTION, 2, 2); - - CollectionAdminRequest.createCollection(COLLECTION2, "conf", 2, 1) - .process(cluster.getSolrClient()); - cluster.waitForActiveCollection(COLLECTION2, 2, 2); - - CloudSolrClient client = getRandomClient(); - SolrInputDocument doc = new SolrInputDocument("id", "1", "title_s", "my doc"); - client.add(COLLECTION, doc); - client.commit(COLLECTION); - CollectionAdminRequest.createAlias("testalias", COLLECTION).process(cluster.getSolrClient()); - - SolrInputDocument doc2 = new SolrInputDocument("id", "2", "title_s", "my doc too"); - client.add(COLLECTION2, doc2); - client.commit(COLLECTION2); - CollectionAdminRequest.createAlias("testalias2", COLLECTION2).process(cluster.getSolrClient()); - - CollectionAdminRequest.createAlias("testaliascombined", COLLECTION + "," + COLLECTION2) - .process(cluster.getSolrClient()); - - // ensure that the aliases have been registered - Map aliases = - new CollectionAdminRequest.ListAliases().process(cluster.getSolrClient()).getAliases(); - assertEquals(COLLECTION, aliases.get("testalias")); - assertEquals(COLLECTION2, aliases.get("testalias2")); - assertEquals(COLLECTION + "," + COLLECTION2, aliases.get("testaliascombined")); - - assertEquals(1, client.query(COLLECTION, params("q", "*:*")).getResults().getNumFound()); - assertEquals(1, client.query("testalias", params("q", "*:*")).getResults().getNumFound()); - - assertEquals(1, client.query(COLLECTION2, params("q", "*:*")).getResults().getNumFound()); - assertEquals(1, client.query("testalias2", params("q", "*:*")).getResults().getNumFound()); - - assertEquals( - 2, client.query("testaliascombined", params("q", "*:*")).getResults().getNumFound()); - - ModifiableSolrParams paramsWithBothCollections = - params("q", "*:*", "collection", COLLECTION + "," + COLLECTION2); - assertEquals(2, client.query(null, paramsWithBothCollections).getResults().getNumFound()); - - ModifiableSolrParams paramsWithBothAliases = - params("q", "*:*", "collection", "testalias,testalias2"); - assertEquals(2, client.query(null, paramsWithBothAliases).getResults().getNumFound()); - - ModifiableSolrParams paramsWithCombinedAlias = - params("q", "*:*", "collection", "testaliascombined"); - assertEquals(2, client.query(null, paramsWithCombinedAlias).getResults().getNumFound()); - - ModifiableSolrParams paramsWithMixedCollectionAndAlias = - params("q", "*:*", "collection", "testalias," + COLLECTION2); - assertEquals( - 2, client.query(null, paramsWithMixedCollectionAndAlias).getResults().getNumFound()); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - @Test - public void testRouting() throws Exception { - CollectionAdminRequest.createCollection("routing_collection", "conf", 2, 1) - .process(cluster.getSolrClient()); - cluster.waitForActiveCollection("routing_collection", 2, 2); - - AbstractUpdateRequest request = - new UpdateRequest() - .add(id, "0", "a_t", "hello1") - .add(id, "2", "a_t", "hello2") - .setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true); - - // Test single threaded routed updates for UpdateRequest - NamedList response = getRandomClient().request(request, "routing_collection"); - if (getRandomClient().isDirectUpdatesToLeadersOnly()) { - checkSingleServer(response); - } - CloudSolrClient.RouteResponse rr = (CloudSolrClient.RouteResponse) response; - Map routes = rr.getRoutes(); - Iterator> it = routes.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = it.next(); - String coreUrl = entry.getKey(); - final String baseUrl = URLUtil.extractBaseUrl(coreUrl); - final String coreName = URLUtil.extractCoreFromCoreUrl(coreUrl); - UpdateRequest updateRequest = (UpdateRequest) entry.getValue().getRequest(); - SolrInputDocument doc = updateRequest.getDocuments().get(0); - String id = doc.getField("id").getValue().toString(); - ModifiableSolrParams params = new ModifiableSolrParams(); - params.add("q", "id:" + id); - params.add("distrib", "false"); - QueryRequest queryRequest = new QueryRequest(params); - try (SolrClient solrClient = getHttpSolrClient(baseUrl, coreName)) { - QueryResponse queryResponse = queryRequest.process(solrClient); - SolrDocumentList docList = queryResponse.getResults(); - assertEquals(1, docList.getNumFound()); - } - } - - // Test the deleteById routing for UpdateRequest - - final UpdateResponse uResponse = - new UpdateRequest() - .deleteById("0") - .deleteById("2") - .commit(cluster.getSolrClient(), "routing_collection"); - if (getRandomClient().isDirectUpdatesToLeadersOnly()) { - checkSingleServer(uResponse.getResponse()); - } - - QueryResponse qResponse = getRandomClient().query("routing_collection", new SolrQuery("*:*")); - SolrDocumentList docs = qResponse.getResults(); - assertEquals(0, docs.getNumFound()); - - // Test Multi-Threaded routed updates for UpdateRequest - try (CloudSolrClient threadedClient = - new RandomizingCloudSolrClientBuilder( - Collections.singletonList(cluster.getZkServer().getZkAddress()), Optional.empty()) - .sendUpdatesOnlyToShardLeaders() - .withParallelUpdates(true) - .withDefaultCollection("routing_collection") - .build()) { - response = threadedClient.request(request); - if (threadedClient.isDirectUpdatesToLeadersOnly()) { - checkSingleServer(response); - } - rr = (CloudSolrClient.RouteResponse) response; - routes = rr.getRoutes(); - it = routes.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = it.next(); - String coreUrl = entry.getKey(); - final String baseUrl = URLUtil.extractBaseUrl(coreUrl); - final String coreName = URLUtil.extractCoreFromCoreUrl(coreUrl); - UpdateRequest updateRequest = (UpdateRequest) entry.getValue().getRequest(); - SolrInputDocument doc = updateRequest.getDocuments().get(0); - String id = doc.getField("id").getValue().toString(); - ModifiableSolrParams params = new ModifiableSolrParams(); - params.add("q", "id:" + id); - params.add("distrib", "false"); - QueryRequest queryRequest = new QueryRequest(params); - try (SolrClient solrClient = getHttpSolrClient(baseUrl, coreName)) { - QueryResponse queryResponse = queryRequest.process(solrClient); - SolrDocumentList docList = queryResponse.getResults(); - assertEquals(1, docList.getNumFound()); - } - } - } - - // Test that queries with _route_ params are routed by the client - - // Track request counts on each node before query calls - ClusterState clusterState = cluster.getSolrClient().getClusterState(); - DocCollection col = clusterState.getCollection("routing_collection"); - Map requestCountsMap = new HashMap<>(); - for (Slice slice : col.getSlices()) { - for (Replica replica : slice.getReplicas()) { - String baseURL = replica.getBaseUrl(); - requestCountsMap.put(baseURL, getNumSelectRequests(baseURL)); - } - } - - // Collect the base URLs of the replicas of shard that's expected to be hit - DocRouter router = col.getRouter(); - Collection expectedSlices = router.getSearchSlicesSingle("0", null, col); - Set expectedBaseURLs = new HashSet<>(); - for (Slice expectedSlice : expectedSlices) { - for (Replica replica : expectedSlice.getReplicas()) { - expectedBaseURLs.add(replica.getBaseUrl()); - } - } - - assertTrue( - "expected urls is not fewer than all urls! expected=" - + expectedBaseURLs - + "; all=" - + requestCountsMap.keySet(), - expectedBaseURLs.size() < requestCountsMap.size()); - - // Calculate a number of shard keys that route to the same shard. - int n; - if (TEST_NIGHTLY) { - n = random().nextInt(999) + 2; - } else { - n = random().nextInt(9) + 2; - } - - List expectedSlicesList = List.copyOf(expectedSlices); - List sameShardRoutes = new ArrayList<>(); - sameShardRoutes.add("0"); - for (int i = 1; i < n; i++) { - String shardKey = Integer.toString(i); - List slices = List.copyOf(router.getSearchSlicesSingle(shardKey, null, col)); - log.info("Expected Slices {}", slices); - if (expectedSlicesList.equals(slices)) { - sameShardRoutes.add(shardKey); - } - } - - assertTrue(sameShardRoutes.size() > 1); - - // Do N queries with _route_ parameter to the same shard - for (int i = 0; i < n; i++) { - ModifiableSolrParams solrParams = new ModifiableSolrParams(); - solrParams.set(CommonParams.Q, "*:*"); - solrParams.set( - ShardParams._ROUTE_, sameShardRoutes.get(random().nextInt(sameShardRoutes.size()))); - if (log.isInfoEnabled()) { - log.info("output: {}", getRandomClient().query("routing_collection", solrParams)); - } - } - - // Request counts increase from expected nodes should aggregate to 1000, while there should be - // no increase in unexpected nodes. - Double increaseFromExpectedUrls = 0.0; - Double increaseFromUnexpectedUrls = 0.0; - Map numRequestsToUnexpectedUrls = new HashMap<>(); - for (Slice slice : col.getSlices()) { - for (Replica replica : slice.getReplicas()) { - String baseURL = replica.getBaseUrl(); - - Double prevNumRequests = requestCountsMap.get(baseURL); - Double curNumRequests = getNumSelectRequests(baseURL); - - double delta = curNumRequests - prevNumRequests; - if (expectedBaseURLs.contains(baseURL)) { - increaseFromExpectedUrls += delta; - } else { - increaseFromUnexpectedUrls += delta; - numRequestsToUnexpectedUrls.put(baseURL, delta); - } - } - } - - assertEquals( - "Unexpected number of requests to expected URLs", n, increaseFromExpectedUrls, 0.0); - assertEquals( - "Unexpected number of requests to unexpected URLs: " + numRequestsToUnexpectedUrls, - 0, - increaseFromUnexpectedUrls, - 0.0); - } - - /** - * Tests if the specification of 'shards.preference=replica.location:local' in the query-params - * limits the distributed query to locally hosted shards only - */ - @Test - public void queryWithLocalShardsPreferenceRulesTest() throws Exception { - - String collectionName = "localShardsTestColl"; - - int liveNodes = cluster.getJettySolrRunners().size(); - - // For this case every shard should have all its cores on the same node. - // Hence, the below configuration for our collection - CollectionAdminRequest.createCollection(collectionName, "conf", liveNodes, liveNodes) - .processAndWait(cluster.getSolrClient(), TIMEOUT); - cluster.waitForActiveCollection(collectionName, liveNodes, liveNodes * liveNodes); - // Add some new documents - new UpdateRequest() - .add(id, "0", "a_t", "hello1") - .add(id, "2", "a_t", "hello2") - .add(id, "3", "a_t", "hello2") - .commit(getRandomClient(), collectionName); - - queryWithShardsPreferenceRules(getRandomClient(), collectionName); - } - - @SuppressWarnings("deprecation") - private void queryWithShardsPreferenceRules(CloudSolrClient cloudClient, String collectionName) - throws Exception { - SolrQuery qRequest = new SolrQuery("*:*"); - - ModifiableSolrParams qParams = new ModifiableSolrParams(); - qParams.add( - ShardParams.SHARDS_PREFERENCE, - ShardParams.SHARDS_PREFERENCE_REPLICA_LOCATION + ":" + ShardParams.REPLICA_LOCAL); - qParams.add(ShardParams.SHARDS_INFO, "true"); - qRequest.add(qParams); - - // CloudSolrClient sends the request to some node. - // And since all the nodes are hosting cores from all shards, the - // distributed query formed by this node will select cores from the - // local shards only - QueryResponse qResponse = cloudClient.query(collectionName, qRequest); - - Object shardsInfo = qResponse.getResponse().get(ShardParams.SHARDS_INFO); - assertNotNull("Unable to obtain " + ShardParams.SHARDS_INFO, shardsInfo); - - // Iterate over shards-info and check what cores responded - SimpleOrderedMap shardsInfoMap = (SimpleOrderedMap) shardsInfo; - @SuppressWarnings({"unchecked"}) - Iterator> itr = shardsInfoMap.asMap(100).entrySet().iterator(); - List shardAddresses = new ArrayList(); - while (itr.hasNext()) { - Map.Entry e = itr.next(); - assertTrue( - "Did not find map-type value in " + ShardParams.SHARDS_INFO, e.getValue() instanceof Map); - String shardAddress = (String) ((Map) e.getValue()).get("shardAddress"); - assertNotNull( - ShardParams.SHARDS_INFO + " did not return 'shardAddress' parameter", shardAddress); - shardAddresses.add(shardAddress); - } - if (log.isInfoEnabled()) { - log.info("Shards giving the response: {}", Arrays.toString(shardAddresses.toArray())); - } - - // Make sure the distributed queries were directed to a single node only - Set ports = new HashSet(); - for (String shardAddr : shardAddresses) { - URI uri = URI.create(shardAddr); - ports.add(uri.getPort()); - } - - // This assertion would hold true as long as every shard has a core on each node - assertTrue( - "Response was not received from shards on a single node", - shardAddresses.size() > 1 && ports.size() == 1); - } - - /** Tests if the 'shards.preference' parameter works with single-sharded collections. */ - @Test - public void singleShardedPreferenceRules() throws Exception { - String collectionName = "singleShardPreferenceTestColl"; - - int liveNodes = cluster.getJettySolrRunners().size(); - - // For testing replica.type, we want to have all replica types available for the collection - CollectionAdminRequest.createCollection( - collectionName, "conf", 1, liveNodes / 3, liveNodes / 3, liveNodes / 3) - .processAndWait(cluster.getSolrClient(), TIMEOUT); - cluster.waitForActiveCollection(collectionName, 1, liveNodes); - - // Add some new documents - new UpdateRequest() - .add(id, "0", "a_t", "hello1") - .add(id, "2", "a_t", "hello2") - .add(id, "3", "a_t", "hello2") - .commit(getRandomClient(), collectionName); - - // Run the actual test for 'queryReplicaType' - queryReplicaType(getRandomClient(), Replica.Type.PULL, collectionName); - queryReplicaType(getRandomClient(), Replica.Type.TLOG, collectionName); - queryReplicaType(getRandomClient(), Replica.Type.NRT, collectionName); - } - - private void queryReplicaType( - CloudSolrClient cloudClient, Replica.Type typeToQuery, String collectionName) - throws Exception { - SolrQuery qRequest = new SolrQuery("*:*"); - - ModifiableSolrParams qParams = new ModifiableSolrParams(); - qParams.add( - ShardParams.SHARDS_PREFERENCE, - ShardParams.SHARDS_PREFERENCE_REPLICA_TYPE + ":" + typeToQuery.toString()); - qParams.add(ShardParams.SHARDS_INFO, "true"); - qRequest.add(qParams); - - Map replicaTypeToReplicas = - mapReplicasToReplicaType(getCollectionState(collectionName)); - - QueryResponse qResponse = cloudClient.query(collectionName, qRequest); - - Object shardsInfo = qResponse.getResponse().get(ShardParams.SHARDS_INFO); - assertNotNull("Unable to obtain " + ShardParams.SHARDS_INFO, shardsInfo); - - // Iterate over shards-info and check what cores responded - SimpleOrderedMap shardsInfoMap = (SimpleOrderedMap) shardsInfo; - @SuppressWarnings({"unchecked"}) - Iterator> itr = shardsInfoMap.asMap(100).entrySet().iterator(); - List shardAddresses = new ArrayList(); - while (itr.hasNext()) { - Map.Entry e = itr.next(); - assertTrue( - "Did not find map-type value in " + ShardParams.SHARDS_INFO, e.getValue() instanceof Map); - String shardAddress = (String) ((Map) e.getValue()).get("shardAddress"); - if (shardAddress.endsWith("/")) { - shardAddress = shardAddress.substring(0, shardAddress.length() - 1); - } - assertNotNull( - ShardParams.SHARDS_INFO + " did not return 'shardAddress' parameter", shardAddress); - shardAddresses.add(shardAddress); - } - assertEquals( - "Shard addresses must be of size 1, since there is only 1 shard in the collection", - 1, - shardAddresses.size()); - - assertEquals( - "Make sure that the replica queried was the replicaType desired", - typeToQuery.toString().toUpperCase(Locale.ROOT), - replicaTypeToReplicas.get(shardAddresses.get(0)).toUpperCase(Locale.ROOT)); - } - - private Double getNumSelectRequests(String baseUrl) throws SolrServerException, IOException { - return SolrJMetricTestUtils.getNumCoreRequests( - baseUrl, "routing_collection", "QUERY", "/select"); - } - - @Test - public void testNonRetryableRequests() throws Exception { - String collection = getSaferTestName(); - - try (CloudSolrClient client = - new RandomizingCloudSolrClientBuilder( - Collections.singletonList(cluster.getZkServer().getZkAddress()), Optional.empty()) - .withDefaultCollection(collection) - .build()) { - // important to have one replica on each node - RequestStatusState state = - CollectionAdminRequest.createCollection(collection, "conf", 1, NODE_COUNT) - .processAndWait(client, 60); - if (state == RequestStatusState.COMPLETED) { - cluster.waitForActiveCollection(collection, 1, NODE_COUNT); - - Map adminPathToMbean = new HashMap<>(CommonParams.ADMIN_PATHS.size()); - adminPathToMbean.put( - CommonParams.COLLECTIONS_HANDLER_PATH, CollectionsHandler.class.getName()); - adminPathToMbean.put(CommonParams.CORES_HANDLER_PATH, CoreAdminHandler.class.getName()); - adminPathToMbean.put( - CommonParams.CONFIGSETS_HANDLER_PATH, ConfigSetsHandler.class.getName()); - // we do not add the authc/authz handlers because they do not currently expose any mbeans - - for (String adminPath : adminPathToMbean.keySet()) { - long errorsBefore = 0; - for (JettySolrRunner runner : cluster.getJettySolrRunners()) { - Double numRequests = - SolrJMetricTestUtils.getNumNodeRequestErrors( - runner.getBaseUrl().toString(), SolrRequestType.ADMIN.name(), adminPath); - errorsBefore += numRequests.longValue(); - if (log.isInfoEnabled()) { - log.info( - "Found {} requests to {} on {}", numRequests, adminPath, runner.getBaseUrl()); - } - } - - ModifiableSolrParams params = new ModifiableSolrParams(); - params.set("action", "foobar"); // this should cause an error - - var request = - new GenericSolrRequest(METHOD.GET, adminPath, SolrRequestType.ADMIN, params); - try { - NamedList resp = client.request(request); - fail("call to foo for admin path " + adminPath + " should have failed"); - } catch (Exception e) { - // expected - } - long errorsAfter = 0; - for (JettySolrRunner runner : cluster.getJettySolrRunners()) { - Double numRequests = - SolrJMetricTestUtils.getNumNodeRequestErrors( - runner.getBaseUrl().toString(), SolrRequestType.ADMIN.name(), adminPath); - errorsAfter += numRequests.longValue(); - if (log.isInfoEnabled()) { - log.info( - "Found {} requests to {} on {}", numRequests, adminPath, runner.getBaseUrl()); - } - } - assertEquals(errorsBefore + 1, errorsAfter); - } - } else { - fail("Collection could not be created within 60 seconds"); - } - } - } - - @Test - public void checkCollectionParameters() throws Exception { - - try (CloudSolrClient client = - new RandomizingCloudSolrClientBuilder( - Collections.singletonList(cluster.getZkServer().getZkAddress()), Optional.empty()) - .withDefaultCollection("multicollection1") - .build()) { - - String async1 = - CollectionAdminRequest.createCollection("multicollection1", "conf", 2, 1) - .processAsync(client); - String async2 = - CollectionAdminRequest.createCollection("multicollection2", "conf", 2, 1) - .processAsync(client); - - CollectionAdminRequest.waitForAsyncRequest(async1, client, TIMEOUT); - CollectionAdminRequest.waitForAsyncRequest(async2, client, TIMEOUT); - cluster.waitForActiveCollection("multicollection1", 2, 2); - cluster.waitForActiveCollection("multicollection2", 2, 2); - - List docs = new ArrayList<>(3); - for (int i = 0; i < 3; i++) { - SolrInputDocument doc = new SolrInputDocument(); - doc.addField(id, Integer.toString(i)); - doc.addField("a_t", "hello"); - docs.add(doc); - } - - client.add(docs); // default - will add them to multicollection1 - client.commit(); - - ModifiableSolrParams queryParams = new ModifiableSolrParams(); - queryParams.add("q", "*:*"); - assertEquals(3, client.query(queryParams).getResults().size()); - assertEquals(0, client.query("multicollection2", queryParams).getResults().size()); - - SolrQuery query = new SolrQuery("*:*"); - query.set("collection", "multicollection2"); - assertEquals(0, client.query(query).getResults().size()); - - client.add("multicollection2", docs); - client.commit("multicollection2"); - - assertEquals(3, client.query("multicollection2", queryParams).getResults().size()); - } - } - - @Test - public void stateVersionParamTest() throws Exception { - String COLLECTION = getSaferTestName(); - - CollectionAdminRequest.createCollection(COLLECTION, "conf", 2, 1) - .process(cluster.getSolrClient()); - cluster.waitForActiveCollection(COLLECTION, 2, 2); - - DocCollection coll = cluster.getSolrClient().getClusterState().getCollection(COLLECTION); - Replica r = coll.getSlices().iterator().next().getReplicas().iterator().next(); - - SolrQuery q = new SolrQuery().setQuery("*:*"); - RemoteSolrException sse = null; - - try (SolrClient solrClient = getHttpSolrClient(r.getBaseUrl(), COLLECTION)) { - - if (log.isInfoEnabled()) { - log.info("should work query, result {}", solrClient.query(q)); - } - // no problem - q.setParam(CloudSolrClient.STATE_VERSION, COLLECTION + ":" + coll.getZNodeVersion()); - if (log.isInfoEnabled()) { - log.info("2nd query , result {}", solrClient.query(q)); - } - // no error yet good - - q.setParam( - CloudSolrClient.STATE_VERSION, - COLLECTION + ":" + (coll.getZNodeVersion() - 1)); // an older version expect error - - QueryResponse rsp = solrClient.query(q); - @SuppressWarnings({"rawtypes"}) - Map m = - (Map) rsp.getResponse().get(CloudSolrClient.STATE_VERSION, rsp.getResponse().size() - 1); - assertNotNull( - "Expected an extra information from server with the list of invalid collection states", - m); - assertNotNull(m.get(COLLECTION)); - } - - // now send the request to another node that does not serve the collection - - Set allNodesOfColl = new HashSet<>(); - for (Slice slice : coll.getSlices()) { - for (Replica replica : slice.getReplicas()) { - allNodesOfColl.add(replica.getBaseUrl()); - } - } - String theNode = null; - Set liveNodes = cluster.getSolrClient().getClusterState().getLiveNodes(); - for (String s : liveNodes) { - String n = cluster.getZkStateReader().getBaseUrlForNodeName(s); - if (!allNodesOfColl.contains(n)) { - theNode = n; - break; - } - } - log.info("the node which does not serve this collection{} ", theNode); - assertNotNull(theNode); - - try (SolrClient solrClient = getHttpSolrClient(theNode, COLLECTION)) { - - q.setParam(CloudSolrClient.STATE_VERSION, COLLECTION + ":" + (coll.getZNodeVersion() - 1)); - try { - QueryResponse rsp = solrClient.query(q); - log.info("error was expected"); - } catch (RemoteSolrException e) { - sse = e; - } - assertNotNull(sse); - assertEquals( - " Error code should be 510", SolrException.ErrorCode.INVALID_STATE.code, sse.code()); - } - } - - @Test - public void testShutdown() throws IOException { - try (CloudSolrClient client = - new RandomizingCloudSolrClientBuilder( - Collections.singletonList(DEAD_HOST_1), Optional.empty()) - .build()) { - try (ZkClientClusterStateProvider zkClientClusterStateProvider = - ZkClientClusterStateProvider.from(client)) { - zkClientClusterStateProvider.setZkConnectTimeout(100); - SolrException ex = expectThrows(SolrException.class, client::connect); - assertTrue(ex.getCause() instanceof TimeoutException); - } - } - } - - @Test - public void testWrongZkChrootTest() throws IOException { - try (CloudSolrClient client = - new RandomizingCloudSolrClientBuilder( - Collections.singletonList(cluster.getZkServer().getZkAddress() + "/xyz/foo"), - Optional.empty()) - .build()) { - try (ZkClientClusterStateProvider zkClientClusterStateProvider = - ZkClientClusterStateProvider.from(client)) { - zkClientClusterStateProvider.setZkConnectTimeout(1000 * 60); - SolrException ex = expectThrows(SolrException.class, client::connect); - assertThat( - "Wrong error message for empty chRoot", - ex.getMessage(), - Matchers.containsString("cluster not found/not ready")); - assertThat( - "Wrong node missing message for empty chRoot", - ex.getMessage(), - Matchers.containsString( - "Expected node '" + ZkStateReader.ALIASES + "' does not exist")); - } - } - } - - @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); - } - } - - @Test - public void testVersionsAreReturned() throws Exception { - String collection = getSaferTestName(); - - CollectionAdminRequest.createCollection(collection, "conf", 2, 1) - .process(cluster.getSolrClient()); - cluster.waitForActiveCollection(collection, 2, 2); - - // assert that "adds" are returned - UpdateRequest updateRequest = - new UpdateRequest().add("id", "1", "a_t", "hello1").add("id", "2", "a_t", "hello2"); - updateRequest.setParam(UpdateParams.VERSIONS, Boolean.TRUE.toString()); - - NamedList response = updateRequest.commit(getRandomClient(), collection).getResponse(); - Object addsObject = response.get("adds"); - - assertNotNull("There must be a adds parameter", addsObject); - assertTrue(addsObject instanceof NamedList); - NamedList adds = (NamedList) addsObject; - assertEquals("There must be 2 versions (one per doc)", 2, adds.size()); - - Map versions = new HashMap<>(); - Object object = adds.get("1"); - assertNotNull("There must be a version for id 1", object); - assertTrue("Version for id 1 must be a long", object instanceof Long); - versions.put("1", (Long) object); - - object = adds.get("2"); - assertNotNull("There must be a version for id 2", object); - assertTrue("Version for id 2 must be a long", object instanceof Long); - versions.put("2", (Long) object); - - QueryResponse resp = getRandomClient().query(collection, new SolrQuery("*:*")); - assertEquals( - "There should be one document because overwrite=true", 2, resp.getResults().getNumFound()); - - for (SolrDocument doc : resp.getResults()) { - Long version = versions.get(doc.getFieldValue("id")); - assertEquals( - "Version on add must match _version_ field", version, doc.getFieldValue("_version_")); - } - - // assert that "deletes" are returned - UpdateRequest deleteRequest = new UpdateRequest().deleteById("1"); - deleteRequest.setParam(UpdateParams.VERSIONS, Boolean.TRUE.toString()); - response = deleteRequest.commit(getRandomClient(), collection).getResponse(); - Object deletesObject = response.get("deletes"); - assertNotNull("There must be a deletes parameter", deletesObject); - NamedList deletes = (NamedList) deletesObject; - assertEquals("There must be 1 version", 1, deletes.size()); - } - - @Test - public void testInitializationWithSolrUrls() throws Exception { - String COLLECTION = getSaferTestName(); - - CollectionAdminRequest.createCollection(COLLECTION, "conf", 2, 1) - .process(cluster.getSolrClient()); - cluster.waitForActiveCollection(COLLECTION, 2, 2); - CloudSolrClient client = httpBasedCloudSolrClient; - SolrInputDocument doc = new SolrInputDocument("id", "1", "title_s", "my doc"); - client.add(COLLECTION, doc); - client.commit(COLLECTION); - assertEquals(1, client.query(COLLECTION, params("q", "*:*")).getResults().getNumFound()); - } - - @Test - public void testCollectionDoesntExist() throws Exception { - CloudSolrClient client = getRandomClient(); - SolrInputDocument doc = new SolrInputDocument("id", "1", "title_s", "my doc"); - SolrException ex = - expectThrows(SolrException.class, () -> client.add("boguscollectionname", doc)); - assertEquals("Collection not found: boguscollectionname", ex.getMessage()); - } - - public void testRetryUpdatesWhenClusterStateIsStale() throws Exception { - final String COL = "stale_state_test_col"; - assertTrue(cluster.getJettySolrRunners().size() >= 2); - - final JettySolrRunner old_leader_node = cluster.getJettySolrRunners().get(0); - final JettySolrRunner new_leader_node = cluster.getJettySolrRunners().get(1); - - // start with exactly 1 shard/replica... - assertEquals( - "Couldn't create collection", - 0, - CollectionAdminRequest.createCollection(COL, "conf", 1, 1) - .setCreateNodeSet(old_leader_node.getNodeName()) - .process(cluster.getSolrClient()) - .getStatus()); - cluster.waitForActiveCollection(COL, 1, 1); - - // determine the coreNodeName of only current replica - Collection slices = - cluster.getSolrClient().getClusterState().getCollection(COL).getSlices(); - assertEquals(1, slices.size()); // sanity check - Slice slice = slices.iterator().next(); - assertEquals(1, slice.getReplicas().size()); // sanity check - final String old_leader_core_node_name = slice.getLeader().getName(); - - // NOTE: creating our own CloudSolrClient with settings for this specific test... - try (CloudSolrClient stale_client = - new RandomizingCloudSolrClientBuilder( - Collections.singletonList(cluster.getZkServer().getZkAddress()), Optional.empty()) - .sendDirectUpdatesToAnyShardReplica() - .withParallelUpdates(true) - // don't let collection cache entries get expired, even on a slow machine... - .withCollectionCacheTtl(Integer.MAX_VALUE) - .withDefaultCollection(COL) - .build()) { - - // do a query to populate stale_client's cache... - assertEquals(0, stale_client.query(new SolrQuery("*:*")).getResults().getNumFound()); - - // add 1 replica on a diff node... - assertEquals( - "Couldn't create collection", - 0, - CollectionAdminRequest.addReplicaToShard(COL, "shard1") - .setNode(new_leader_node.getNodeName()) - // NOTE: don't use our stale_client for this -- don't tip it off of a collection - // change - .process(cluster.getSolrClient()) - .getStatus()); - AbstractFullDistribZkTestBase.waitForRecoveriesToFinish( - COL, cluster.getZkStateReader(), true, true, 330); - // ...and delete our original leader. - assertEquals( - "Couldn't create collection", - 0, - CollectionAdminRequest.deleteReplica(COL, "shard1", old_leader_core_node_name) - // NOTE: don't use our stale_client for this -- don't tip it off of a collection - // change - .process(cluster.getSolrClient()) - .getStatus()); - AbstractFullDistribZkTestBase.waitForRecoveriesToFinish( - COL, cluster.getZkStateReader(), true, true, 330); - - // stale_client's collection state cache should now only point at a leader that no longer - // exists. - - // attempt a (direct) update that should succeed in spite of cached cluster state - // pointing solely to a node that's no longer part of our collection... - assertEquals(0, (new UpdateRequest().add("id", "1").commit(stale_client, COL)).getStatus()); - assertEquals(1, stale_client.query(new SolrQuery("*:*")).getResults().getNumFound()); - } - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private static void checkSingleServer(NamedList response) { - final CloudSolrClient.RouteResponse rr = (CloudSolrClient.RouteResponse) response; - final Map routes = rr.getRoutes(); - final Iterator> it = routes.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = it.next(); - assertEquals( - "wrong number of servers: " + entry.getValue().getEndpoints(), - 1, - entry.getValue().getEndpoints().size()); - } - } - - /** - * Tests if the specification of 'preferReplicaTypes` in the query-params limits the distributed - * query to locally hosted shards only - */ - @Test - public void preferReplicaTypesTest() throws Exception { - - String collectionName = "replicaTypesTestColl"; - - int liveNodes = cluster.getJettySolrRunners().size(); - - // For these tests we need to have multiple replica types. - // Hence, the below configuration for our collection - int pullReplicas = Math.max(1, liveNodes - 2); - CollectionAdminRequest.createCollection(collectionName, "conf", liveNodes, 1, 1, pullReplicas) - .processAndWait(cluster.getSolrClient(), TIMEOUT); - cluster.waitForActiveCollection(collectionName, liveNodes, liveNodes * (2 + pullReplicas)); - - // Add some new documents - new UpdateRequest() - .add(id, "0", "a_t", "hello1") - .add(id, "2", "a_t", "hello2") - .add(id, "3", "a_t", "hello2") - .commit(getRandomClient(), collectionName); - - // Run the actual tests for 'shards.preference=replica.type:*' - queryWithPreferReplicaTypes(getRandomClient(), "PULL", collectionName); - queryWithPreferReplicaTypes(getRandomClient(), "PULL|TLOG", collectionName); - queryWithPreferReplicaTypes(getRandomClient(), "TLOG", collectionName); - queryWithPreferReplicaTypes(getRandomClient(), "TLOG|PULL", collectionName); - queryWithPreferReplicaTypes(getRandomClient(), "NRT", collectionName); - queryWithPreferReplicaTypes(getRandomClient(), "NRT|PULL", collectionName); - CollectionAdminRequest.deleteCollection(collectionName) - .processAndWait(cluster.getSolrClient(), TIMEOUT); - } - - private void queryWithPreferReplicaTypes( - CloudSolrClient cloudClient, String preferReplicaTypes, String collectionName) - throws Exception { - SolrQuery qRequest = new SolrQuery("*:*"); - ModifiableSolrParams qParams = new ModifiableSolrParams(); - - final List preferredTypes = Arrays.asList(preferReplicaTypes.split("\\|")); - StringBuilder rule = new StringBuilder(); - preferredTypes.forEach( - type -> { - if (rule.length() != 0) { - rule.append(','); - } - rule.append(ShardParams.SHARDS_PREFERENCE_REPLICA_TYPE); - rule.append(':'); - rule.append(type); - }); - qParams.add(ShardParams.SHARDS_PREFERENCE, rule.toString()); - qParams.add(ShardParams.SHARDS_INFO, "true"); - qRequest.add(qParams); - - // CloudSolrClient sends the request to some node. - // And since all the nodes are hosting cores from all shards, the - // distributed query formed by this node will select cores from the - // local shards only - QueryResponse qResponse = cloudClient.query(collectionName, qRequest); - - Object shardsInfo = qResponse.getResponse().get(ShardParams.SHARDS_INFO); - assertNotNull("Unable to obtain " + ShardParams.SHARDS_INFO, shardsInfo); - - Map replicaTypeMap = new HashMap<>(); - DocCollection collection = getCollectionState(collectionName); - for (Slice slice : collection.getSlices()) { - for (Replica replica : slice.getReplicas()) { - String coreUrl = replica.getCoreUrl(); - // It seems replica reports its core URL with a trailing slash while shard - // info returned from the query doesn't. - if (coreUrl.endsWith("/")) { - coreUrl = coreUrl.substring(0, coreUrl.length() - 1); - } - replicaTypeMap.put(coreUrl, replica.getType().toString()); - } - } - - // Iterate over shards-info and check that replicas of correct type responded - SimpleOrderedMap shardsInfoMap = (SimpleOrderedMap) shardsInfo; - @SuppressWarnings({"unchecked"}) - Iterator> itr = shardsInfoMap.asMap(100).entrySet().iterator(); - List shardAddresses = new ArrayList<>(); - while (itr.hasNext()) { - Map.Entry e = itr.next(); - assertTrue( - "Did not find map-type value in " + ShardParams.SHARDS_INFO, e.getValue() instanceof Map); - String shardAddress = (String) ((Map) e.getValue()).get("shardAddress"); - assertNotNull( - ShardParams.SHARDS_INFO + " did not return 'shardAddress' parameter", shardAddress); - assertTrue(replicaTypeMap.containsKey(shardAddress)); - assertEquals(0, preferredTypes.indexOf(replicaTypeMap.get(shardAddress))); - shardAddresses.add(shardAddress); - } - assertTrue("No responses", shardAddresses.size() > 0); - if (log.isInfoEnabled()) { - log.info("Shards giving the response: {}", Arrays.toString(shardAddresses.toArray())); - } - } - - @Test - public void testPing() throws Exception { - final String testCollection = "ping_test"; - CollectionAdminRequest.createCollection(testCollection, "conf", 2, 1) - .process(cluster.getSolrClient()); - cluster.waitForActiveCollection(testCollection, 2, 2); - final SolrClient clientUnderTest = getRandomClient(); - - final SolrPingResponse response = clientUnderTest.ping(testCollection); - - assertEquals("This should be OK", 0, response.getStatus()); - } - - public void testPerReplicaStateCollection() throws Exception { - String collection = getSaferTestName(); - - CollectionAdminRequest.createCollection(collection, "conf", 2, 1) - .process(cluster.getSolrClient()); - - String testCollection = "perReplicaState_test"; - String collectionPath = DocCollection.getCollectionPath(testCollection); - - int liveNodes = cluster.getJettySolrRunners().size(); - CollectionAdminRequest.createCollection(testCollection, "conf", 2, 2) - .setPerReplicaState(Boolean.TRUE) - .process(cluster.getSolrClient()); - cluster.waitForActiveCollection(testCollection, 2, 4); - final SolrClient clientUnderTest = getRandomClient(); - final SolrPingResponse response = clientUnderTest.ping(testCollection); - assertEquals("This should be OK", 0, response.getStatus()); - - DocCollection c = cluster.getZkStateReader().getCollection(testCollection); - c.forEachReplica((s, replica) -> assertNotNull(replica.getReplicaState())); - PerReplicaStates prs = PerReplicaStatesOps.fetch(collectionPath, cluster.getZkClient(), null); - assertEquals(4, prs.states.size()); - - JettySolrRunner jsr = null; - try { - jsr = cluster.startJettySolrRunner(); - - // Now let's do an add replica - CollectionAdminRequest.addReplicaToShard(testCollection, "shard1") - .process(cluster.getSolrClient()); - prs = PerReplicaStatesOps.fetch(collectionPath, cluster.getZkClient(), null); - assertEquals(5, prs.states.size()); - - // create a collection with PRS and v2 API - testCollection = "perReplicaState_testv2"; - collectionPath = DocCollection.getCollectionPath(testCollection); - - new V2Request.Builder("/collections") - .withMethod(POST) - .withPayload( - "{\"name\": \"perReplicaState_testv2\", \"config\" : \"conf\", \"numShards\" : 2, \"nrtReplicas\" : 2, \"perReplicaState\" : true}") - .build() - .process(cluster.getSolrClient()); - cluster.waitForActiveCollection(testCollection, 2, 4); - c = cluster.getZkStateReader().getCollection(testCollection); - c.forEachReplica((s, replica) -> assertNotNull(replica.getReplicaState())); - prs = PerReplicaStatesOps.fetch(collectionPath, cluster.getZkClient(), null); - assertEquals(4, prs.states.size()); - } finally { - if (jsr != null) { - cluster.stopJettySolrRunner(jsr); - } - } - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientBadInputTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientBadInputTest.java deleted file mode 100644 index 9522bb62e488..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientBadInputTest.java +++ /dev/null @@ -1,116 +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.apache; - -import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP; - -import java.util.ArrayList; -import java.util.List; -import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.common.util.EnvUtils; -import org.apache.solr.util.ExternalPaths; -import org.apache.solr.util.SolrJettyTestRule; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; - -public class ConcurrentUpdateSolrClientBadInputTest extends SolrTestCaseJ4 { - @ClassRule public static SolrJettyTestRule solrTestRule = new SolrJettyTestRule(); - - private static final List NULL_STR_LIST = null; - private static final List EMPTY_STR_LIST = new ArrayList<>(); - private static final String ANY_COLLECTION = "ANY_COLLECTION"; - private static final int ANY_COMMIT_WITHIN_TIME = -1; - private static final int ANY_QUEUE_SIZE = 1; - private static final int ANY_MAX_NUM_THREADS = 1; - - @BeforeClass - public static void beforeTest() throws Exception { - EnvUtils.setProperty( - ALLOW_PATHS_SYSPROP, ExternalPaths.SERVER_HOME.toAbsolutePath().toString()); - solrTestRule.startSolr(); - solrTestRule.newCollection().withConfigSet(ExternalPaths.TECHPRODUCTS_CONFIGSET).create(); - } - - @Test - public void testDeleteByIdReportsInvalidIdLists() throws Exception { - try (SolrClient client = - new ConcurrentUpdateSolrClient.Builder(solrTestRule.getBaseUrl()) - .withDefaultCollection(ANY_COLLECTION) - .withQueueSize(ANY_QUEUE_SIZE) - .withThreadCount(ANY_MAX_NUM_THREADS) - .build()) { - assertExceptionThrownWithMessageContaining( - IllegalArgumentException.class, - List.of("ids", "null"), - () -> { - client.deleteById(NULL_STR_LIST); - }); - assertExceptionThrownWithMessageContaining( - IllegalArgumentException.class, - List.of("ids", "empty"), - () -> { - client.deleteById(EMPTY_STR_LIST); - }); - assertExceptionThrownWithMessageContaining( - IllegalArgumentException.class, - List.of("ids", "null"), - () -> { - client.deleteById(NULL_STR_LIST, ANY_COMMIT_WITHIN_TIME); - }); - assertExceptionThrownWithMessageContaining( - IllegalArgumentException.class, - List.of("ids", "empty"), - () -> { - client.deleteById(EMPTY_STR_LIST, ANY_COMMIT_WITHIN_TIME); - }); - } - - try (SolrClient client = - new ConcurrentUpdateSolrClient.Builder(solrTestRule.getBaseUrl()) - .withQueueSize(ANY_QUEUE_SIZE) - .withThreadCount(ANY_MAX_NUM_THREADS) - .build()) { - assertExceptionThrownWithMessageContaining( - IllegalArgumentException.class, - List.of("ids", "null"), - () -> { - client.deleteById(ANY_COLLECTION, NULL_STR_LIST); - }); - assertExceptionThrownWithMessageContaining( - IllegalArgumentException.class, - List.of("ids", "empty"), - () -> { - client.deleteById(ANY_COLLECTION, EMPTY_STR_LIST); - }); - assertExceptionThrownWithMessageContaining( - IllegalArgumentException.class, - List.of("ids", "null"), - () -> { - client.deleteById(ANY_COLLECTION, NULL_STR_LIST, ANY_COMMIT_WITHIN_TIME); - }); - assertExceptionThrownWithMessageContaining( - IllegalArgumentException.class, - List.of("ids", "empty"), - () -> { - client.deleteById(ANY_COLLECTION, EMPTY_STR_LIST, ANY_COMMIT_WITHIN_TIME); - }); - } - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientBuilderTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientBuilderTest.java deleted file mode 100644 index 7291c30ceba4..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientBuilderTest.java +++ /dev/null @@ -1,87 +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.apache; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.SocketTimeoutException; -import java.util.concurrent.TimeUnit; -import org.apache.solr.SolrTestCase; -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.apache.ConcurrentUpdateSolrClient.Builder; -import org.junit.Test; - -/** Unit tests for {@link Builder}. */ -public class ConcurrentUpdateSolrClientBuilderTest extends SolrTestCase { - - private static final String ANY_BASE_URL = "http://localhost:8983/solr"; - - @Test(expected = IllegalArgumentException.class) - public void testRejectsMissingBaseSolrUrl() { - new Builder(null).build(); - } - - @Test - @SuppressWarnings({"try"}) - public void testMissingQueueSize() { - try (ConcurrentUpdateSolrClient client = new Builder(ANY_BASE_URL).build()) { - // Do nothing as we just need to test that the only mandatory parameter for building the - // client is the baseSolrUrl - } - } - - /** - * Test that connection timeout information is passed to the HttpSolrClient that handles non add - * operations. - */ - @Test(timeout = 10000) - public void testSocketTimeoutOnCommit() throws IOException, SolrServerException { - InetAddress localHost = InetAddress.getLocalHost(); - try (ServerSocket server = new ServerSocket(0, 1, localHost); - ConcurrentUpdateSolrClient client = - new ConcurrentUpdateSolrClient.Builder( - "http://" - + localHost.getHostAddress() - + ":" - + server.getLocalPort() - + "/noOneThere") - .withSocketTimeout(1, TimeUnit.MILLISECONDS) - .build()) { - // Expecting an exception - client.commit(); - fail(); - } catch (SolrServerException e) { - if (!(e.getCause() instanceof SocketTimeoutException)) { - throw e; - } - // else test passes - } - } - - @Test - public void testDefaultCollectionPassedFromBuilderToClient() throws IOException { - try (SolrClient createdClient = - new ConcurrentUpdateSolrClient.Builder(ANY_BASE_URL) - .withDefaultCollection("aCollection") - .build()) { - assertEquals("aCollection", createdClient.getDefaultCollection()); - } - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientMultiCollectionTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientMultiCollectionTest.java deleted file mode 100644 index c164e548b097..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientMultiCollectionTest.java +++ /dev/null @@ -1,98 +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.apache; - -import java.io.IOException; -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.request.CollectionAdminRequest; -import org.apache.solr.client.solrj.request.SolrQuery; -import org.apache.solr.cloud.SolrCloudTestCase; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.util.ExternalPaths; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -/** - * {@link ConcurrentUpdateSolrClient} reuses the same HTTP connection to send multiple requests. - * These tests ensure that this connection-reuse never results in documents being sent to the wrong - * collection. See SOLR-12803 - */ -public class ConcurrentUpdateSolrClientMultiCollectionTest extends SolrCloudTestCase { - - private static final String COLLECTION_ONE_NAME = "collection1"; - private static final String COLLECTION_TWO_NAME = "collection2"; - - private String solrUrl; - - @BeforeClass - public static void setupCluster() throws Exception { - configureCluster(1).addConfig("conf", ExternalPaths.TECHPRODUCTS_CONFIGSET).configure(); - } - - @Before - public void createCollections() throws Exception { - solrUrl = cluster.getJettySolrRunner(0).getBaseUrl().toString(); - - CollectionAdminRequest.createCollection(COLLECTION_ONE_NAME, "conf", 1, 1) - .process(cluster.getSolrClient()); - CollectionAdminRequest.createCollection(COLLECTION_TWO_NAME, "conf", 1, 1) - .process(cluster.getSolrClient()); - } - - @After - public void deleteCollections() throws Exception { - cluster.deleteAllCollections(); - } - - @Test - public void testEnsureDocumentsSentToCorrectCollection() throws Exception { - int numTotalDocs = 1000; - int numExpectedPerCollection = numTotalDocs / 2; - try (SolrClient client = - new ConcurrentUpdateSolrClient.Builder(solrUrl).withQueueSize(numTotalDocs).build()) { - splitDocumentsAcrossCollections(client, numTotalDocs); - - assertEquals( - numExpectedPerCollection, - client.query(COLLECTION_ONE_NAME, new SolrQuery("*:*")).getResults().getNumFound()); - assertEquals( - numExpectedPerCollection, - client.query(COLLECTION_TWO_NAME, new SolrQuery("*:*")).getResults().getNumFound()); - } - } - - private void splitDocumentsAcrossCollections(SolrClient client, int numTotalDocs) - throws IOException, SolrServerException { - for (int docNum = 0; docNum < numTotalDocs; docNum++) { - final SolrInputDocument doc = new SolrInputDocument(); - doc.setField("id", "value" + docNum); - - if (docNum % 2 == 0) { - client.add(COLLECTION_ONE_NAME, doc); - } else { - client.add(COLLECTION_TWO_NAME, doc); - } - } - - client.commit(COLLECTION_ONE_NAME); - client.commit(COLLECTION_TWO_NAME); - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientTest.java deleted file mode 100644 index 804580f6c2b6..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConcurrentUpdateSolrClientTest.java +++ /dev/null @@ -1,389 +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.apache; - -import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.lang.invoke.MethodHandles; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.http.HttpResponse; -import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.request.JavaBinUpdateRequestCodec; -import org.apache.solr.client.solrj.request.SolrQuery; -import org.apache.solr.client.solrj.request.UpdateRequest; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.common.util.EnvUtils; -import org.apache.solr.common.util.ExecutorUtil; -import org.apache.solr.common.util.SolrNamedThreadFactory; -import org.apache.solr.embedded.JettyConfig; -import org.apache.solr.util.ExternalPaths; -import org.apache.solr.util.SolrJettyTestRule; -import org.eclipse.jetty.ee10.servlet.ServletHolder; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ConcurrentUpdateSolrClientTest extends SolrTestCaseJ4 { - @ClassRule public static SolrJettyTestRule solrTestRule = new SolrJettyTestRule(); - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - /** Mock endpoint where the CUSS being tested in this class sends requests. */ - public static class TestServlet extends HttpServlet - implements JavaBinUpdateRequestCodec.StreamingUpdateHandler { - private static final long serialVersionUID = 1L; - - public static void clear() { - lastMethod = null; - headers = null; - parameters = null; - errorCode = null; - numReqsRcvd.set(0); - numDocsRcvd.set(0); - } - - public static Integer errorCode = null; - public static String lastMethod = null; - public static HashMap headers = null; - public static Map parameters = null; - public static AtomicInteger numReqsRcvd = new AtomicInteger(0); - public static AtomicInteger numDocsRcvd = new AtomicInteger(0); - - public static void setErrorCode(Integer code) { - errorCode = code; - } - - private void setHeaders(HttpServletRequest req) { - Enumeration headerNames = req.getHeaderNames(); - headers = new HashMap<>(); - while (headerNames.hasMoreElements()) { - final String name = headerNames.nextElement(); - headers.put(name, req.getHeader(name)); - } - } - - private void setParameters(HttpServletRequest req) { - // parameters = req.getParameterMap(); - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - numReqsRcvd.incrementAndGet(); - lastMethod = "post"; - recordRequest(req, resp); - - InputStream reqIn = req.getInputStream(); - JavaBinUpdateRequestCodec javabin = new JavaBinUpdateRequestCodec(); - for (; ; ) { - try { - javabin.unmarshal(reqIn, this); - } catch (EOFException e) { - break; // this is expected - } - } - } - - private void recordRequest(HttpServletRequest req, HttpServletResponse resp) { - setHeaders(req); - setParameters(req); - if (null != errorCode) { - try { - resp.sendError(errorCode); - } catch (IOException e) { - throw new RuntimeException("sendError IO fail in TestServlet", e); - } - } - } - - @Override - public void update( - SolrInputDocument document, UpdateRequest req, Integer commitWithin, Boolean override) { - numDocsRcvd.incrementAndGet(); - } - } // end TestServlet - - @BeforeClass - public static void beforeTest() throws Exception { - JettyConfig jettyConfig = - JettyConfig.builder().withServlet(new ServletHolder(TestServlet.class), "/cuss/*").build(); - - EnvUtils.setProperty( - ALLOW_PATHS_SYSPROP, ExternalPaths.SERVER_HOME.toAbsolutePath().toString()); - solrTestRule.startSolr(createTempDir(), new Properties(), jettyConfig); - solrTestRule.newCollection().withConfigSet(ExternalPaths.TECHPRODUCTS_CONFIGSET).create(); - } - - @Test - public void testConcurrentUpdate() throws Exception { - TestServlet.clear(); - - String serverUrl = solrTestRule.getBaseUrl() + "/cuss/foo"; - - int cussThreadCount = 2; - int cussQueueSize = 100; - - // for tracking callbacks from CUSS - final AtomicInteger successCounter = new AtomicInteger(0); - final AtomicInteger errorCounter = new AtomicInteger(0); - final StringBuilder errors = new StringBuilder(); - - @SuppressWarnings("serial") - ConcurrentUpdateSolrClient concurrentClient = - new OutcomeCountingConcurrentUpdateSolrClient.Builder( - serverUrl, successCounter, errorCounter, errors) - .withQueueSize(cussQueueSize) - .withThreadCount(cussThreadCount) - .withPollQueueTime(0) - .build(); - - // ensure it doesn't block where there's nothing to do yet - concurrentClient.blockUntilFinished(); - - int poolSize = 5; - ExecutorService threadPool = - ExecutorUtil.newMDCAwareFixedThreadPool(poolSize, new SolrNamedThreadFactory("testCUSS")); - - int numDocs = 100; - int numRunnables = 5; - for (int r = 0; r < numRunnables; r++) - threadPool.execute(new SendDocsRunnable(String.valueOf(r), numDocs, concurrentClient)); - - // ensure all docs are sent - threadPool.awaitTermination(5, TimeUnit.SECONDS); - threadPool.shutdown(); - - // wait until all requests are processed by CUSS - concurrentClient.blockUntilFinished(); - concurrentClient.shutdownNow(); - - assertEquals("post", TestServlet.lastMethod); - - // expect all requests to be successful - int expectedSuccesses = TestServlet.numReqsRcvd.get(); - assertTrue(expectedSuccesses > 0); // at least one request must have been sent - - assertEquals( - "Expected no errors but got " + errorCounter.get() + ", due to: " + errors.toString(), - 0, - errorCounter.get()); - assertEquals( - "Expected " + expectedSuccesses + " successes, but got " + successCounter.get(), - successCounter.get(), - expectedSuccesses); - - int expectedDocs = numDocs * numRunnables; - assertEquals( - "Expected CUSS to send " + expectedDocs + " but got " + TestServlet.numDocsRcvd.get(), - TestServlet.numDocsRcvd.get(), - expectedDocs); - } - - @Test - public void testCollectionParameters() throws IOException, SolrServerException { - - int cussThreadCount = 2; - int cussQueueSize = 10; - - try (ConcurrentUpdateSolrClient concurrentClient = - (new ConcurrentUpdateSolrClient.Builder(solrTestRule.getBaseUrl())) - .withQueueSize(cussQueueSize) - .withThreadCount(cussThreadCount) - .build()) { - - SolrInputDocument doc = new SolrInputDocument(); - doc.addField("id", "collection"); - concurrentClient.add("collection1", doc); - concurrentClient.commit("collection1"); - - assertEquals( - 1, - concurrentClient - .query("collection1", new SolrQuery("id:collection")) - .getResults() - .getNumFound()); - } - - try (ConcurrentUpdateSolrClient concurrentClient = - (new ConcurrentUpdateSolrClient.Builder(solrTestRule.getBaseUrl())) - .withDefaultCollection(DEFAULT_TEST_CORENAME) - .withQueueSize(cussQueueSize) - .withThreadCount(cussThreadCount) - .build()) { - - assertEquals( - 1, concurrentClient.query(new SolrQuery("id:collection")).getResults().getNumFound()); - } - } - - @Test - public void testConcurrentCollectionUpdate() throws Exception { - - int cussThreadCount = 2; - int cussQueueSize = 100; - int numDocs = 100; - int numRunnables = 5; - int expected = numDocs * numRunnables; - - try (ConcurrentUpdateSolrClient concurrentClient = - (new ConcurrentUpdateSolrClient.Builder(solrTestRule.getBaseUrl())) - .withQueueSize(cussQueueSize) - .withThreadCount(cussThreadCount) - .withPollQueueTime(0) - .build()) { - - // ensure it doesn't block where there's nothing to do yet - concurrentClient.blockUntilFinished(); - - // Delete all existing documents. - concurrentClient.deleteByQuery("collection1", "*:*"); - - int poolSize = 5; - ExecutorService threadPool = - ExecutorUtil.newMDCAwareFixedThreadPool(poolSize, new SolrNamedThreadFactory("testCUSS")); - - for (int r = 0; r < numRunnables; r++) - threadPool.execute( - new SendDocsRunnable(String.valueOf(r), numDocs, concurrentClient, "collection1")); - - // ensure all docs are sent - threadPool.awaitTermination(5, TimeUnit.SECONDS); - threadPool.shutdown(); - - concurrentClient.commit("collection1"); - - assertEquals( - expected, - concurrentClient.query("collection1", new SolrQuery("*:*")).getResults().getNumFound()); - - // wait until all requests are processed by CUSS - concurrentClient.blockUntilFinished(); - concurrentClient.shutdownNow(); - } - - try (ConcurrentUpdateSolrClient concurrentClient = - (new ConcurrentUpdateSolrClient.Builder(solrTestRule.getBaseUrl())) - .withDefaultCollection(DEFAULT_TEST_CORENAME) - .withQueueSize(cussQueueSize) - .withThreadCount(cussThreadCount) - .build()) { - - assertEquals( - expected, concurrentClient.query(new SolrQuery("*:*")).getResults().getNumFound()); - } - } - - static class SendDocsRunnable implements Runnable { - - private String id; - private int numDocs; - private SolrClient cuss; - private String collection; - - SendDocsRunnable(String id, int numDocs, SolrClient cuss) { - this(id, numDocs, cuss, null); - } - - SendDocsRunnable(String id, int numDocs, SolrClient cuss, String collection) { - this.id = id; - this.numDocs = numDocs; - this.cuss = cuss; - this.collection = collection; - } - - @Override - public void run() { - for (int d = 0; d < numDocs; d++) { - SolrInputDocument doc = new SolrInputDocument(); - String docId = id + "_" + d; - doc.setField("id", docId); - UpdateRequest req = new UpdateRequest(); - req.add(doc); - try { - if (this.collection == null) cuss.request(req); - else cuss.request(req, this.collection); - } catch (Throwable t) { - log.error("error making request", t); - } - } - } - } - - static class OutcomeCountingConcurrentUpdateSolrClient extends ConcurrentUpdateSolrClient { - private final AtomicInteger successCounter; - private final AtomicInteger failureCounter; - private final StringBuilder errors; - - public OutcomeCountingConcurrentUpdateSolrClient(Builder builder) { - super(builder); - this.successCounter = builder.successCounter; - this.failureCounter = builder.failureCounter; - this.errors = builder.errors; - } - - @Override - public void handleError(Throwable ex) { - failureCounter.incrementAndGet(); - errors.append(" " + ex); - } - - @Override - public void onSuccess(HttpResponse resp) { - successCounter.incrementAndGet(); - } - - static class Builder extends ConcurrentUpdateSolrClient.Builder { - protected final AtomicInteger successCounter; - protected final AtomicInteger failureCounter; - protected final StringBuilder errors; - - public Builder( - String baseSolrUrl, - AtomicInteger successCounter, - AtomicInteger failureCounter, - StringBuilder errors) { - super(baseSolrUrl); - this.successCounter = successCounter; - this.failureCounter = failureCounter; - this.errors = errors; - } - - @Override - public OutcomeCountingConcurrentUpdateSolrClient build() { - return new OutcomeCountingConcurrentUpdateSolrClient(this); - } - } - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConnectionReuseTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConnectionReuseTest.java deleted file mode 100644 index 2a5a4241cc19..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/ConnectionReuseTest.java +++ /dev/null @@ -1,237 +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.apache; - -import java.io.IOException; -import java.lang.invoke.MethodHandles; -import java.net.URL; -import java.util.Collections; -import java.util.Optional; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.http.HttpClientConnection; -import org.apache.http.HttpConnectionMetrics; -import org.apache.http.HttpException; -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpVersion; -import org.apache.http.client.HttpClient; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.conn.ConnectionPoolTimeoutException; -import org.apache.http.conn.ConnectionRequest; -import org.apache.http.conn.routing.HttpRoute; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.message.BasicHttpRequest; -import org.apache.solr.SolrTestCaseJ4.SuppressSSL; -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.request.CollectionAdminRequest; -import org.apache.solr.cloud.SolrCloudTestCase; -import org.apache.solr.update.AddUpdateCommand; -import org.apache.solr.util.TestInjection; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@SuppressSSL -@Ignore("https://issues.apache.org/jira/browse/SOLR-17962") -public class ConnectionReuseTest extends SolrCloudTestCase { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - private AtomicInteger id = new AtomicInteger(); - private HttpClientContext context = HttpClientContext.create(); - - private static final String COLLECTION = "collection1"; - - @BeforeClass - public static void setupCluster() throws Exception { - TestInjection.failUpdateRequests = "true:100"; - configureCluster(1) - .addConfig( - "config", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf")) - .configure(); - - CollectionAdminRequest.createCollection(COLLECTION, "config", 1, 1) - .processAndWait(cluster.getSolrClient(), DEFAULT_TIMEOUT); - - cluster - .getZkStateReader() - .waitForState( - COLLECTION, - DEFAULT_TIMEOUT, - TimeUnit.SECONDS, - (n, c) -> SolrCloudTestCase.replicasForCollectionAreFullyActive(n, c, 1, 1)); - } - - private SolrClient buildClient(CloseableHttpClient httpClient, URL url) { - switch (random().nextInt(3)) { - case 0: - // currently, only testing with 1 thread - return new ConcurrentUpdateSolrClient.Builder(url.toString()) - .withDefaultCollection(COLLECTION) - .withHttpClient(httpClient) - .withQueueSize(6) - .withThreadCount(1) - .build(); - case 1: - return new HttpSolrClient.Builder(url.toString()) - .withDefaultCollection(COLLECTION) - .withHttpClient(httpClient) - .build(); - case 2: - var builder = - new RandomizingCloudSolrClientBuilder( - Collections.singletonList(cluster.getZkServer().getZkAddress()), Optional.empty()); - boolean shardLeadersOnly = random().nextBoolean(); - if (shardLeadersOnly) { - builder.sendUpdatesOnlyToShardLeaders(); - } else { - builder.sendUpdatesToAllReplicasInShard(); - } - builder.withDefaultCollection(COLLECTION); - return builder - .withHttpClient(httpClient) - .withConnectionTimeout(30000) - .withSocketTimeout(60000) - .build(); - } - throw new RuntimeException("impossible"); - } - - @Test - public void testConnectionReuse() throws Exception { - - URL url = cluster.getJettySolrRunners().get(0).getBaseUrl(); - PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); - - CloseableHttpClient httpClient = HttpClientUtil.createClient(null, cm); - try (SolrClient client = buildClient(httpClient, url)) { - - HttpHost target = new HttpHost(url.getHost(), url.getPort(), isSSLMode() ? "https" : "http"); - HttpRoute route = new HttpRoute(target); - - ConnectionRequest mConn = getClientConnectionRequest(httpClient, route, cm); - - HttpClientConnection conn1 = getConn(mConn); - headerRequest(target, route, conn1, cm); - - cm.releaseConnection(conn1, null, -1, TimeUnit.MILLISECONDS); - - int queueBreaks = 0; - int cnt1 = atLeast(3); - int cnt2 = atLeast(30); - for (int j = 0; j < cnt1; j++) { - boolean done = false; - for (int i = 0; i < cnt2; i++) { - AddUpdateCommand c = new AddUpdateCommand(null); - c.solrDoc = sdoc("id", id.incrementAndGet()); - try { - client.add(c.solrDoc); - } catch (Exception e) { - log.error("error adding doc", e); - } - if (!done - && i > 0 - && i < cnt2 - 1 - && client instanceof ConcurrentUpdateSolrClient - && random().nextInt(10) > 8) { - queueBreaks++; - done = true; - Thread.sleep(350); // wait past streaming client poll time of 250ms - } - } - if (client instanceof ConcurrentUpdateSolrClient) { - ((ConcurrentUpdateSolrClient) client).blockUntilFinished(); - } - } - - route = - new HttpRoute(new HttpHost(url.getHost(), url.getPort(), isSSLMode() ? "https" : "http")); - - mConn = cm.requestConnection(route, HttpSolrClient.cacheKey); - - HttpClientConnection conn2 = getConn(mConn); - - HttpConnectionMetrics metrics = conn2.getMetrics(); - headerRequest(target, route, conn2, cm); - - cm.releaseConnection(conn2, null, -1, TimeUnit.MILLISECONDS); - - assertNotNull( - "No connection metrics found - is the connection getting aborted? server closing the connection? " - + client.getClass().getSimpleName(), - metrics); - - // we try and make sure the connection we get has handled all the requests in this test - if (client instanceof ConcurrentUpdateSolrClient) { - // we can't fully control queue polling breaking up requests - allow a bit of leeway - int exp = cnt1 + queueBreaks + 2; - assertTrue( - "We expected all communication via streaming client to use one connection! expected=" - + exp - + " got=" - + metrics.getRequestCount(), - Math.max(exp, metrics.getRequestCount()) - Math.min(exp, metrics.getRequestCount()) - < 3); - } else { - assertTrue( - "We expected all communication to use one connection! " - + client.getClass().getSimpleName() - + " " - + metrics.getRequestCount(), - cnt1 * cnt2 + 2 <= metrics.getRequestCount()); - } - - } finally { - HttpClientUtil.close(httpClient); - } - } - - public HttpClientConnection getConn(ConnectionRequest mConn) - throws InterruptedException, ConnectionPoolTimeoutException, ExecutionException { - - return mConn.get(30, TimeUnit.SECONDS); - } - - public void headerRequest( - HttpHost target, - HttpRoute route, - HttpClientConnection conn, - PoolingHttpClientConnectionManager cm) - throws IOException, HttpException { - HttpRequest req = new BasicHttpRequest("OPTIONS", "*", HttpVersion.HTTP_1_1); - - req.addHeader("Host", target.getHostName()); - if (!conn.isOpen()) { - // establish connection based on its route info - cm.connect(conn, route, 1000, context); - // and mark it as route complete - cm.routeComplete(conn, route, context); - } - conn.sendRequestHeader(req); - conn.flush(); - conn.receiveResponseHeader(); - } - - public ConnectionRequest getClientConnectionRequest( - HttpClient httpClient, HttpRoute route, PoolingHttpClientConnectionManager cm) { - return cm.requestConnection(route, HttpSolrClient.cacheKey); - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpClientUtilTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpClientUtilTest.java deleted file mode 100644 index ce9242d03678..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpClientUtilTest.java +++ /dev/null @@ -1,232 +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.apache; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.zip.GZIPOutputStream; -import java.util.zip.ZipException; -import javax.net.ssl.HostnameVerifier; -import org.apache.commons.lang3.reflect.FieldUtils; -import org.apache.http.HttpEntity; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.conn.ssl.DefaultHostnameVerifier; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.entity.InputStreamEntity; -import org.apache.http.entity.StringEntity; -import org.apache.lucene.tests.util.TestRuleRestoreSystemProperties; -import org.apache.solr.SolrTestCase; -import org.apache.solr.client.solrj.apache.HttpClientUtil.SocketFactoryRegistryProvider; -import org.apache.solr.common.util.SuppressForbidden; -import org.junit.After; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; - -public class HttpClientUtilTest extends SolrTestCase { - - @Rule - public TestRule syspropRestore = - new TestRuleRestoreSystemProperties(HttpClientUtil.SYS_PROP_CHECK_PEER_NAME); - - @After - public void resetHttpClientBuilder() { - HttpClientUtil.resetHttpClientBuilder(); - } - - @Test - public void testSSLSystemProperties() { - - assertNotNull( - "HTTPS scheme could not be created using system defaults", - HttpClientUtil.getSocketFactoryRegistryProvider() - .getSocketFactoryRegistry() - .lookup("https")); - - assertSSLHostnameVerifier( - DefaultHostnameVerifier.class, HttpClientUtil.getSocketFactoryRegistryProvider()); - - System.setProperty(HttpClientUtil.SYS_PROP_CHECK_PEER_NAME, "true"); - resetHttpClientBuilder(); - assertSSLHostnameVerifier( - DefaultHostnameVerifier.class, HttpClientUtil.getSocketFactoryRegistryProvider()); - - System.setProperty(HttpClientUtil.SYS_PROP_CHECK_PEER_NAME, ""); - resetHttpClientBuilder(); - assertSSLHostnameVerifier( - DefaultHostnameVerifier.class, HttpClientUtil.getSocketFactoryRegistryProvider()); - - System.setProperty(HttpClientUtil.SYS_PROP_CHECK_PEER_NAME, "false"); - resetHttpClientBuilder(); - assertSSLHostnameVerifier( - NoopHostnameVerifier.class, HttpClientUtil.getSocketFactoryRegistryProvider()); - } - - private void assertSSLHostnameVerifier( - Class expected, SocketFactoryRegistryProvider provider) { - ConnectionSocketFactory socketFactory = provider.getSocketFactoryRegistry().lookup("https"); - assertNotNull("unable to lookup https", socketFactory); - assertTrue( - "socketFactory is not an SSLConnectionSocketFactory: " + socketFactory.getClass(), - socketFactory instanceof SSLConnectionSocketFactory); - SSLConnectionSocketFactory sslSocketFactory = (SSLConnectionSocketFactory) socketFactory; - Object hostnameVerifier = getHostnameVerifier(sslSocketFactory); - assertNotNull("sslSocketFactory has null hostnameVerifier", hostnameVerifier); - assertEquals( - "sslSocketFactory does not have expected hostnameVerifier impl", - expected, - hostnameVerifier.getClass()); - } - - @SuppressForbidden(reason = "Uses commons-lang3 FieldUtils.readField to get hostnameVerifier") - private Object getHostnameVerifier(SSLConnectionSocketFactory sslSocketFactory) { - try { - return FieldUtils.readField(sslSocketFactory, "hostnameVerifier", true); - } catch (IllegalAccessException e) { - throw new AssertionError("Unexpected access error reading hostnameVerifier field", e); - } - } - - @Test - public void testToBooleanDefaultIfNull() throws Exception { - assertFalse(HttpClientUtil.toBooleanDefaultIfNull(Boolean.FALSE, true)); - assertTrue(HttpClientUtil.toBooleanDefaultIfNull(Boolean.TRUE, false)); - assertFalse(HttpClientUtil.toBooleanDefaultIfNull(null, false)); - assertTrue(HttpClientUtil.toBooleanDefaultIfNull(null, true)); - } - - @Test - public void testToBooleanObject() { - assertEquals(Boolean.TRUE, HttpClientUtil.toBooleanObject("true")); - assertEquals(Boolean.TRUE, HttpClientUtil.toBooleanObject("TRUE")); - assertEquals(Boolean.TRUE, HttpClientUtil.toBooleanObject("tRuE")); - - assertEquals(Boolean.FALSE, HttpClientUtil.toBooleanObject("false")); - assertEquals(Boolean.FALSE, HttpClientUtil.toBooleanObject("FALSE")); - assertEquals(Boolean.FALSE, HttpClientUtil.toBooleanObject("fALSE")); - - assertNull(HttpClientUtil.toBooleanObject("t")); - assertNull(HttpClientUtil.toBooleanObject("f")); - assertNull(HttpClientUtil.toBooleanObject("foo")); - assertNull(HttpClientUtil.toBooleanObject(null)); - } - - @Test - public void testNonRepeatableMalformedGzipEntityAutoClosed() throws IOException { - HttpEntity baseEntity = - new InputStreamEntity( - new ByteArrayInputStream("this is not compressed".getBytes(StandardCharsets.UTF_8))); - HttpClientUtil.GzipDecompressingEntity gzipDecompressingEntity = - new HttpClientUtil.GzipDecompressingEntity(baseEntity); - Throwable error = - expectThrows( - IOException.class, - "An IOException wrapping a ZIPException should be thrown when loading a malformed GZIP Entity Content", - gzipDecompressingEntity::getContent); - assertEquals( - "IOException should be caused by a ZipException", - ZipException.class, - error.getCause() == null ? null : error.getCause().getClass()); - assertNull( - "The second time getContent is called, null should be returned since the underlying entity is non-repeatable", - gzipDecompressingEntity.getContent()); - assertEquals( - "No more content should be available after the GZIP Entity failed to load", - 0, - baseEntity.getContent().available()); - } - - @Test - public void testRepeatableMalformedGzipEntity() throws IOException { - HttpEntity baseEntity = new StringEntity("this is not compressed"); - HttpClientUtil.GzipDecompressingEntity gzipDecompressingEntity = - new HttpClientUtil.GzipDecompressingEntity(baseEntity); - Throwable error = - expectThrows( - IOException.class, - "An IOException wrapping a ZIPException should be thrown when loading a malformed GZIP Entity Content", - gzipDecompressingEntity::getContent); - assertEquals( - "IOException should be caused by a ZipException", - ZipException.class, - error.getCause() == null ? null : error.getCause().getClass()); - error = - expectThrows( - IOException.class, - "An IOException should be thrown again when re-loading a repeatable malformed GZIP Entity Content", - gzipDecompressingEntity::getContent); - assertEquals( - "IOException should be caused by a ZipException", - ZipException.class, - error.getCause() == null ? null : error.getCause().getClass()); - } - - @Test - public void testRepeatableGzipEntity() throws IOException { - String testString = "this is compressed"; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(baos)) { - gzipOutputStream.write(testString.getBytes(StandardCharsets.UTF_8)); - } - // Use an ByteArrayEntity because it is repeatable - HttpEntity baseEntity = new ByteArrayEntity(baos.toByteArray()); - HttpClientUtil.GzipDecompressingEntity gzipDecompressingEntity = - new HttpClientUtil.GzipDecompressingEntity(baseEntity); - try (InputStream stream = gzipDecompressingEntity.getContent()) { - assertEquals( - "Entity incorrect after decompression", - testString, - new String(stream.readAllBytes(), StandardCharsets.UTF_8)); - } - try (InputStream stream = gzipDecompressingEntity.getContent()) { - assertEquals( - "Entity incorrect after decompression after repeating", - testString, - new String(stream.readAllBytes(), StandardCharsets.UTF_8)); - } - } - - @Test - public void testNonRepeatableGzipEntity() throws IOException { - String testString = "this is compressed"; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(baos)) { - gzipOutputStream.write(testString.getBytes(StandardCharsets.UTF_8)); - } - // Use an InputStreamEntity because it is non-repeatable - HttpEntity baseEntity = new InputStreamEntity(new ByteArrayInputStream(baos.toByteArray())); - HttpClientUtil.GzipDecompressingEntity gzipDecompressingEntity = - new HttpClientUtil.GzipDecompressingEntity(baseEntity); - try (InputStream stream = gzipDecompressingEntity.getContent()) { - assertEquals( - "Entity incorrect after decompression", - testString, - new String(stream.readAllBytes(), StandardCharsets.UTF_8)); - } - try (InputStream stream = gzipDecompressingEntity.getContent()) { - expectThrows( - IOException.class, - "Entity Content should already be closed since the input is non-repeatable", - stream::available); - } - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpSolrClientBuilderTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpSolrClientBuilderTest.java deleted file mode 100644 index a363141f6691..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpSolrClientBuilderTest.java +++ /dev/null @@ -1,97 +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.apache; - -import java.io.IOException; -import org.apache.http.client.HttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.solr.SolrTestCase; -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.apache.HttpSolrClient.Builder; -import org.apache.solr.client.solrj.response.InputStreamResponseParser; -import org.apache.solr.client.solrj.response.JavaBinResponseParser; -import org.apache.solr.client.solrj.response.ResponseParser; -import org.apache.solr.common.params.ModifiableSolrParams; -import org.junit.Test; - -/** Unit tests for {@link Builder}. */ -public class HttpSolrClientBuilderTest extends SolrTestCase { - private static final String ANY_BASE_SOLR_URL = "ANY_BASE_SOLR_URL"; - private static final HttpClient ANY_HTTP_CLIENT = HttpClientBuilder.create().build(); - private static final ResponseParser ANY_RESPONSE_PARSER = new InputStreamResponseParser("xml"); - - @Test(expected = IllegalArgumentException.class) - public void testBaseSolrUrlIsRequired() { - new Builder(null).build(); - } - - @Test - public void testProvidesBaseSolrUrlToClient() throws IOException { - try (HttpSolrClient createdClient = new HttpSolrClient.Builder(ANY_BASE_SOLR_URL).build()) { - assertEquals(ANY_BASE_SOLR_URL, createdClient.getBaseURL()); - } - } - - @Test - public void testProvidesHttpClientToClient() throws IOException { - try (HttpSolrClient createdClient = - new Builder(ANY_BASE_SOLR_URL).withHttpClient(ANY_HTTP_CLIENT).build()) { - assertEquals(createdClient.getHttpClient(), ANY_HTTP_CLIENT); - } - } - - @Test - public void testUsesTimeoutProvidedByHttpClient() throws IOException { - - ModifiableSolrParams clientParams = new ModifiableSolrParams(); - clientParams.set(HttpClientUtil.PROP_SO_TIMEOUT, 12345); - clientParams.set(HttpClientUtil.PROP_CONNECTION_TIMEOUT, 67890); - HttpClient httpClient = HttpClientUtil.createClient(clientParams); - try (HttpSolrClient createdClient = - new Builder(ANY_BASE_SOLR_URL).withHttpClient(httpClient).build()) { - assertEquals(createdClient.getHttpClient(), httpClient); - assertEquals(67890, createdClient.getConnectionTimeout()); - assertEquals(12345, createdClient.getSocketTimeout()); - } - HttpClientUtil.close(httpClient); - } - - @Test - public void testProvidesResponseParserToClient() throws IOException { - try (HttpSolrClient createdClient = - new Builder(ANY_BASE_SOLR_URL).withResponseParser(ANY_RESPONSE_PARSER).build()) { - assertEquals(createdClient.getParser(), ANY_RESPONSE_PARSER); - } - } - - @Test - public void testDefaultsToBinaryResponseParserWhenNoneProvided() throws IOException { - try (HttpSolrClient createdClient = new Builder(ANY_BASE_SOLR_URL).build()) { - final ResponseParser usedParser = createdClient.getParser(); - assertTrue(usedParser instanceof JavaBinResponseParser); - } - } - - @Test - public void testDefaultCollectionPassedFromBuilderToClient() throws IOException { - try (final SolrClient createdClient = - new Builder(ANY_BASE_SOLR_URL).withDefaultCollection("aCollection").build()) { - assertEquals("aCollection", createdClient.getDefaultCollection()); - } - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpSolrClientConPoolTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpSolrClientConPoolTest.java deleted file mode 100644 index 1bd221afad72..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpSolrClientConPoolTest.java +++ /dev/null @@ -1,201 +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.apache; - -import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ExecutorService; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.pool.PoolStats; -import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.impl.LBSolrClient; -import org.apache.solr.client.solrj.request.SolrQuery; -import org.apache.solr.client.solrj.request.UpdateRequest; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.common.params.ModifiableSolrParams; -import org.apache.solr.common.util.EnvUtils; -import org.apache.solr.common.util.ExecutorUtil; -import org.apache.solr.common.util.SolrNamedThreadFactory; -import org.apache.solr.util.ExternalPaths; -import org.apache.solr.util.SolrJettyTestRule; -import org.junit.BeforeClass; -import org.junit.ClassRule; - -public class HttpSolrClientConPoolTest extends SolrTestCaseJ4 { - - @ClassRule public static SolrJettyTestRule solrTestRule = new SolrJettyTestRule(); - @ClassRule public static SolrJettyTestRule secondJetty = new SolrJettyTestRule(); - private static String fooUrl; // first Jetty URL - private static String barUrl; // second Jetty URL - - @BeforeClass - public static void beforeTest() throws SolrServerException, IOException { - EnvUtils.setProperty( - ALLOW_PATHS_SYSPROP, ExternalPaths.SERVER_HOME.toAbsolutePath().toString()); - solrTestRule.startSolr(); - solrTestRule.newCollection().withConfigSet(ExternalPaths.TECHPRODUCTS_CONFIGSET).create(); - - fooUrl = solrTestRule.getBaseUrl(); - - secondJetty.startSolr(); - secondJetty.newCollection().withConfigSet(ExternalPaths.TECHPRODUCTS_CONFIGSET).create(); - - barUrl = secondJetty.getBaseUrl(); - } - - public void testPoolSize() throws SolrServerException, IOException { - PoolingHttpClientConnectionManager pool = HttpClientUtil.createPoolingConnectionManager(); - - CloseableHttpClient httpClient = - HttpClientUtil.createClient( - new ModifiableSolrParams(), pool, false /* let client shutdown it*/); - final HttpSolrClient clientFoo = - new HttpSolrClient.Builder(fooUrl) - .withDefaultCollection(DEFAULT_TEST_COLLECTION_NAME) - .withHttpClient(httpClient) - .build(); - final HttpSolrClient clientBar = - new HttpSolrClient.Builder(barUrl) - .withDefaultCollection(DEFAULT_TEST_COLLECTION_NAME) - .withHttpClient(httpClient) - .build(); - - clientFoo.deleteByQuery("*:*"); - clientBar.deleteByQuery("*:*"); - - List urls = new ArrayList<>(); - for (int i = 0; i < 17; i++) { - urls.add(fooUrl); - } - for (int i = 0; i < 31; i++) { - urls.add(barUrl); - } - - Collections.shuffle(urls, random()); - - try { - int i = 0; - for (String url : urls) { - if (clientFoo.getBaseURL().equals(url)) { - clientFoo.add(new SolrInputDocument("id", "" + (i++))); - } else { - clientBar.add(new SolrInputDocument("id", "" + (i++))); - } - } - - clientFoo.commit(); - clientBar.commit(); - - assertEquals(17, clientFoo.query(new SolrQuery("*:*")).getResults().getNumFound()); - assertEquals(31, clientBar.query(new SolrQuery("*:*")).getResults().getNumFound()); - - PoolStats stats = pool.getTotalStats(); - assertEquals("oh " + stats, 2, stats.getAvailable()); - } finally { - for (HttpSolrClient c : new HttpSolrClient[] {clientFoo, clientBar}) { - HttpClientUtil.close(c.getHttpClient()); - c.close(); - } - } - } - - public void testLBClient() throws IOException, SolrServerException { - - PoolingHttpClientConnectionManager pool = HttpClientUtil.createPoolingConnectionManager(); - int threadCount = atLeast(2); - final ExecutorService threads = - ExecutorUtil.newMDCAwareFixedThreadPool( - threadCount, new SolrNamedThreadFactory(getClass().getSimpleName() + "TestScheduler")); - CloseableHttpClient httpClient = HttpClientUtil.createClient(new ModifiableSolrParams(), pool); - try (var roundRobin = - new LBHttpSolrClient.Builder() - .withBaseEndpoint(fooUrl) - .withBaseEndpoint(barUrl) - .withDefaultCollection(DEFAULT_TEST_COLLECTION_NAME) - .withHttpClient(httpClient) - .build(); - final var fooClient = - new ConcurrentUpdateSolrClient.Builder(fooUrl) - .withDefaultCollection(DEFAULT_TEST_COLLECTION_NAME) - .withHttpClient(httpClient) - .withThreadCount(threadCount) - .withQueueSize(10) - .withExecutorService(threads) - .build(); - final var barClient = - new ConcurrentUpdateSolrClient.Builder(barUrl) - .withDefaultCollection(DEFAULT_TEST_COLLECTION_NAME) - .withHttpClient(httpClient) - .withThreadCount(threadCount) - .withQueueSize(10) - .withExecutorService(threads) - .build()) { - List concurrentClients = Arrays.asList(fooClient, barClient); - - for (int i = 0; i < 2; i++) { - roundRobin.deleteByQuery("*:*"); - } - - for (int i = 0; i < 57; i++) { - final SolrInputDocument doc = new SolrInputDocument("id", "" + i); - if (random().nextBoolean()) { - final ConcurrentUpdateSolrClient concurrentClient = - concurrentClients.get(random().nextInt(concurrentClients.size())); - concurrentClient.add(doc); // here we are testing that CUSC and plain clients reuse pool - concurrentClient.blockUntilFinished(); - } else { - if (random().nextBoolean()) { - roundRobin.add(doc); - } else { - final UpdateRequest updateRequest = new UpdateRequest(); - updateRequest.add(doc); // here we mimic CloudSolrClient impl - final List urls = - Arrays.asList(new LBSolrClient.Endpoint(fooUrl), new LBSolrClient.Endpoint(barUrl)); - Collections.shuffle(urls, random()); - LBSolrClient.Req req = new LBSolrClient.Req(updateRequest, urls); - roundRobin.request(req); - } - } - } - - for (int i = 0; i < 2; i++) { - roundRobin.commit(); - } - long total = 0; - for (int i = 0; i < 2; i++) { - total += roundRobin.query(new SolrQuery("*:*")).getResults().getNumFound(); - } - assertEquals(57, total); - PoolStats stats = pool.getTotalStats(); - // System.out.println("\n"+stats); - assertEquals( - "expected number of connections shouldn't exceed number of endpoints" + stats, - 2, - stats.getAvailable()); - } finally { - threads.shutdown(); - HttpClientUtil.close(httpClient); - } - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpSolrClientSSLAuthConPoolTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpSolrClientSSLAuthConPoolTest.java deleted file mode 100644 index 4238a7ed2cfc..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/HttpSolrClientSSLAuthConPoolTest.java +++ /dev/null @@ -1,36 +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.apache; - -import java.net.URL; -import java.util.Arrays; -import org.apache.solr.util.RandomizeSSL; -import org.junit.BeforeClass; - -@RandomizeSSL(1.0) -public class HttpSolrClientSSLAuthConPoolTest extends HttpSolrClientConPoolTest { - - @BeforeClass - public static void checkUrls() { - URL[] urls = - new URL[] {solrTestRule.getJetty().getBaseUrl(), secondJetty.getJetty().getBaseUrl()}; - for (URL u : urls) { - assertEquals("expect https urls ", "https", u.getProtocol()); - } - assertNotEquals("expect different urls " + Arrays.toString(urls), urls[0], urls[1]); - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/LBHttpSolrClientBuilderTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/LBHttpSolrClientBuilderTest.java deleted file mode 100644 index 777d39213078..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/LBHttpSolrClientBuilderTest.java +++ /dev/null @@ -1,93 +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.apache; - -import java.io.IOException; -import org.apache.http.client.HttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.solr.SolrTestCase; -import org.apache.solr.client.solrj.apache.LBHttpSolrClient.Builder; -import org.apache.solr.client.solrj.response.InputStreamResponseParser; -import org.apache.solr.client.solrj.response.JavaBinResponseParser; -import org.apache.solr.client.solrj.response.ResponseParser; -import org.apache.solr.common.params.ModifiableSolrParams; -import org.junit.Test; - -/** Unit tests for {@link Builder}. */ -public class LBHttpSolrClientBuilderTest extends SolrTestCase { - private static final String ANY_BASE_SOLR_URL = "ANY_BASE_SOLR_URL"; - private static final HttpClient ANY_HTTP_CLIENT = HttpClientBuilder.create().build(); - private static final ResponseParser ANY_RESPONSE_PARSER = new InputStreamResponseParser("xml"); - - @Test - public void providesHttpClientToClient() { - try (LBHttpSolrClient createdClient = - new Builder().withBaseEndpoint(ANY_BASE_SOLR_URL).withHttpClient(ANY_HTTP_CLIENT).build()) { - assertEquals(createdClient.getHttpClient(), ANY_HTTP_CLIENT); - } - } - - @Test - public void providesResponseParserToClient() { - try (LBHttpSolrClient createdClient = - new Builder() - .withBaseEndpoint(ANY_BASE_SOLR_URL) - .withResponseParser(ANY_RESPONSE_PARSER) - .build()) { - assertEquals(createdClient.getParser(), ANY_RESPONSE_PARSER); - } - } - - @Test - public void testDefaultsToBinaryResponseParserWhenNoneProvided() { - try (LBHttpSolrClient createdClient = - new Builder().withBaseEndpoint(ANY_BASE_SOLR_URL).build()) { - final ResponseParser usedParser = createdClient.getParser(); - - assertTrue(usedParser instanceof JavaBinResponseParser); - } - } - - @Test - public void testUsesTimeoutProvidedByHttpClient() throws IOException { - - ModifiableSolrParams clientParams = new ModifiableSolrParams(); - clientParams.set(HttpClientUtil.PROP_SO_TIMEOUT, 12345); - clientParams.set(HttpClientUtil.PROP_CONNECTION_TIMEOUT, 67890); - HttpClient httpClient = HttpClientUtil.createClient(clientParams); - - try (LBHttpSolrClient createdClient = - new Builder().withBaseEndpoint(ANY_BASE_SOLR_URL).withHttpClient(httpClient).build()) { - assertEquals(createdClient.getHttpClient(), httpClient); - assertEquals(67890, createdClient.connectionTimeoutMillis); - assertEquals(12345, createdClient.soTimeoutMillis); - } - HttpClientUtil.close(httpClient); - } - - @Test - public void testDefaultCollectionPassedFromBuilderToClient() throws IOException { - try (LBHttpSolrClient createdClient = - new LBHttpSolrClient.Builder() - .withBaseEndpoint(ANY_BASE_SOLR_URL) - .withDefaultCollection("aCollection") - .build()) { - assertEquals("aCollection", createdClient.getDefaultCollection()); - } - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/LBHttpSolrClientTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/LBHttpSolrClientTest.java deleted file mode 100644 index c5797ed877eb..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/LBHttpSolrClientTest.java +++ /dev/null @@ -1,69 +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.apache; - -import java.io.IOException; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.solr.SolrTestCase; -import org.apache.solr.client.solrj.impl.LBSolrClient; -import org.apache.solr.client.solrj.response.JavaBinResponseParser; -import org.apache.solr.client.solrj.response.ResponseParser; -import org.apache.solr.common.params.ModifiableSolrParams; -import org.junit.Test; - -/** Test the LBHttpSolrClient. */ -public class LBHttpSolrClientTest extends SolrTestCase { - - /** - * Test method for {@link LBHttpSolrClient.Builder}. - * - *

Validate that the parser passed in is used in the HttpSolrClient instances - * created. - */ - @Test - public void testLBHttpSolrClientHttpClientResponseParserStringArray() throws IOException { - CloseableHttpClient httpClient = HttpClientUtil.createClient(new ModifiableSolrParams()); - try (LBHttpSolrClient testClient = - new LBHttpSolrClient.Builder() - .withHttpClient(httpClient) - .withResponseParser(null) - .build(); - HttpSolrClient httpSolrClient = - testClient.makeSolrClient(new LBSolrClient.Endpoint("http://127.0.0.1:8080"))) { - assertNull("Generated server should have null parser.", httpSolrClient.getParser()); - } finally { - HttpClientUtil.close(httpClient); - } - - ResponseParser parser = new JavaBinResponseParser(); - httpClient = HttpClientUtil.createClient(new ModifiableSolrParams()); - try { - try (LBHttpSolrClient testClient = - new LBHttpSolrClient.Builder() - .withHttpClient(httpClient) - .withResponseParser(parser) - .build(); - HttpSolrClient httpSolrClient = - testClient.makeSolrClient(new LBSolrClient.Endpoint("http://127.0.0.1:8080"))) { - assertEquals( - "Invalid parser passed to generated server.", parser, httpSolrClient.getParser()); - } - } finally { - HttpClientUtil.close(httpClient); - } - } -} diff --git a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/SolrPortAwareCookieSpecTest.java b/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/SolrPortAwareCookieSpecTest.java deleted file mode 100644 index b88ce8faee01..000000000000 --- a/solr/test-framework/src/test/org/apache/solr/client/solrj/apache/SolrPortAwareCookieSpecTest.java +++ /dev/null @@ -1,153 +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.apache; - -import org.apache.http.cookie.CookieAttributeHandler; -import org.apache.http.cookie.CookieOrigin; -import org.apache.http.cookie.MalformedCookieException; -import org.apache.http.impl.cookie.BasicClientCookie; -import org.apache.solr.SolrTestCaseJ4; -import org.junit.Test; - -// Test cases imported from TestNetscapeCookieAttribHandlers of HttpClient project -public class SolrPortAwareCookieSpecTest extends SolrTestCaseJ4 { - - @Test - public void testDomainHostPortValidate() throws Exception { - final BasicClientCookie cookie = new BasicClientCookie("name", "value"); - final CookieOrigin origin = new CookieOrigin("somehost", 80, "/", false); - final CookieAttributeHandler h = new SolrPortAwareCookieSpecFactory.PortAwareDomainHandler(); - - cookie.setDomain("somehost:80"); - h.validate(cookie, origin); - - cookie.setDomain("somehost:1234"); - SolrTestCaseJ4.expectThrows(MalformedCookieException.class, () -> h.validate(cookie, origin)); - } - - @Test - public void testDomainHostPortMatch() { - final BasicClientCookie cookie = new BasicClientCookie("name", "value"); - final CookieOrigin origin = new CookieOrigin("myhost", 80, "/", false); - final CookieAttributeHandler h = new SolrPortAwareCookieSpecFactory.PortAwareDomainHandler(); - - cookie.setDomain("myhost"); - SolrTestCaseJ4.expectThrows(IllegalArgumentException.class, () -> h.match(cookie, null)); - - cookie.setDomain(null); - assertFalse(h.match(cookie, origin)); - - cookie.setDomain("otherhost"); - assertFalse(h.match(cookie, origin)); - - cookie.setDomain("myhost"); - assertTrue(h.match(cookie, origin)); - - cookie.setDomain("myhost:80"); - assertTrue(h.match(cookie, origin)); - - cookie.setDomain("myhost:8080"); - assertFalse(h.match(cookie, origin)); - } - - @Test - public void testDomainValidate1() throws Exception { - final BasicClientCookie cookie = new BasicClientCookie("name", "value"); - final CookieOrigin origin = new CookieOrigin("somehost", 80, "/", false); - final CookieAttributeHandler h = new SolrPortAwareCookieSpecFactory.PortAwareDomainHandler(); - - cookie.setDomain("somehost"); - h.validate(cookie, origin); - - cookie.setDomain("otherhost"); - SolrTestCaseJ4.expectThrows(MalformedCookieException.class, () -> h.validate(cookie, origin)); - } - - @Test - public void testDomainValidate2() throws Exception { - final BasicClientCookie cookie = new BasicClientCookie("name", "value"); - final CookieOrigin origin = new CookieOrigin("www.somedomain.com", 80, "/", false); - final CookieAttributeHandler h = new SolrPortAwareCookieSpecFactory.PortAwareDomainHandler(); - - cookie.setDomain(".somedomain.com"); - h.validate(cookie, origin); - - cookie.setDomain(".otherdomain.com"); - SolrTestCaseJ4.expectThrows(MalformedCookieException.class, () -> h.validate(cookie, origin)); - - cookie.setDomain("www.otherdomain.com"); - SolrTestCaseJ4.expectThrows(MalformedCookieException.class, () -> h.validate(cookie, origin)); - } - - @Test - public void testDomainValidate3() throws Exception { - final BasicClientCookie cookie = new BasicClientCookie("name", "value"); - final CookieOrigin origin = new CookieOrigin("www.a.com", 80, "/", false); - final CookieAttributeHandler h = new SolrPortAwareCookieSpecFactory.PortAwareDomainHandler(); - - cookie.setDomain(".a.com"); - h.validate(cookie, origin); - - cookie.setDomain(".com"); - SolrTestCaseJ4.expectThrows(MalformedCookieException.class, () -> h.validate(cookie, origin)); - } - - @Test - public void testDomainValidate4() throws Exception { - final BasicClientCookie cookie = new BasicClientCookie("name", "value"); - final CookieOrigin origin = new CookieOrigin("www.a.b.c", 80, "/", false); - final CookieAttributeHandler h = new SolrPortAwareCookieSpecFactory.PortAwareDomainHandler(); - - cookie.setDomain(".a.b.c"); - h.validate(cookie, origin); - - cookie.setDomain(".b.c"); - SolrTestCaseJ4.expectThrows(MalformedCookieException.class, () -> h.validate(cookie, origin)); - } - - @Test - public void testDomainMatch1() { - final BasicClientCookie cookie = new BasicClientCookie("name", "value"); - final CookieOrigin origin = new CookieOrigin("www.somedomain.com", 80, "/", false); - final CookieAttributeHandler h = new SolrPortAwareCookieSpecFactory.PortAwareDomainHandler(); - - cookie.setDomain(null); - assertFalse(h.match(cookie, origin)); - - cookie.setDomain(".somedomain.com"); - assertTrue(h.match(cookie, origin)); - } - - @Test - public void testDomainMatch2() { - final BasicClientCookie cookie = new BasicClientCookie("name", "value"); - final CookieOrigin origin = new CookieOrigin("www.whatever.somedomain.com", 80, "/", false); - final CookieAttributeHandler h = new SolrPortAwareCookieSpecFactory.PortAwareDomainHandler(); - - cookie.setDomain(".somedomain.com"); - assertTrue(h.match(cookie, origin)); - } - - @Test - public void testDomainInvalidInput() { - final CookieAttributeHandler h = new SolrPortAwareCookieSpecFactory.PortAwareDomainHandler(); - SolrTestCaseJ4.expectThrows(IllegalArgumentException.class, () -> h.match(null, null)); - SolrTestCaseJ4.expectThrows( - IllegalArgumentException.class, - () -> h.match(new BasicClientCookie("name", "value"), null)); - } -} From b1509e122c4d88b6c29f6b7bd3d47e67c1fc2e30 Mon Sep 17 00:00:00 2001 From: David Smiley Date: Fri, 3 Apr 2026 01:42:41 -0400 Subject: [PATCH 2/3] Remove TestLBHttpSolrClient.java Only for org.apache.solr.client.solrj.apache.LBHttpSolrClient --- .../client/solrj/TestLBHttpSolrClient.java | 323 ------------------ 1 file changed, 323 deletions(-) delete mode 100644 solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrClient.java diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrClient.java b/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrClient.java deleted file mode 100644 index 1f4d0ce1e846..000000000000 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrClient.java +++ /dev/null @@ -1,323 +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.io.IOException; -import java.lang.invoke.MethodHandles; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.lucene.util.IOUtils; -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.apache.LBHttpSolrClient; -import org.apache.solr.client.solrj.request.SolrQuery; -import org.apache.solr.client.solrj.response.QueryResponse; -import org.apache.solr.client.solrj.response.SolrResponseBase; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.common.util.TimeSource; -import org.apache.solr.embedded.JettyConfig; -import org.apache.solr.embedded.JettySolrRunner; -import org.apache.solr.util.TimeOut; -import org.junit.BeforeClass; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test for LBHttpSolrClient - * - * @since solr 1.4 - */ -public class TestLBHttpSolrClient extends SolrTestCaseJ4 { - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - SolrInstance[] solr = new SolrInstance[3]; - CloseableHttpClient httpClient; - - // TODO: fix this test to not require FSDirectory - @BeforeClass - public static void beforeClass() { - System.setProperty("solr.directoryFactory", "org.apache.solr.core.MockFSDirectoryFactory"); - System.setProperty("tests.shardhandler.randomSeed", Long.toString(random().nextLong())); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - httpClient = HttpClientUtil.createClient(null); - - for (int i = 0; i < solr.length; i++) { - solr[i] = new SolrInstance("solr/collection1" + i, createTempDir("instance-" + i), 0); - solr[i].setUp(); - solr[i].startJetty(); - addDocs(solr[i]); - } - } - - private void addDocs(SolrInstance solrInstance) throws IOException, SolrServerException { - List docs = new ArrayList<>(); - for (int i = 0; i < 10; i++) { - SolrInputDocument doc = new SolrInputDocument(); - doc.addField("id", i); - doc.addField("name", solrInstance.name); - docs.add(doc); - } - SolrResponseBase resp; - try (SolrClient client = - new HttpSolrClient.Builder(solrInstance.getBaseUrl()) - .withDefaultCollection(solrInstance.getDefaultCollection()) - .withHttpClient(httpClient) - .build()) { - resp = client.add(docs); - assertEquals(0, resp.getStatus()); - resp = client.commit(); - assertEquals(0, resp.getStatus()); - } - } - - @Override - public void tearDown() throws Exception { - for (SolrInstance aSolr : solr) { - if (aSolr != null) { - aSolr.tearDown(); - } - } - HttpClientUtil.close(httpClient); - super.tearDown(); - } - - public void testSimple() throws Exception { - String[] solrUrls = new String[solr.length]; - for (int i = 0; i < solr.length; i++) { - solrUrls[i] = solr[i].getBaseUrl(); - } - try (LBHttpSolrClient client = - new LBHttpSolrClient.Builder() - .withHttpClient(httpClient) - .withBaseEndpoints(solrUrls) - .withDefaultCollection(solr[0].getDefaultCollection()) - .setAliveCheckInterval(500) - .build()) { - SolrQuery solrQuery = new SolrQuery("*:*"); - Set names = new HashSet<>(); - QueryResponse resp = null; - for (int i = 0; i < solr.length; i++) { - resp = client.query(solrQuery); - assertEquals(10, resp.getResults().getNumFound()); - names.add(resp.getResults().get(0).getFieldValue("name").toString()); - } - assertEquals(3, names.size()); - - // Kill a server and test again - solr[1].jetty.stop(); - solr[1].jetty = null; - names.clear(); - for (int i = 0; i < solr.length; i++) { - resp = client.query(solrQuery); - assertEquals(10, resp.getResults().getNumFound()); - names.add(resp.getResults().get(0).getFieldValue("name").toString()); - } - assertEquals(2, names.size()); - assertFalse(names.contains("solr1")); - - // Start the killed server once again - solr[1].startJetty(); - // Wait for the alive check to complete - Thread.sleep(1200); - names.clear(); - for (int i = 0; i < solr.length; i++) { - resp = client.query(solrQuery); - assertEquals(10, resp.getResults().getNumFound()); - names.add(resp.getResults().get(0).getFieldValue("name").toString()); - } - assertEquals(3, names.size()); - } - } - - public void testTwoServers() throws Exception { - String[] solrUrls = new String[2]; - for (int i = 0; i < 2; i++) { - solrUrls[i] = solr[i].getBaseUrl(); - } - try (LBHttpSolrClient client = - new LBHttpSolrClient.Builder() - .withHttpClient(httpClient) - .withBaseEndpoints(solrUrls) - .withDefaultCollection(solr[0].getDefaultCollection()) - .setAliveCheckInterval(500) - .build()) { - SolrQuery solrQuery = new SolrQuery("*:*"); - QueryResponse resp = null; - solr[0].jetty.stop(); - solr[0].jetty = null; - resp = client.query(solrQuery); - String name = resp.getResults().get(0).getFieldValue("name").toString(); - assertEquals("solr/collection11", name); - resp = client.query(solrQuery); - name = resp.getResults().get(0).getFieldValue("name").toString(); - assertEquals("solr/collection11", name); - solr[1].jetty.stop(); - solr[1].jetty = null; - solr[0].startJetty(); - Thread.sleep(1200); - try { - resp = client.query(solrQuery); - } catch (SolrServerException e) { - // try again after a pause in case the error is lack of time to start server - Thread.sleep(3000); - resp = client.query(solrQuery); - } - name = resp.getResults().get(0).getFieldValue("name").toString(); - assertEquals("solr/collection10", name); - } - } - - public void testReliability() throws Exception { - String[] solrUrls = new String[solr.length]; - for (int i = 0; i < solr.length; i++) { - solrUrls[i] = solr[i].getBaseUrl(); - } - - try (LBHttpSolrClient client = - new LBHttpSolrClient.Builder() - .withHttpClient(httpClient) - .withBaseEndpoints(solrUrls) - .withDefaultCollection(solr[0].getDefaultCollection()) - .withConnectionTimeout(500, TimeUnit.MILLISECONDS) - .withSocketTimeout(500, TimeUnit.MILLISECONDS) - .setAliveCheckInterval(500) - .build()) { - - // Kill a server and test again - solr[1].jetty.stop(); - solr[1].jetty = null; - - // query the servers - for (String value : solrUrls) client.query(new SolrQuery("*:*")); - - // Start the killed server once again - solr[1].startJetty(); - // Wait for the alive check to complete - waitForServer(30, client, 3, solr[1].name); - } - } - - // wait maximum ms for serverName to come back up - private void waitForServer( - int maxSeconds, LBHttpSolrClient client, int nServers, String serverName) throws Exception { - final TimeOut timeout = new TimeOut(maxSeconds, TimeUnit.SECONDS, TimeSource.NANO_TIME); - while (!timeout.hasTimedOut()) { - QueryResponse resp; - try { - resp = client.query(new SolrQuery("*:*")); - } catch (Exception e) { - log.warn("", e); - continue; - } - String name = resp.getResults().get(0).getFieldValue("name").toString(); - if (name.equals(serverName)) return; - - Thread.sleep(500); - } - } - - private static class SolrInstance { - String name; - Path homeDir; - Path dataDir; - Path confDir; - int port; - JettySolrRunner jetty; - - public SolrInstance(String name, Path homeDir, int port) { - this.name = name; - this.homeDir = homeDir; - this.port = port; - - dataDir = homeDir.resolve("collection1").resolve("data"); - confDir = homeDir.resolve("collection1").resolve("conf"); - } - - public String getHomeDir() { - return homeDir.toString(); - } - - public String getBaseUrl() { - return buildUrl(port); - } - - public String getDefaultCollection() { - return "collection1"; - } - - public String getSchemaFile() { - return "solrj/solr/collection1/conf/schema-replication1.xml"; - } - - public String getDataDir() { - return dataDir.toString(); - } - - public String getSolrConfigFile() { - return "solrj/solr/collection1/conf/solrconfig-follower1.xml"; - } - - public void setUp() throws Exception { - Files.createDirectories(homeDir); - Files.createDirectories(dataDir); - Files.createDirectories(confDir); - - Path f = confDir.resolve("solrconfig.xml"); - Files.copy(SolrTestCaseJ4.getFile(getSolrConfigFile()), f); - f = confDir.resolve("schema.xml"); - Files.copy(SolrTestCaseJ4.getFile(getSchemaFile()), f); - Files.createFile(homeDir.resolve("collection1/core.properties")); - } - - public void tearDown() throws Exception { - if (jetty != null) jetty.stop(); - IOUtils.rm(homeDir); - } - - public void startJetty() throws Exception { - - Properties props = new Properties(); - props.setProperty("solrconfig", "bad_solrconfig.xml"); - props.setProperty("solr.data.dir", getDataDir()); - - JettyConfig jettyConfig = JettyConfig.builder().setPort(port).build(); - - jetty = new JettySolrRunner(getHomeDir(), props, jettyConfig); - jetty.start(); - int newPort = jetty.getLocalPort(); - if (port != 0 && newPort != port) { - fail("TESTING FAILURE: could not grab requested port."); - } - this.port = newPort; - // System.out.println("waiting........."); - // Thread.sleep(5000); - } - } -} From 57466151a28ddeca3e33c1427c119ea83eae0a1d Mon Sep 17 00:00:00 2001 From: David Smiley Date: Fri, 3 Apr 2026 17:34:04 -0400 Subject: [PATCH 3/3] lockfile --- solr/test-framework/gradle.lockfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solr/test-framework/gradle.lockfile b/solr/test-framework/gradle.lockfile index 2ae0de12ce0c..18e2d4850626 100644 --- a/solr/test-framework/gradle.lockfile +++ b/solr/test-framework/gradle.lockfile @@ -78,7 +78,7 @@ javax.inject:javax.inject:1=annotationProcessor,errorprone,testAnnotationProcess junit:junit:4.13.2=apiHelper,compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath org.antlr:antlr4-runtime:4.13.2=apiHelper,jarValidation,runtimeClasspath,testRuntimeClasspath org.apache.commons:commons-exec:1.5.0=apiHelper,jarValidation,runtimeClasspath,testRuntimeClasspath -org.apache.commons:commons-lang3:3.20.0=apiHelper,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.apache.commons:commons-lang3:3.20.0=apiHelper,jarValidation,runtimeClasspath,testRuntimeClasspath org.apache.commons:commons-math3:3.6.1=apiHelper,jarValidation,runtimeClasspath,testRuntimeClasspath org.apache.curator:curator-client:5.9.0=apiHelper,compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath org.apache.curator:curator-framework:5.9.0=apiHelper,compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath