This is an automated email from the ASF dual-hosted git repository. dsmiley pushed a commit to branch branch_10_0 in repository https://gitbox.apache.org/repos/asf/solr.git
commit 95cb7ff348c26b3bf2fd4bd2f5ee4b35fe5b2fa5 Author: David Smiley <[email protected]> AuthorDate: Thu Nov 20 09:11:39 2025 -0500 Tests: ServletFixtures (#3877) Deduplicate DebugServlet into one; resolve some semantic differences regarding case sensitivity of headers. Put several test servlets under a ServletFixtures class. --- .../client/solrj/impl/BasicHttpSolrClientTest.java | 225 ++++---------------- .../solr/client/solrj/impl/DebugServlet.java | 180 ---------------- .../impl/Http2SolrClientCompatibilityTest.java | 1 + .../client/solrj/impl/Http2SolrClientTest.java | 3 +- .../client/solrj/impl/HttpJdkSolrClientTest.java | 1 + .../client/solrj/impl/HttpSolrClientTestBase.java | 15 +- .../solr/client/solrj/impl/ServletFixtures.java | 228 +++++++++++++++++++++ 7 files changed, 281 insertions(+), 372 deletions(-) diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/BasicHttpSolrClientTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/BasicHttpSolrClientTest.java index 601c2442c10..ef372e93e50 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/BasicHttpSolrClientTest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/BasicHttpSolrClientTest.java @@ -16,26 +16,17 @@ */ package org.apache.solr.client.solrj.impl; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.lang.invoke.MethodHandles; import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; -import java.util.stream.IntStream; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpException; @@ -64,6 +55,10 @@ import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.apache.HttpClientUtil; import org.apache.solr.client.solrj.apache.HttpSolrClient; import org.apache.solr.client.solrj.apache.SolrPortAwareCookieSpecFactory; +import org.apache.solr.client.solrj.impl.ServletFixtures.DebugServlet; +import org.apache.solr.client.solrj.impl.ServletFixtures.RedirectServlet; +import org.apache.solr.client.solrj.impl.ServletFixtures.SlowServlet; +import org.apache.solr.client.solrj.impl.ServletFixtures.SlowStreamServlet; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.request.UpdateRequest; import org.apache.solr.client.solrj.response.QueryResponse; @@ -73,7 +68,6 @@ 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.NamedList; -import org.apache.solr.common.util.SuppressForbidden; import org.apache.solr.embedded.JettyConfig; import org.eclipse.jetty.ee10.servlet.ServletHolder; import org.junit.BeforeClass; @@ -86,141 +80,6 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private static final String UA_VERSION = SolrVersion.LATEST_STRING; - public static class RedirectServlet extends HttpServlet { - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - resp.sendRedirect("/solr/collection1/select?" + req.getQueryString()); - } - } - - public static class SlowServlet extends HttpServlet { - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - try { - Thread.sleep(5000); - } catch (InterruptedException ignored) { - } - } - } - - public static class SlowStreamServlet extends HttpServlet { - - public static final int PACKET_MS = 500; - - @Override - @SuppressForbidden(reason = "don't forbid in tests") - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { - String countStr = req.getParameter("count"); - IntStream.range(0, countStr == null ? 10 : Integer.parseInt(countStr)) - .forEach( - i -> { - try { - Thread.sleep(PACKET_MS); - resp.getOutputStream().write(String.valueOf(i).getBytes(StandardCharsets.UTF_8)); - resp.getOutputStream().flush(); - } catch (IOException | InterruptedException e) { - throw new RuntimeException(e); - } - }); - } - } - - public static class DebugServlet extends HttpServlet { - public static void clear() { - lastMethod = null; - headers = null; - parameters = null; - errorCode = null; - queryString = null; - cookies = null; - } - - public static Integer errorCode = null; - public static String lastMethod = null; - public static HashMap<String, String> headers = null; - public static Map<String, String[]> parameters = null; - public static String queryString = null; - public static jakarta.servlet.http.Cookie[] cookies = null; - - public static void setErrorCode(Integer code) { - errorCode = code; - } - - @Override - protected void doDelete(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - lastMethod = "delete"; - recordRequest(req, resp); - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - lastMethod = "get"; - recordRequest(req, resp); - } - - @Override - protected void doHead(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - lastMethod = "head"; - recordRequest(req, resp); - } - - private void setHeaders(HttpServletRequest req) { - Enumeration<String> headerNames = req.getHeaderNames(); - headers = new HashMap<>(); - while (headerNames.hasMoreElements()) { - final String name = headerNames.nextElement(); - headers.put(name, req.getHeader(name)); - } - } - - @SuppressForbidden(reason = "fake servlet only") - private void setParameters(HttpServletRequest req) { - parameters = req.getParameterMap(); - } - - private void setQueryString(HttpServletRequest req) { - queryString = req.getQueryString(); - } - - private void setCookies(HttpServletRequest req) { - jakarta.servlet.http.Cookie[] ck = req.getCookies(); - cookies = req.getCookies(); - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - lastMethod = "post"; - recordRequest(req, resp); - } - - @Override - protected void doPut(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - lastMethod = "put"; - recordRequest(req, resp); - } - - private void recordRequest(HttpServletRequest req, HttpServletResponse resp) { - setHeaders(req); - setParameters(req); - setQueryString(req); - setCookies(req); - if (null != errorCode) { - try { - resp.sendError(errorCode); - } catch (IOException e) { - throw new RuntimeException("sendError IO fail in DebugServlet", e); - } - } - } - } - @BeforeClass public static void beforeTest() throws Exception { JettyConfig jettyConfig = @@ -290,18 +149,18 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { // agent assertEquals( "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("User-Agent")); + 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")); + DebugServlet.headers.get("user-agent")); // keepalive - assertEquals("keep-alive", DebugServlet.headers.get("Connection")); + assertEquals("keep-alive", DebugServlet.headers.get("connection")); // content-type - assertNull(DebugServlet.headers.get("Content-Type")); + assertNull(DebugServlet.headers.get("content-type")); // param encoding assertEquals(1, DebugServlet.parameters.get("a").length); assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); @@ -314,18 +173,18 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { assertEquals("post", DebugServlet.lastMethod); assertEquals( "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("User-Agent")); + 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")); + 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.headers.get("content-type")); // PUT DebugServlet.clear(); @@ -335,18 +194,18 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { assertEquals("put", DebugServlet.lastMethod); assertEquals( "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("User-Agent")); + 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")); + 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.headers.get("content-type")); } // XML @@ -362,15 +221,15 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { assertEquals("get", DebugServlet.lastMethod); assertEquals( "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("User-Agent")); + 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")); + DebugServlet.headers.get("user-agent")); + assertEquals("keep-alive", DebugServlet.headers.get("connection")); // XML/POST DebugServlet.clear(); @@ -380,18 +239,18 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { assertEquals("post", DebugServlet.lastMethod); assertEquals( "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("User-Agent")); + 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")); + 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.headers.get("content-type")); DebugServlet.clear(); queryRequest.setMethod(METHOD.PUT); @@ -400,18 +259,18 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { assertEquals("put", DebugServlet.lastMethod); assertEquals( "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("User-Agent")); + 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")); + 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.headers.get("content-type")); } } @@ -431,16 +290,16 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { // agent assertEquals( "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("User-Agent")); + 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")); + DebugServlet.headers.get("user-agent")); // keepalive - assertEquals("keep-alive", DebugServlet.headers.get("Connection")); + assertEquals("keep-alive", DebugServlet.headers.get("connection")); } // XML @@ -458,13 +317,13 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { assertEquals("post", DebugServlet.lastMethod); assertEquals( "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("User-Agent")); + 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")); + DebugServlet.headers.get("user-agent")); + assertEquals("keep-alive", DebugServlet.headers.get("connection")); } } @@ -497,12 +356,12 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { // agent assertEquals( "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("User-Agent")); + 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")); + assertEquals("application/javabin", DebugServlet.headers.get("content-type")); // parameter encoding assertEquals(1, DebugServlet.parameters.get("a").length); assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); @@ -524,10 +383,10 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { assertEquals("post", DebugServlet.lastMethod); assertEquals( "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("User-Agent")); + 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("application/xml; charset=UTF-8", DebugServlet.headers.get("content-type")); assertEquals(1, DebugServlet.parameters.get("a").length); assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); } @@ -548,10 +407,10 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { assertEquals("post", DebugServlet.lastMethod); assertEquals( "Solr[" + HttpSolrClient.class.getName() + "] " + UA_VERSION, - DebugServlet.headers.get("User-Agent")); + 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("application/javabin", DebugServlet.headers.get("content-type")); assertEquals(1, DebugServlet.parameters.get("a").length); assertEquals("\u1234", DebugServlet.parameters.get("a")[0]); } @@ -597,7 +456,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { // verify request header gets set DebugServlet.clear(); expectThrows(SolrClient.RemoteSolrException.class, () -> queryRequest.process(client)); - assertNull(DebugServlet.headers.toString(), DebugServlet.headers.get("Accept-Encoding")); + assertNull(DebugServlet.headers.toString(), DebugServlet.headers.get("accept-encoding")); } try (SolrClient client = @@ -606,7 +465,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { queryRequest.process(client); } catch (SolrClient.RemoteSolrException ignored) { } - assertNotNull(DebugServlet.headers.get("Accept-Encoding")); + assertNotNull(DebugServlet.headers.get("accept-encoding")); } try (SolrClient client = @@ -616,7 +475,7 @@ public class BasicHttpSolrClientTest extends SolrJettyTestBase { } catch (SolrClient.RemoteSolrException ignored) { } } - assertNull(DebugServlet.headers.get("Accept-Encoding")); + assertNull(DebugServlet.headers.get("accept-encoding")); // verify server compresses output HttpGet get = new HttpGet(getCoreUrl() + "/select?q=foo&wt=xml"); diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/DebugServlet.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/DebugServlet.java deleted file mode 100644 index dee9b4a2549..00000000000 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/DebugServlet.java +++ /dev/null @@ -1,180 +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.impl; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import org.apache.solr.common.util.SuppressForbidden; - -public class DebugServlet extends HttpServlet { - public static void clear() { - lastMethod = null; - url = null; - headers = null; - parameters = null; - errorCode = null; - queryString = null; - cookies = null; - responseHeaders = null; - responseBodyByQueryFragment = new ConcurrentHashMap<>(); - } - - public static Integer errorCode = null; - public static String lastMethod = null; - public static String url = null; - public static HashMap<String, String> headers = null; - public static Map<String, String[]> parameters = null; - public static String queryString = null; - public static Cookie[] cookies = null; - public static List<String[]> responseHeaders = null; - public static Map<String, Object> responseBodyByQueryFragment = new ConcurrentHashMap<>(); - public static byte[] requestBody = null; - - public static void setErrorCode(Integer code) { - errorCode = code; - } - - public static void addResponseHeader(String headerName, String headerValue) { - if (responseHeaders == null) { - responseHeaders = new ArrayList<>(); - } - responseHeaders.add(new String[] {headerName, headerValue}); - } - - @Override - protected void doDelete(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - lastMethod = "delete"; - recordRequest(req, resp); - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - lastMethod = "get"; - recordRequest(req, resp); - } - - @Override - protected void doHead(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - lastMethod = "head"; - recordRequest(req, resp); - } - - private void setHeaders(HttpServletRequest req) { - Enumeration<String> headerNames = req.getHeaderNames(); - headers = new HashMap<>(); - while (headerNames.hasMoreElements()) { - final String name = headerNames.nextElement(); - headers.put(name.toLowerCase(Locale.getDefault()), req.getHeader(name)); - } - } - - @SuppressForbidden(reason = "fake servlet only") - private void setParameters(HttpServletRequest req) { - parameters = req.getParameterMap(); - } - - private void setQueryString(HttpServletRequest req) { - queryString = req.getQueryString(); - } - - private void setCookies(HttpServletRequest req) { - Cookie[] ck = req.getCookies(); - cookies = req.getCookies(); - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - lastMethod = "post"; - recordRequest(req, resp); - } - - @Override - protected void doPut(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - lastMethod = "put"; - recordRequest(req, resp); - } - - @SuppressForbidden(reason = "tests needn't comply") - private void recordRequest(HttpServletRequest req, HttpServletResponse resp) { - url = req.getRequestURL().toString(); - setHeaders(req); - setParameters(req); - setQueryString(req); - setCookies(req); - try { - requestBody = req.getInputStream().readAllBytes(); - } catch (Exception e) { - // ignore - } - if (responseHeaders != null) { - for (String[] h : responseHeaders) { - resp.addHeader(h[0], h[1]); - } - } - String qs = req.getQueryString(); - qs = qs == null ? "" : qs; - Object responseBody = null; - - // Tests can set this up to return different response bodies based on substrings in the query - // string - for (Map.Entry<String, Object> entry : responseBodyByQueryFragment.entrySet()) { - if (qs.contains(entry.getKey())) { - responseBody = entry.getValue(); - break; - } - } - - if (responseBody != null) { - try { - if (responseBody instanceof String) { - resp.getWriter().print((String) responseBody); - } else if (responseBody instanceof byte[]) { - resp.getOutputStream().write((byte[]) responseBody); - } else { - throw new IllegalArgumentException( - "Only String and byte[] are supported for responseBody."); - } - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - } - if (null != errorCode) { - try { - resp.sendError(errorCode); - } catch (IOException e) { - throw new RuntimeException("sendError IO fail in DebugServlet", e); - } - } - } -} diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientCompatibilityTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientCompatibilityTest.java index 3763e251da6..e58a016f9b6 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientCompatibilityTest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientCompatibilityTest.java @@ -23,6 +23,7 @@ import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.impl.ServletFixtures.DebugServlet; import org.apache.solr.embedded.JettyConfig; import org.apache.solr.util.LogLevel; import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP; diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientTest.java index 92d089f5ad2..b05da93f3f3 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientTest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientTest.java @@ -35,6 +35,7 @@ import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.impl.ServletFixtures.DebugServlet; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.request.SolrPing; import org.apache.solr.common.SolrException; @@ -675,7 +676,7 @@ public class Http2SolrClientTest extends HttpSolrClientTestBase { // too little time to succeed int packets = LuceneTestCase.RANDOM_MULTIPLIER == 1 ? 10 : 80; // 60 crosses a default timeout - long timeToSendMs = (long) packets * BasicHttpSolrClientTest.SlowStreamServlet.PACKET_MS; + long timeToSendMs = (long) packets * ServletFixtures.SlowStreamServlet.PACKET_MS; QueryRequest req = new QueryRequest(SolrParams.of("count", "" + packets)); req.setResponseParser(new InputStreamResponseParser(FILE_STREAM)); assertIsTimeout(expectThrows(SolrServerException.class, () -> oldClient.request(req))); diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpJdkSolrClientTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpJdkSolrClientTest.java index 8616cca08e9..b29be52e5f2 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpJdkSolrClientTest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpJdkSolrClientTest.java @@ -37,6 +37,7 @@ import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.impl.ServletFixtures.DebugServlet; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.response.SolrPingResponse; import org.apache.solr.common.params.CommonParams; diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientTestBase.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientTestBase.java index 79266ac9024..6a870b2b58e 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientTestBase.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientTestBase.java @@ -42,6 +42,10 @@ import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.apache.HttpClientUtil; +import org.apache.solr.client.solrj.impl.ServletFixtures.DebugServlet; +import org.apache.solr.client.solrj.impl.ServletFixtures.RedirectServlet; +import org.apache.solr.client.solrj.impl.ServletFixtures.SlowServlet; +import org.apache.solr.client.solrj.impl.ServletFixtures.SlowStreamServlet; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.request.UpdateRequest; import org.apache.solr.client.solrj.response.QueryResponse; @@ -74,15 +78,10 @@ public abstract class HttpSolrClientTestBase extends SolrJettyTestBase { public static void beforeTest() throws Exception { JettyConfig jettyConfig = JettyConfig.builder() - .withServlet( - new ServletHolder(BasicHttpSolrClientTest.RedirectServlet.class), - REDIRECT_SERVLET_REGEX) - .withServlet( - new ServletHolder(BasicHttpSolrClientTest.SlowServlet.class), SLOW_SERVLET_REGEX) + .withServlet(new ServletHolder(RedirectServlet.class), REDIRECT_SERVLET_REGEX) + .withServlet(new ServletHolder(SlowServlet.class), SLOW_SERVLET_REGEX) .withServlet(new ServletHolder(DebugServlet.class), DEBUG_SERVLET_REGEX) - .withServlet( - new ServletHolder(BasicHttpSolrClientTest.SlowStreamServlet.class), - SLOW_STREAM_SERVLET_REGEX) + .withServlet(new ServletHolder(SlowStreamServlet.class), SLOW_STREAM_SERVLET_REGEX) .withSSLConfig(sslConfig.buildServerSSLConfig()) .build(); createAndStartJetty(legacyExampleCollection1SolrHome(), jettyConfig); diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/ServletFixtures.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/ServletFixtures.java new file mode 100644 index 00000000000..c093cd673ca --- /dev/null +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/ServletFixtures.java @@ -0,0 +1,228 @@ +/* + * 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.impl; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.IntStream; +import org.apache.solr.common.util.SuppressForbidden; + +public class ServletFixtures { + + private ServletFixtures() {} + + public static class RedirectServlet extends HttpServlet { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.sendRedirect("/solr/collection1/select?" + req.getQueryString()); + } + } + + public static class SlowServlet extends HttpServlet { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + try { + Thread.sleep(5000); + } catch (InterruptedException ignored) { + } + } + } + + public static class SlowStreamServlet extends HttpServlet { + + public static final int PACKET_MS = 500; + + @SuppressForbidden(reason = "forbiddenApis: getParameter is fine in tests") + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String countStr = req.getParameter("count"); + IntStream.range(0, countStr == null ? 10 : Integer.parseInt(countStr)) + .forEach( + i -> { + try { + Thread.sleep(PACKET_MS); + resp.getOutputStream().write(String.valueOf(i).getBytes(StandardCharsets.UTF_8)); + resp.getOutputStream().flush(); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + }); + } + } + + public static class DebugServlet extends HttpServlet { + public static void clear() { + lastMethod = null; + url = null; + headers = null; + parameters = null; + errorCode = null; + queryString = null; + cookies = null; + responseHeaders = null; + responseBodyByQueryFragment = new ConcurrentHashMap<>(); + } + + public static Integer errorCode = null; + public static String lastMethod = null; + public static String url = null; + public static HashMap<String, String> headers = null; // lowercase keys! + public static Map<String, String[]> parameters = null; + public static String queryString = null; + public static Cookie[] cookies = null; + public static List<String[]> responseHeaders = null; + public static Map<String, Object> responseBodyByQueryFragment = new ConcurrentHashMap<>(); + public static byte[] requestBody = null; + + public static void setErrorCode(Integer code) { + errorCode = code; + } + + public static void addResponseHeader(String headerName, String headerValue) { + if (responseHeaders == null) { + responseHeaders = new ArrayList<>(); + } + responseHeaders.add(new String[] {headerName, headerValue}); + } + + @Override + protected void doDelete(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + lastMethod = "delete"; + recordRequest(req, resp); + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + lastMethod = "get"; + recordRequest(req, resp); + } + + @Override + protected void doHead(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + lastMethod = "head"; + recordRequest(req, resp); + } + + private void setHeaders(HttpServletRequest req) { + Enumeration<String> headerNames = req.getHeaderNames(); + headers = new HashMap<>(); + while (headerNames.hasMoreElements()) { + final String name = headerNames.nextElement(); + headers.put(name.toLowerCase(Locale.ROOT), req.getHeader(name)); + } + } + + @SuppressForbidden(reason = "fake servlet only") + private void setParameters(HttpServletRequest req) { + parameters = req.getParameterMap(); + } + + private void setQueryString(HttpServletRequest req) { + queryString = req.getQueryString(); + } + + private void setCookies(HttpServletRequest req) { + Cookie[] ck = req.getCookies(); + cookies = req.getCookies(); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + lastMethod = "post"; + recordRequest(req, resp); + } + + @Override + protected void doPut(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + lastMethod = "put"; + recordRequest(req, resp); + } + + @SuppressForbidden(reason = "forbiddenApis: getWriter is fine in tests") + private void recordRequest(HttpServletRequest req, HttpServletResponse resp) { + url = req.getRequestURL().toString(); + setHeaders(req); + setParameters(req); + setQueryString(req); + setCookies(req); + try { + requestBody = req.getInputStream().readAllBytes(); + } catch (Exception e) { + // ignore + } + if (responseHeaders != null) { + for (String[] h : responseHeaders) { + resp.addHeader(h[0], h[1]); + } + } + String qs = req.getQueryString(); + qs = qs == null ? "" : qs; + Object responseBody = null; + + // Tests can set this up to return different response bodies based on substrings in the query + // string + for (Map.Entry<String, Object> entry : responseBodyByQueryFragment.entrySet()) { + if (qs.contains(entry.getKey())) { + responseBody = entry.getValue(); + break; + } + } + + if (responseBody != null) { + try { + if (responseBody instanceof String) { + resp.getWriter().print((String) responseBody); + } else if (responseBody instanceof byte[]) { + resp.getOutputStream().write((byte[]) responseBody); + } else { + throw new IllegalArgumentException( + "Only String and byte[] are supported for responseBody."); + } + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } + if (null != errorCode) { + try { + resp.sendError(errorCode); + } catch (IOException e) { + throw new RuntimeException("sendError IO fail in DebugServlet", e); + } + } + } + } +}
