diff --git a/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java b/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java index e8cb48874b68..9282af37e520 100644 --- a/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java +++ b/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java @@ -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); diff --git a/solr/core/src/test/org/apache/solr/servlet/GzipCompressionTest.java b/solr/core/src/test/org/apache/solr/servlet/GzipCompressionTest.java new file mode 100644 index 000000000000..c6a2d69b4ab6 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/servlet/GzipCompressionTest.java @@ -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 { + + 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 . + 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)); + } +} diff --git a/solr/packaging/test/test_compression.bats b/solr/packaging/test/test_compression.bats deleted file mode 100644 index 575490c8f99a..000000000000 --- a/solr/packaging/test/test_compression.bats +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bats - -# 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. - -load bats_helper - -setup_file() { - common_clean_setup - solr start -e films -} - -setup() { - common_setup -} - -teardown_file() { - save_home_on_failure - solr stop --all >/dev/null 2>&1 -} - -@test "server does not compress response without Accept-Encoding header" { - run curl -s -D - -o /dev/null "http://localhost:${SOLR_PORT}/solr/films/select?q=*:*&rows=100" - refute_output --partial "Content-Encoding:" -} - -@test "server compresses response when Accept-Encoding: gzip is requested" { - run curl -s -D - -o /dev/null -H "Accept-Encoding: gzip" "http://localhost:${SOLR_PORT}/solr/films/select?q=*:*&rows=100" - assert_output --partial "gzip" -} - -@test "compressed response can be decompressed and parsed" { - run curl -s --compressed "http://localhost:${SOLR_PORT}/solr/films/select?q=*:*&rows=100" - assert_output --partial '"status":0' -} diff --git a/solr/packaging/test/test_example.bats b/solr/packaging/test/test_example.bats index a15ba4b6f625..a5b4108e549d 100644 --- a/solr/packaging/test/test_example.bats +++ b/solr/packaging/test/test_example.bats @@ -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' } diff --git a/solr/packaging/test/test_example_noprompt.bats b/solr/packaging/test/test_example_noprompt.bats deleted file mode 100644 index 19329a8041af..000000000000 --- a/solr/packaging/test/test_example_noprompt.bats +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bats - -# 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. - -load bats_helper - -setup() { - common_clean_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 start -e cloud --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 -} diff --git a/solr/packaging/test/test_healthcheck.bats b/solr/packaging/test/test_healthcheck.bats index 30edfeff2357..ce5f480398d7 100644 --- a/solr/packaging/test/test_healthcheck.bats +++ b/solr/packaging/test/test_healthcheck.bats @@ -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' - } diff --git a/solr/packaging/test/test_opennlp.bats b/solr/packaging/test/test_opennlp.bats index 69ee71253cf4..c5d53c78f581 100644 --- a/solr/packaging/test/test_opennlp.bats +++ b/solr/packaging/test/test_opennlp.bats @@ -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..." diff --git a/solr/packaging/test/test_packages.bats b/solr/packaging/test/test_packages.bats deleted file mode 100644 index 1f60523e53f0..000000000000 --- a/solr/packaging/test/test_packages.bats +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env bats - -# 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. - -load bats_helper - -setup() { - common_clean_setup -} - -teardown() { - # save a snapshot of SOLR_HOME for failed tests - save_home_on_failure - - solr stop --all >/dev/null 2>&1 -} - -@test "lifecycle of package" { - run solr start -Dsolr.packages.enabled=true - - run solr package --help - assert_output --partial "Add a repository to Solr" - - run solr package list-available - assert_output --partial "Available packages:" -} - -@test "deploying and undeploying a collection level package" { - run solr start -Dsolr.packages.enabled=true - - solr create -c foo-1.2 - - # Deploy package - the package doesn't need to exist before the collection validation kicks in - run solr package deploy PACKAGE_NAME --collections foo-1.2 - # assert_output --partial "Deployment successful" - refute_output --partial "Invalid collection" - - # Until PACKAGE_NAME refers to an actual installable package, this is as far as we get. - assert_output --partial "Package instance doesn't exist: PACKAGE_NAME:null" - - # Undeploy package - run solr package undeploy PACKAGE_NAME --collections foo-1.2 - refute_output --partial "Invalid collection" - assert_output --partial "Package PACKAGE_NAME not deployed on collection foo-1.2" -} - -# This test is useful if you are debugging/working with packages. -# We have disabled it for now since it depends on a live internet -# connection to run. This could be updated with a local Repo server if we had -# a package that is part of the Solr project to use. -@test "deploying and undeploying a cluster level package" { - skip "For developing package infra; requires a connection to github" - - run solr start -Dsolr.packages.enabled=true - - run solr package add-repo splainer "https://raw.githubusercontent.com/o19s/splainer/refs/heads/main/solr-splainer-package/repo/" - assert_output --partial "Added repository: splainer" - - run solr package list-available - assert_output --partial "solr-splainer Splainer for Solr" - run solr package install solr-splainer - assert_output --partial "solr-splainer installed." - - run solr package deploy solr-splainer -y --cluster - assert_output --partial "Deployment successful" - - run -0 curl --fail http://localhost:${SOLR_PORT}/v2/splainer/index.html -} diff --git a/solr/packaging/test/test_ssl.bats b/solr/packaging/test/test_ssl.bats index 5075ec763380..cf92d144d4f9 100644 --- a/solr/packaging/test/test_ssl.bats +++ b/solr/packaging/test/test_ssl.bats @@ -572,26 +572,26 @@ teardown() { # Replace server1 keystore with client's cp cert2.keystore.p12 server1.keystore.p12 ) - # Give some time for the server reload - sleep 6 + # Wait for Jetty keystore-reload scan to pick up the new certificate + wait_for 30 1 solr api --solr-url "https://localhost:${SOLR_PORT}/solr/admin/info/system" - run solr healthcheck --solr-url https://localhost:${SOLR_PORT} + run solr healthcheck -c test --solr-url https://localhost:${SOLR_PORT} # Server 2 still uses the cert1, so this request should fail run ! solr api --solr-url "https://localhost:${SOLR2_PORT}/solr/test/select?q=query2" - run ! solr healthcheck --solr-url https://localhost:${SOLR2_PORT} + run ! solr healthcheck -c test --solr-url https://localhost:${SOLR2_PORT} ( cd "$ssl_dir" # Replace server2 keystore with client's cp cert2.keystore.p12 server2.keystore.p12 ) - # Give some time for the server reload - sleep 6 + # Wait for Jetty keystore-reload scan to pick up the new certificate + wait_for 30 1 solr api --solr-url "https://localhost:${SOLR2_PORT}/solr/admin/info/system" - run solr healthcheck --solr-url https://localhost:${SOLR_PORT} - run solr healthcheck --solr-url https://localhost:${SOLR2_PORT} + run solr healthcheck -c test --solr-url https://localhost:${SOLR_PORT} + run solr healthcheck -c test --solr-url https://localhost:${SOLR2_PORT} run solr api --solr-url "https://localhost:${SOLR_PORT}/solr/test/select?q=query3" assert_output --partial '"numFound":0' diff --git a/solr/packaging/test/test_start_solr.bats b/solr/packaging/test/test_start_solr.bats index a24ceadd24c5..d136413c882b 100644 --- a/solr/packaging/test/test_start_solr.bats +++ b/solr/packaging/test/test_start_solr.bats @@ -25,7 +25,7 @@ teardown() { # save a snapshot of SOLR_HOME for failed tests save_home_on_failure - solr stop --all >/dev/null 2>&1 + SOLR_STOP_WAIT=30 solr stop --all >/dev/null 2>&1 } @test "SOLR-11740 check 'solr stop' connection" { diff --git a/solr/packaging/test/test_status.bats b/solr/packaging/test/test_status.bats index 5399a0b9fd6c..22589b35a1f7 100644 --- a/solr/packaging/test/test_status.bats +++ b/solr/packaging/test/test_status.bats @@ -17,40 +17,38 @@ load bats_helper -setup() { +setup_file() { common_clean_setup + solr start +} + +teardown_file() { + common_setup + solr stop --all +} + +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 "status detects locally running solr" { - run solr status - assert_output --partial "No Solr nodes are running." - solr start run solr status assert_output --partial "running on port ${SOLR_PORT}" - solr stop - run solr status - assert_output --partial "No Solr nodes are running." } @test "status with --solr-url from user" { - solr start run solr status --solr-url http://localhost:${SOLR_PORT} assert_output --partial "\"solr_home\":" - solr stop } @test "status with --port from user" { - solr start run solr status --port ${SOLR_PORT} assert_output --partial "running on port ${SOLR_PORT}" - solr stop } @test "multiple connection options are prevented" { @@ -64,8 +62,6 @@ teardown() { } @test "status with --short format" { - solr start run solr status --port ${SOLR_PORT} --short assert_output --partial "http://localhost:${SOLR_PORT}/solr" - solr stop } diff --git a/solr/packaging/test/test_zk.bats b/solr/packaging/test/test_zk.bats index 11ee3a7a76d1..5f5fe6b1ad2f 100644 --- a/solr/packaging/test/test_zk.bats +++ b/solr/packaging/test/test_zk.bats @@ -59,13 +59,11 @@ teardown() { } @test "listing out files" { - sleep 1 run solr zk ls / -z localhost:${ZK_PORT} --recursive assert_output --partial "aliases.json" } @test "connecting to solr via various solr urls and zk hosts" { - sleep 1 run solr zk ls / --solr-url http://localhost:${SOLR_PORT} assert_output --partial "aliases.json" @@ -87,20 +85,17 @@ teardown() { run solr zk cp myfile.txt zk:/myfile.txt -z localhost:${ZK_PORT} assert_output --partial "Copying from 'myfile.txt' to 'zk:/myfile.txt'. ZooKeeper at localhost:${ZK_PORT}" - sleep 1 run solr zk ls / -z localhost:${ZK_PORT} assert_output --partial "myfile.txt" touch myfile2.txt run solr zk cp myfile2.txt zk:myfile2.txt -z localhost:${ZK_PORT} - sleep 1 run solr zk ls / -z localhost:${ZK_PORT} assert_output --partial "myfile2.txt" touch myfile3.txt run solr zk cp myfile3.txt zk:/myfile3.txt -z localhost:${ZK_PORT} assert_output --partial "Copying from 'myfile3.txt' to 'zk:/myfile3.txt'. ZooKeeper at localhost:${ZK_PORT}" - sleep 1 run solr zk ls / -z localhost:${ZK_PORT} assert_output --partial "myfile3.txt" @@ -122,7 +117,7 @@ teardown() { assert_output --partial "Uploading" refute_output --partial "ERROR" - sleep 1 + wait_for 10 1 bash -c "curl -s 'http://localhost:${SOLR_PORT}/api/configsets' | grep -q techproducts2" run curl "http://localhost:${SOLR_PORT}/api/configsets" assert_output --partial '"configSets":["_default","techproducts2"]' } @@ -169,8 +164,6 @@ teardown() { } @test "env var ZK_HOST is honored" { - sleep 1 - # Need to unset SOLR_PORT to avoid the tool being smart and look at SOLR_PORT export SOLR_PORT_KEEP=$SOLR_PORT_LISTEN unset SOLR_PORT_LISTEN