Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions solr/core/src/test/org/apache/solr/cli/PackageToolTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,63 @@ public static void testForResponseElement(
success);
}

/** Validates that collection existence is checked before package resolution. */
@Test
public void testDeployValidationMessages() throws Exception {
String solrUrl = cluster.getJettySolrRunner(0).getBaseUrl().toString();

withBasicAuth(CollectionAdminRequest.createCollection("validation-test", "conf1", 1, 1))
.processAndWait(cluster.getSolrClient(), 10);

CLITestHelper.TestingRuntime captureRuntime = new CLITestHelper.TestingRuntime(true);
PackageTool tool = new PackageTool(captureRuntime);

// Collection exists but package does not — collection validation should pass,
// package lookup should fail.
tool.runTool(
SolrCLI.processCommandLineArgs(
tool,
new String[] {
"--solr-url",
solrUrl,
"deploy",
"NONEXISTENT_PKG",
"--collections",
"validation-test",
"--credentials",
SecurityJson.USER_PASS
}));
String deployOut = captureRuntime.getOutput();
assertFalse(
"Should not complain about invalid collection", deployOut.contains("Invalid collection"));
assertTrue(
"Should report missing package",
deployOut.contains("Package instance doesn't exist: NONEXISTENT_PKG:null"));

captureRuntime.clearOutput();

// Undeploy of a package that was never deployed should give a clear message.
tool.runTool(
SolrCLI.processCommandLineArgs(
tool,
new String[] {
"--solr-url",
solrUrl,
"undeploy",
"NONEXISTENT_PKG",
"--collections",
"validation-test",
"--credentials",
SecurityJson.USER_PASS
}));
String undeployOut = captureRuntime.getOutput();
assertFalse(
"Should not complain about invalid collection", undeployOut.contains("Invalid collection"));
assertTrue(
"Should report package not deployed",
undeployOut.contains("Package NONEXISTENT_PKG not deployed on collection validation-test"));
}

