Skip to content

SOLR-18188: Tests, switch from Apache HttpClient to Jetty HttpClient#4266

Open
dsmiley wants to merge 24 commits intoapache:mainfrom
dsmiley:SOLR-18188-migrateToJettyHttpClient
Open

SOLR-18188: Tests, switch from Apache HttpClient to Jetty HttpClient#4266
dsmiley wants to merge 24 commits intoapache:mainfrom
dsmiley:SOLR-18188-migrateToJettyHttpClient

Conversation

@dsmiley
Copy link
Copy Markdown
Contributor

@dsmiley dsmiley commented Apr 6, 2026

https://issues.apache.org/jira/browse/SOLR-18188

This PR switches nearly all tests that were using Apache HttpClient directly to instead use Jetty HttpClient (or in some cases a plain SolrClient given we can do a lot with them). Also any tests with import org.apache.http.

As of this writing, I deferred ~8 tests that casted a cloud client to CloudLegacySolrClient to then call getHttpClient merely to create an HttpSolrClient with the same backing client -- maybe for efficiency. TBD on their fate.

SimplePrinciple was made a record and used in places where an Apache variant was used.

In URLUtils, I added a new method: buildURI which is needed in RestTestHarness, BackupRestoreUtils, and I think eventually more places. It handles URI encoding matters. Apparently Apache HttpClient was doing things implicitly that Jetty doesn't.

This is another step in a journey that continues

(follow-up note: scope was reduced. see #4270 for the rest).

dsmiley added 2 commits April 5, 2026 12:14
…ient etc. is still allowed.

Don't import org.apache.http classes.

Mostly done via Google Jules.
Introduce URLUtil.buildURI
Copy link
Copy Markdown
Contributor

@epugh epugh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

14 out of 67 reviewed, this is all looking great! Really excited to see this big lift done, and the tests are reading much nicer.

createCollectionPost.setEntity(new StringEntity(requestBody));
HttpResponse httpResponse =
((CloudLegacySolrClient) cluster.getSolrClient())
var response2 =
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is much nicer, much less clunky plumbing!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even thoguh we set all the same things.

400, httpClient.newRequest(baseUrl + aliasApi).method(HttpMethod.PUT).send().getStatus());

String body =
"{\n"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i had good luck with the """ tags to simplify json formatted strings. Since you are reformatting a lot in this PR, might be worth embracing it for the JSON?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may change some of these where I add new code but otherwise don't want to change more lines in a massive PR.

url = url + pickRandom("", "&nrtReplicas=1", "&replicationFactor=1");
HttpGet createCollectionGet = new HttpGet(url);
getHttpClient().execute(createCollectionGet);
url1 = url1 + pickRandom("", "&nrtReplicas=1", "&replicationFactor=1");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah my old friend, you are back again numbered variable..

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm able to address most/all of those issues via simply using switch-expressions, which creates blocks of isolated scope


@SuppressWarnings({"rawtypes"})
private static LinkedHashMapWriter getRespMap(String baseUrl, String path) throws Exception {
// a hack... if possible pass in an httpClient and also be able to init RestTestHarness with it
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a note to yourself for future work in this PR, or for a future developer? if it's for a future dev, maybe elaborate a bit more and add that tag we use? todo or something?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"hack" is possibly overstated. It's not ideal to create a new harness (which creates a client) when I'd rather somehow re-use a client. I don't think I feel strongly enough now to bother with TODO here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a little... trick/hack enabling use of TestHarness created for a different baseUrl, and thus this method is now removed.

.newRequest(baseUrl + "/cluster/filestore/files" + path)
.send();
assertEquals(200, resp.getStatus());
ByteBuffer buf = ByteBuffer.wrap(resp.getContent());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reads so much nicer!

Copy link
Copy Markdown
Contributor Author

@dsmiley dsmiley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is huge...
Honestly review-wise... if tests pass...
I'll try and draw attention to "interesting" things.


/** A basic name-only {@link Principal}. */
public final class SimplePrincipal implements Principal {
// TODO use a record. But javadoc tooling complained as it was confused (Java version issue?)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this mystery was solved previously, unblocking this nice conversion


public class AliasIntegrationTest extends SolrCloudTestCase {

private CloseableHttpClient httpClient;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usually no field is needed since it's easy to grab a managed Jetty HttpClient from places

Comment on lines +248 to +252
httpClient
.newRequest(baseUrl + aliasApi)
.method(HttpMethod.PUT)
.body(new StringRequestContent("application/json", body, StandardCharsets.UTF_8))
.send());
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I preferred this "fluent" style whenever possible as I thinks it helps readability

} catch (Exception exc) {
Throwable rootCause = SolrException.getRootCause(exc);
if (rootCause instanceof NoHttpResponseException) {
if (rootCause instanceof IOException) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in tests we trust... 🙏
NoHttpResponseException is Apache HttpClient specific

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ported/moved

dsmiley added 6 commits April 6, 2026 13:14
…88-migrateToJettyHttpClient

# Conflicts:
#	solr/solrj/src/test/org/apache/solr/client/solrj/embedded/JettyWebappTest.java
  Didn't need version suffixes on vars since they are now scoped.
dsmiley added 7 commits April 6, 2026 16:52
* better exception handling.
* allow passing an absolute URL thus overriding the base
…ettyHttpClient

# Conflicts:
#	solr/test-framework/build.gradle
…onstruct

RestTestHarness is now immutable and no longer owns resources, making it
cheap to create on-the-fly for different URLs without complex lifecycle
management.

Changes to RestTestHarness:
- Removed Closeable interface - RTH no longer owns the HttpClient
- Removed RESTfulServerProvider interface and setServerProvider() method
- Removed the "://" hack for detecting absolute URLs in buildUri()
- New constructor: RestTestHarness(HttpClient, String baseUrl)
- Convenience constructor: RestTestHarness(JettySolrRunner, String coreOrCollection)
  Gets HttpClient from jetty.getSolrClient().getHttpClient()
- Added newWithUrl(String) helper to create new instance with different URL
  sharing the same HttpClient

Updated test infrastructure:
- Simplified testForResponseElement() by removing testServerBaseUrl and
  cloudSolrClient parameters; now requires non-null harness
- Simplified reqhandlertests() to take only RestTestHarness parameter
- Removed all close() calls and try-with-resources blocks
- Updated tests to create RTH instances on-the-fly instead of mutating via
  setServerProvider()
- TestReqParamsAPI, TestSolrConfigHandlerCloud, and others now use
  harness.newWithUrl() to query specific replica URLs
- TestSolrConfigHandlerConcurrent.getAsMap() now takes RestTestHarness
  instead of HttpClient + URI
dsmiley added 2 commits April 7, 2026 09:45
RestTestHarness: URI based
RestTestHarness.head restored; different signature
RestTestHarness: URI based
RestTestHarness.head restored; different signature

Fixed a few bugs
@dsmiley
Copy link
Copy Markdown
Contributor Author

dsmiley commented Apr 7, 2026

I made a significant change to make RestTestHarness cheap to create without any need to close it, and also making it immutable.

I think I should split this big PR, a new one centered on RestTestHarness and most of its users and thus also including the URLUtils.buildURI addition. WDYT @epugh ? I could do that ~quickly and then we come back to this PR.

@dsmiley
Copy link
Copy Markdown
Contributor Author

dsmiley commented Apr 7, 2026

RestTestHarness & URLUtils stuff is now reverted from this PR; see #4270 for them.

Now this PR is smaller, albeit still pretty big.

@epugh
Copy link
Copy Markdown
Contributor

epugh commented Apr 8, 2026

I think that was a good decision. I will review and run the tests locally

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants