This is an automated email from the ASF dual-hosted git repository.
epugh pushed a commit to branch branch_10_0
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/branch_10_0 by this push:
new 6b54b4f0d9e SOLR-17935: Fix flaky TestRandomFlRTGCloud (#3860)
6b54b4f0d9e is described below
commit 6b54b4f0d9e077888cc332a89bf57b1eea10b75b
Author: Eric Pugh <[email protected]>
AuthorDate: Sat Nov 15 12:08:17 2025 -0500
SOLR-17935: Fix flaky TestRandomFlRTGCloud (#3860)
Rework the test TestRandomFlRTGCloud to avoid issues. Change
InputStreamResponseParser processRequest to correctly throw
UnsupportedOperationException.
---------
Co-authored-by: David Smiley <[email protected]>
---
.../apache/solr/cloud/TestRandomFlRTGCloud.java | 115 +++++++--------------
.../solrj/impl/InputStreamResponseParser.java | 9 +-
.../response/InputStreamResponseParserTest.java | 10 +-
.../response/TestDelegationTokenResponse.java | 18 +++-
4 files changed, 61 insertions(+), 91 deletions(-)
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestRandomFlRTGCloud.java
b/solr/core/src/test/org/apache/solr/cloud/TestRandomFlRTGCloud.java
index 8cd083c248a..3cf825f02bd 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestRandomFlRTGCloud.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestRandomFlRTGCloud.java
@@ -17,7 +17,6 @@
package org.apache.solr.cloud;
import java.io.IOException;
-import java.io.StringReader;
import java.lang.invoke.MethodHandles;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -37,12 +36,11 @@ import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.commons.io.FilenameUtils;
import org.apache.lucene.tests.util.TestUtil;
-import org.apache.solr.client.solrj.ResponseParser;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.apache.HttpSolrClient;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
-import org.apache.solr.client.solrj.impl.InputStreamResponseParser;
+import org.apache.solr.client.solrj.impl.JsonMapResponseParser;
import org.apache.solr.client.solrj.impl.XMLResponseParser;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.QueryRequest;
@@ -56,7 +54,6 @@ import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.IOUtils;
import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.Pair;
import org.apache.solr.embedded.JettySolrRunner;
import org.apache.solr.response.transform.DocTransformer;
import org.apache.solr.response.transform.RawValueTransformerFactory;
@@ -80,8 +77,8 @@ public class TestRandomFlRTGCloud extends SolrCloudTestCase {
/** A collection specific client for operations at the cloud level */
private static CloudSolrClient COLLECTION_CLIENT;
- /** We have a map of clients using specific writerTypes, keyed by pair of
baseurl and wt */
- private static final Map<Pair<String, String>, SolrClient> CLIENTS = new
ConcurrentHashMap<>();
+ /** We have a map of clients, keyed by base URL */
+ private static final Map<String, SolrClient> CLIENTS = new
ConcurrentHashMap<>();
/** Always included in fl, so we can check what doc we're looking at */
private static final FlValidator ID_VALIDATOR = new
SimpleFieldValueValidator("id");
@@ -276,7 +273,7 @@ public class TestRandomFlRTGCloud extends SolrCloudTestCase
{
final float threshold = (float) itersSinceLastCommit / numIters;
if (rand.nextFloat() < threshold) {
log.info("COMMIT");
- assertEquals(0, getRandomClient(rand).commit().getStatus());
+ assertEquals(0,
cluster.getSolrClient(COLLECTION_NAME).commit().getStatus());
return 0;
}
return itersSinceLastCommit + 1;
@@ -352,7 +349,7 @@ public class TestRandomFlRTGCloud extends SolrCloudTestCase
{
assertEquals(
"Failed delete: " + Arrays.toString(docIds),
0,
- getRandomClient(random()).deleteById(ids).getStatus());
+ cluster.getSolrClient(COLLECTION_NAME).deleteById(ids).getStatus());
}
/**
@@ -361,7 +358,7 @@ public class TestRandomFlRTGCloud extends SolrCloudTestCase
{
*/
private SolrInputDocument addRandomDocument(final int docId)
throws IOException, SolrServerException {
- final SolrClient client = getRandomClient(random());
+ final SolrClient client = cluster.getSolrClient(COLLECTION_NAME);
final SolrInputDocument doc =
sdoc(
@@ -423,26 +420,8 @@ public class TestRandomFlRTGCloud extends
SolrCloudTestCase {
}
}
- private static final ResponseParser RAW_XML_RESPONSE_PARSER =
- new InputStreamResponseParser("xml");
- private static final ResponseParser RAW_JSON_RESPONSE_PARSER =
- new InputStreamResponseParser("json");
-
- /** Helper to convert from wt string parameter to actual SolrClient. */
- private static SolrClient getSolrClient(final String jettyBaseUrl, final
String wt) {
- HttpSolrClient.Builder builder =
- new
HttpSolrClient.Builder(jettyBaseUrl).withDefaultCollection(COLLECTION_NAME);
- switch (wt) {
- case "xml":
- builder.withResponseParser(RAW_XML_RESPONSE_PARSER);
- break;
- case "json":
- builder.withResponseParser(RAW_JSON_RESPONSE_PARSER);
- break;
- default:
- break;
- }
- return builder.build();
+ private static SolrClient getSolrClient(final String jettyBaseUrl) {
+ return new
HttpSolrClient.Builder(jettyBaseUrl).withDefaultCollection(COLLECTION_NAME).build();
}
/**
@@ -508,7 +487,7 @@ public class TestRandomFlRTGCloud extends SolrCloudTestCase
{
}
String wt = params.get(CommonParams.WT, "javabin");
- final SolrClient client = getRandomClient(random(), wt);
+ final SolrClient client = getRandomClient(random());
// If we have chosen a CloudSolrClient, then override wt parameter back to
javabin format,
// regardless of what was randomly picked.
@@ -516,30 +495,30 @@ public class TestRandomFlRTGCloud extends
SolrCloudTestCase {
wt = "javabin";
}
- final Object rsp;
- final SolrDocumentList docs;
- if ("javabin".equals(wt)) {
- // the most common case
- final QueryResponse qRsp = client.query(params);
- assertNotNull(params.toString(), qRsp);
- rsp = qRsp;
- docs = getDocsFromRTGResponse(askForList, qRsp);
- } else {
- final NamedList<Object> nlRsp = client.request(new QueryRequest(params));
- assertNotNull(params.toString(), nlRsp);
- rsp = nlRsp;
- final String textResult =
InputStreamResponseParser.consumeResponseToString(nlRsp);
- switch (wt) {
- case "json":
- docs = getDocsFromJsonResponse(askForList, textResult);
- break;
- case "xml":
- docs = getDocsFromXmlResponse(askForList, textResult);
- break;
- default:
- throw new IllegalStateException();
- }
- }
+ final Object rsp; // only here for an assertion message
+
+ var qr = new QueryRequest(params);
+ final SolrDocumentList docs =
+ switch (wt) {
+ case "javabin" -> { // the most common case
+ final QueryResponse qRsp = qr.process(client);
+ rsp = qRsp;
+ yield getDocsFromRTGResponse(askForList, qRsp);
+ }
+ case "json" -> {
+ qr.setResponseParser(new JsonMapResponseParser());
+ final NamedList<Object> nlRsp = client.request(qr);
+ rsp = nlRsp;
+ yield getDocsFromJsonResponse(askForList, nlRsp);
+ }
+ case "xml" -> {
+ qr.setResponseParser(new RawCapableXMLResponseParser());
+ final NamedList<Object> nlRsp = client.request(qr);
+ rsp = nlRsp;
+ yield getDocsFromXmlResponse(askForList, nlRsp);
+ }
+ default -> throw new IllegalStateException();
+ };
assertNotNull(params + " => " + rsp, docs);
@@ -607,8 +586,7 @@ public class TestRandomFlRTGCloud extends SolrCloudTestCase
{
@SuppressWarnings("unchecked")
private static SolrDocumentList getDocsFromJsonResponse(
- final boolean expectList, final String rsp) throws IOException {
- Map<String, Object> nl = (Map<String, Object>) ObjectBuilder.fromJSON(rsp);
+ final boolean expectList, final NamedList<?> nl) throws IOException {
if (expectList) {
return getSolrDocumentList((Map<String, Object>) nl.get("response"));
} else {
@@ -621,29 +599,17 @@ public class TestRandomFlRTGCloud extends
SolrCloudTestCase {
}
}
+ @SuppressWarnings("unchecked")
private static SolrDocumentList getDocsFromXmlResponse(
- final boolean expectList, final String rsp) {
- return getDocsFromRTGResponse(
- expectList,
- new QueryResponse(
- new RawCapableXMLResponseParser().processResponse(new
StringReader(rsp))));
+ final boolean expectList, final NamedList<?> rsp) {
+ return getDocsFromRTGResponse(expectList, new
QueryResponse((NamedList<Object>) rsp));
}
/**
- * returns a random SolrClient -- either a CloudSolrClient, or an
HttpSolrClient pointed at a node
- * in our cluster. This method doesn't care which wt is defined.
+ * This method return a random SolrClient, and can include CloudSolrClient
to choose from cloud in
+ * our cluster.
*/
public static SolrClient getRandomClient(Random rand) {
- List<String> writerTypes = List.of("javabin", "json", "xml");
- int writerTypeIdx = TestUtil.nextInt(rand, 0, writerTypes.size() - 1);
- return getRandomClient(rand, writerTypes.get(writerTypeIdx));
- }
-
- /**
- * returns a random SolrClient -- either a CloudSolrClient, or an
HttpSolrClient pointed at a node
- * in our cluster. We have different CLIENTS created for each node based on
their wt setting.
- */
- public static SolrClient getRandomClient(Random rand, String wt) {
List<JettySolrRunner> jettySolrRunners = cluster.getJettySolrRunners();
int numClients = jettySolrRunners.size();
int idx = TestUtil.nextInt(rand, 0, numClients);
@@ -653,8 +619,7 @@ public class TestRandomFlRTGCloud extends SolrCloudTestCase
{
} else {
JettySolrRunner jetty = jettySolrRunners.get(idx);
String jettyBaseUrl = jetty.getBaseUrl().toString();
- return CLIENTS.computeIfAbsent(
- new Pair<>(jettyBaseUrl, wt), k -> getSolrClient(k.first(),
k.second()));
+ return CLIENTS.computeIfAbsent(jettyBaseUrl,
TestRandomFlRTGCloud::getSolrClient);
}
}
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/InputStreamResponseParser.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/InputStreamResponseParser.java
index 9da5117d046..ecf121e49b0 100644
---
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/InputStreamResponseParser.java
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/InputStreamResponseParser.java
@@ -19,8 +19,6 @@ package org.apache.solr.client.solrj.impl;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import org.apache.solr.client.solrj.ResponseParser;
@@ -66,12 +64,7 @@ public class InputStreamResponseParser extends
ResponseParser {
@Override
public NamedList<Object> processResponse(InputStream body, String encoding)
throws IOException {
- StringWriter writer = new StringWriter();
- new InputStreamReader(body, encoding == null ? "UTF-8" :
encoding).transferTo(writer);
- String output = writer.toString();
- NamedList<Object> list = new NamedList<>();
- list.add("response", output);
- return list;
+ throw new UnsupportedOperationException();
}
@Override
diff --git
a/solr/solrj/src/test/org/apache/solr/client/solrj/response/InputStreamResponseParserTest.java
b/solr/solrj/src/test/org/apache/solr/client/solrj/response/InputStreamResponseParserTest.java
index 4a39234d52d..f3e8433b85f 100644
---
a/solr/solrj/src/test/org/apache/solr/client/solrj/response/InputStreamResponseParserTest.java
+++
b/solr/solrj/src/test/org/apache/solr/client/solrj/response/InputStreamResponseParserTest.java
@@ -95,11 +95,11 @@ public class InputStreamResponseParserTest extends
SolrJettyTestBase {
InputStreamResponseParser parser = new InputStreamResponseParser("xml");
try (final InputStream is = getResponse()) {
assertNotNull(is);
- NamedList<Object> response = parser.processResponse(is, "UTF-8");
-
- assertNotNull(response.get("response"));
- String expectedResponse = new String(getResponse().readAllBytes(),
StandardCharsets.UTF_8);
- assertEquals(expectedResponse, response.get("response"));
+ assertThrows(
+ UnsupportedOperationException.class,
+ () -> {
+ parser.processResponse(is, "UTF-8");
+ });
}
}
}
diff --git
a/solr/solrj/src/test/org/apache/solr/client/solrj/response/TestDelegationTokenResponse.java
b/solr/solrj/src/test/org/apache/solr/client/solrj/response/TestDelegationTokenResponse.java
index eea00be5608..cd6c717a333 100644
---
a/solr/solrj/src/test/org/apache/solr/client/solrj/response/TestDelegationTokenResponse.java
+++
b/solr/solrj/src/test/org/apache/solr/client/solrj/response/TestDelegationTokenResponse.java
@@ -23,8 +23,10 @@ import java.util.HashMap;
import java.util.Map;
import org.apache.solr.SolrTestCase;
import org.apache.solr.client.solrj.ResponseParser;
+import org.apache.solr.client.solrj.impl.InputStreamResponseParser;
import org.apache.solr.client.solrj.request.DelegationTokenRequest;
import org.apache.solr.common.SolrException;
+import org.apache.solr.common.util.NamedList;
import org.junit.Test;
import org.noggit.CharArr;
import org.noggit.JSONWriter;
@@ -35,9 +37,19 @@ public class TestDelegationTokenResponse extends
SolrTestCase {
DelegationTokenRequest<?, ?> request, DelegationTokenResponse response,
String responseBody)
throws Exception {
ResponseParser parser = request.getResponseParser();
- response.setResponse(
- parser.processResponse(
- new
ByteArrayInputStream(responseBody.getBytes(StandardCharsets.UTF_8)), "UTF-8"));
+
+ // InputStreamResponseParser doesn't support processResponse(),
+ // so we need to handle it differently
+ if (parser instanceof InputStreamResponseParser) {
+ // For InputStreamResponseParser (used by Cancel request),
+ // create a NamedList directly since it expects empty response
+ response.setResponse(new NamedList<>());
+ } else {
+ // For JsonMapResponseParser (used by Get and Renew requests)
+ response.setResponse(
+ parser.processResponse(
+ new
ByteArrayInputStream(responseBody.getBytes(StandardCharsets.UTF_8)), "UTF-8"));
+ }
}
private String getNestedMapJson(String outerKey, String innerKey, Object
innerValue) {