private void run(PackageTool tool, String[] args) throws Exception {
int res = tool.runTool(SolrCLI.processCommandLineArgs(tool, args));
assertEquals("Non-zero status returned for: " + Arrays.toString(args), 0, res);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* 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.servlet;

import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.SolrInputDocument;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.http.HttpHeader;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

/**
* Verifies that Solr's Jetty GzipHandler correctly compresses HTTP responses when the client sends
* {@code Accept-Encoding: gzip} and omits compression when that header is absent.
*/
public class GzipCompressionTest extends SolrCloudTestCase {
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.

Why would use need SolrCloud for only a jetty level thing?

Copy link
Copy Markdown
Contributor Author

@janhoy janhoy May 31, 2026

Choose a reason for hiding this comment

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

Solrcloud is the default now, why not - it's a 1-node "cluster". Is there some overhead with SolrCloudTestCase that we don't have with a simpler JettySolrRunner?

I also tried to refactor to JettySolrRunner but it has no GZip handler as the cloud setup does.

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.

My point is the principle of using the leanest test infrastructure to accomplish the testing goal. Default doesn't matter.

Where is the gzip support in the SolrCloudTestCase/MiniSolrCloudCluster you speak of?

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'd have to dive into the test setup to answer. I thought we used same JettySolrRunner as in standalone, and that Jetty is configured in java instead of xml, but still not 100% identical. I have not verified that the new Gzip test actually tests what it claims to. Will have to do a manual dive to verify. I had my hopes up when Claude selected it as a low hanging fruit.

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 miss the succinteness of the .bats test and how easy it is to read (to my eyes at least!), but totally understand the overhead.

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.

If we keep adding BATS tests in the pace we have been doing lately, we'll surpass 60m run time very soon. So we should probably reserve BATS for testing our bin/solr shell script, plus mechanisms that won't kick in in unit tests. The java-agent is an example of such. And "realistic" jetty setup is probably another.

But I'd hope that as we succeed in slimming down bin/solr even more and move things into java-land, we should be able to migrate more BATS tests to JUnit since the logic is no longer done in bash.

We have already delegated lots of SolrCLI arg parsing to java-land. There is still some glue in script that construct the java cmdline, which do need to be tested, but the cmdline arg/opts parsing for each tool should not need full bats coverage if we know we have separate junit coverage of such parsing.


private static final String COLLECTION = "gzip-test";

@BeforeClass
public static void setupCluster() throws Exception {
// Lower the minGzipSize threshold so any non-empty response body is eligible for compression.
// jetty-gzip.xml reads this property at Jetty start time via <Property
// name="jetty.gzip.minGzipSize">.
System.setProperty("jetty.gzip.minGzipSize", "1");

configureCluster(1).configure();

CollectionAdminRequest.createCollection(COLLECTION, null, 1, 1)
.process(cluster.getSolrClient());

// Index a few documents so the select response has a non-trivial body
UpdateRequest req = new UpdateRequest();
for (int i = 0; i < 10; i++) {
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", "doc-" + i);
doc.addField("name_s", "Document number " + i + " for gzip compression test");
req.add(doc);
}
req.commit(cluster.getSolrClient(), COLLECTION);
}

@AfterClass
public static void clearGzipSysProp() {
System.clearProperty("jetty.gzip.minGzipSize");
}

private HttpClient getHttpClient() {
return cluster.getJettySolrRunner(0).getSolrClient().getHttpClient();
}

private String getSelectUrl() {
return cluster.getJettySolrRunner(0).getBaseUrl() + "/" + COLLECTION + "/select?q=*:*&rows=10";
}

@Test
public void testNoCompressionWithoutAcceptEncodingHeader() throws Exception {
ContentResponse response = getHttpClient().GET(getSelectUrl());
assertEquals("Expected HTTP 200", 200, response.getStatus());
assertNull(
"Content-Encoding should not be set when Accept-Encoding header is absent",
response.getHeaders().get(HttpHeader.CONTENT_ENCODING));
}

@Test
public void testGzipCompressionWithAcceptEncodingHeader() throws Exception {
ContentResponse response =
getHttpClient()
.newRequest(getSelectUrl())
.headers(h -> h.add(HttpHeader.ACCEPT_ENCODING, "gzip"))
.send();
assertEquals("Expected HTTP 200", 200, response.getStatus());
assertEquals(
"Expected gzip Content-Encoding when Accept-Encoding: gzip was requested",
"gzip",
response.getHeaders().get(HttpHeader.CONTENT_ENCODING));
}
}
47 changes: 0 additions & 47 deletions solr/packaging/test/test_compression.bats

This file was deleted.

25 changes: 18 additions & 7 deletions solr/packaging/test/test_example.bats
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,36 @@

load bats_helper

setup() {
setup_file() {
common_clean_setup
solr start -e cloud --no-prompt --jvm-opts "-Dcustom.prop=helloworld"
solr assert --started http://localhost:${SOLR_PORT} --cloud http://localhost:${SOLR_PORT} --timeout 60000
solr assert --started http://localhost:${SOLR2_PORT} --cloud http://localhost:${SOLR2_PORT} --timeout 60000
}

teardown_file() {
common_setup
solr stop --all >/dev/null 2>&1
}

setup() {
common_setup
}

teardown() {
# save a snapshot of SOLR_HOME for failed tests
save_home_on_failure
}

solr stop --all >/dev/null 2>&1
@test "start -e cloud works with --no-prompt" {
solr assert --started http://localhost:${SOLR_PORT} --cloud http://localhost:${SOLR_PORT} --timeout 10000
solr assert --started http://localhost:${SOLR2_PORT} --cloud http://localhost:${SOLR2_PORT} --timeout 10000
}

@test "start -e cloud works with --jvm-opts" {
solr start -e cloud --no-prompt --jvm-opts "-Dcustom.prop=helloworld"
solr assert --started http://localhost:${SOLR_PORT} --cloud http://localhost:${SOLR_PORT} --timeout 60000
solr assert --started http://localhost:${SOLR2_PORT} --cloud http://localhost:${SOLR2_PORT} --timeout 60000

run curl "http://localhost:${SOLR_PORT}/solr/admin/info/properties"
assert_output --partial 'helloworld'

run curl "http://localhost:${SOLR2_PORT}/solr/admin/info/properties"
assert_output --partial 'helloworld'
}
35 changes: 0 additions & 35 deletions solr/packaging/test/test_example_noprompt.bats

This file was deleted.

11 changes: 5 additions & 6 deletions solr/packaging/test/test_healthcheck.bats
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,14 @@ teardown() {
}

@test "healthcheck on cloud solr" {
solr start -e films
run solr healthcheck -c films
solr start
solr create -c healthcheck_test -d _default
run solr healthcheck -c healthcheck_test
refute_output --partial 'error'

}

@test "healthcheck errors on standalone solr" {
solr start --user-managed -e films
run solr healthcheck -c films
solr start --user-managed
run solr healthcheck -c healthcheck_test
assert_output --partial 'Healthcheck tool only works in Solr Cloud mode'

}
3 changes: 3 additions & 0 deletions solr/packaging/test/test_opennlp.bats
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ teardown() {
# I also have dreams of incorporating this as code snippets in a Tutorial via the ascii doc tags
# like we use for the SolrJ code snippets. That way we know the snippets continue to work!
@test "Check lifecycle of sentiment classification" {
if [ -z "${SOLR_BATS_OPENNLP_TESTS:-}" ]; then
skip "Set SOLR_BATS_OPENNLP_TESTS=true to run OpenNLP integration tests (downloads models from network)"
fi

echo "Downloading onnx model and vocab..."

Expand Down
Loading
Loading