This is an automated email from the ASF dual-hosted git repository.
epugh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new 17c0dd1e32c Fix testcontainers assume swallowing legit test failures
(#4868)
17c0dd1e32c is described below
commit 17c0dd1e32c7f5f2f0ec52794cfa7d569f882cf5
Author: Eric Pugh <[email protected]>
AuthorDate: Thu Sep 3 10:48:55 2026 -0400
Fix testcontainers assume swallowing legit test failures (#4868)
---
.../ExtractingRequestHandlerTikaServerTest.java | 50 +++-----------
.../extraction/TikaServerContainerRule.java | 79 ++++++++++++++++++++++
.../TikaServerExtractionBackendTest.java | 54 +++------------
.../org/apache/solr/s3/AbstractS3ClientTest.java | 4 +-
.../org/apache/solr/s3/S3BackupRepositoryTest.java | 8 +--
.../apache/solr/s3/S3IncrementalBackupTest.java | 4 +-
.../org/apache/solr/s3/S3InstallShardTest.java | 4 +-
.../org/apache/solr/s3/S3MockContainerRule.java | 10 +--
.../org/apache/solr/s3/S3OutputStreamTest.java | 5 +-
9 files changed, 118 insertions(+), 100 deletions(-)
diff --git
a/solr/modules/extraction/src/test/org/apache/solr/handler/extraction/ExtractingRequestHandlerTikaServerTest.java
b/solr/modules/extraction/src/test/org/apache/solr/handler/extraction/ExtractingRequestHandlerTikaServerTest.java
index 23470049c98..f32dbb5289c 100644
---
a/solr/modules/extraction/src/test/org/apache/solr/handler/extraction/ExtractingRequestHandlerTikaServerTest.java
+++
b/solr/modules/extraction/src/test/org/apache/solr/handler/extraction/ExtractingRequestHandlerTikaServerTest.java
@@ -20,57 +20,27 @@ import
com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
import java.lang.invoke.MethodHandles;
import org.apache.lucene.tests.util.QuickPatchThreadsFilter;
import org.apache.solr.SolrIgnoredThreadsFilter;
-import org.junit.AfterClass;
-import org.junit.Assume;
import org.junit.BeforeClass;
+import org.junit.ClassRule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.testcontainers.containers.GenericContainer;
-import org.testcontainers.containers.wait.strategy.Wait;
@ThreadLeakFilters(filters = {SolrIgnoredThreadsFilter.class,
QuickPatchThreadsFilter.class})
public class ExtractingRequestHandlerTikaServerTest extends
ExtractingRequestHandlerTestAbstract {
private static final Logger log =
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- public static GenericContainer<?> tika;
+ @ClassRule
+ public static final TikaServerContainerRule tikaContainer = new
TikaServerContainerRule();
@BeforeClass
- @SuppressWarnings("resource")
- public static void beforeClassTika() {
- Assume.assumeFalse(
- "Skipping on s390x",
"s390x".equalsIgnoreCase(System.getProperty("os.arch")));
-
- String baseUrl;
- try {
- tika =
- new GenericContainer<>("apache/tika:3.2.3.0-full")
- .withExposedPorts(9998)
- .waitingFor(Wait.forListeningPort());
- tika.start();
- baseUrl = "http://" + tika.getHost() + ":" + tika.getMappedPort(9998);
- System.setProperty("solr.test.tikaserver.url", baseUrl);
- System.setProperty("solr.test.extraction.backend", "tikaserver");
- System.setProperty("solr.test.tikaserver.metadata.compatibility",
"true");
- log.info("Using extraction backend 'tikaserver'. Tika server running on
{}", baseUrl);
- initCore("solrconfig.xml", "schema.xml", getFile("extraction/solr"));
- } catch (Throwable t) {
- // Skip tests if Docker/Testcontainers are not available in the
environment
- Assume.assumeNoException("Docker/Testcontainers not available; skipping
test", t);
- }
- }
-
- @AfterClass
- public static void afterClassTika() {
- if (tika != null) {
- try {
- tika.stop();
- } catch (Throwable t) {
- // ignore
- } finally {
- tika = null;
- }
- }
+ public static void beforeClassTika() throws Exception {
+ String baseUrl = tikaContainer.getBaseUrl();
+ System.setProperty("solr.test.tikaserver.url", baseUrl);
+ System.setProperty("solr.test.extraction.backend", "tikaserver");
+ System.setProperty("solr.test.tikaserver.metadata.compatibility", "true");
+ log.info("Using extraction backend 'tikaserver'. Tika server running on
{}", baseUrl);
+ initCore("solrconfig.xml", "schema.xml", getFile("extraction/solr"));
}
@Test
diff --git
a/solr/modules/extraction/src/test/org/apache/solr/handler/extraction/TikaServerContainerRule.java
b/solr/modules/extraction/src/test/org/apache/solr/handler/extraction/TikaServerContainerRule.java
new file mode 100644
index 00000000000..7a6ae393799
--- /dev/null
+++
b/solr/modules/extraction/src/test/org/apache/solr/handler/extraction/TikaServerContainerRule.java
@@ -0,0 +1,79 @@
+/*
+ * 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.handler.extraction;
+
+import java.lang.invoke.MethodHandles;
+import org.junit.Assume;
+import org.junit.rules.ExternalResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.DockerClientFactory;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+
+/**
+ * JUnit rule that manages a single Apache Tika Server Testcontainer. Declare
as a
+ * {@code @ClassRule} so the (expensive to start) server is shared across all
{@code @Test} methods
+ * in a class instead of being restarted for each one; JUnit starts it before,
and stops it after,
+ * the whole class runs.
+ *
+ * <p>Skips the calling test (via {@link Assume}) instead of failing outright
if
+ * Docker/Testcontainers isn't available in this environment.
+ */
+public class TikaServerContainerRule extends ExternalResource {
+
+ private static final Logger log =
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ public static final String TIKA_DOCKER_IMAGE = "apache/tika:3.2.3.0-full";
+
+ private GenericContainer<?> tika;
+ private String baseUrl;
+
+ @Override
+ @SuppressWarnings("resource")
+ protected void before() {
+ Assume.assumeFalse(
+ "Skipping on s390x",
"s390x".equalsIgnoreCase(System.getProperty("os.arch")));
+ Assume.assumeTrue(
+ "Docker/Testcontainers not available; skipping test",
+ DockerClientFactory.instance().isDockerAvailable());
+
+ tika =
+ new GenericContainer<>(TIKA_DOCKER_IMAGE)
+ .withExposedPorts(9998)
+ .waitingFor(Wait.forListeningPort());
+ tika.start();
+ baseUrl = "http://" + tika.getHost() + ":" + tika.getMappedPort(9998);
+ }
+
+ @Override
+ protected void after() {
+ if (tika != null) {
+ try {
+ tika.stop();
+ } catch (Exception e) {
+ log.error("Exception stopping Tika container", e);
+ } finally {
+ tika = null;
+ }
+ }
+ }
+
+ public String getBaseUrl() {
+ return baseUrl;
+ }
+}
diff --git
a/solr/modules/extraction/src/test/org/apache/solr/handler/extraction/TikaServerExtractionBackendTest.java
b/solr/modules/extraction/src/test/org/apache/solr/handler/extraction/TikaServerExtractionBackendTest.java
index b7723da94ff..326ab818596 100644
---
a/solr/modules/extraction/src/test/org/apache/solr/handler/extraction/TikaServerExtractionBackendTest.java
+++
b/solr/modules/extraction/src/test/org/apache/solr/handler/extraction/TikaServerExtractionBackendTest.java
@@ -29,11 +29,8 @@ import org.apache.solr.SolrIgnoredThreadsFilter;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrException;
import org.apache.solr.handler.extraction.fromtika.ToXMLContentHandler;
-import org.junit.AfterClass;
-import org.junit.Assume;
-import org.junit.BeforeClass;
+import org.junit.ClassRule;
import org.junit.Test;
-import org.testcontainers.containers.GenericContainer;
/**
* Integration tests for TikaServerExtractionBackend using a real Tika Server
via Testcontainers.
@@ -60,35 +57,8 @@ public class TikaServerExtractionBackendTest extends
SolrTestCaseJ4 {
}
}
- private static GenericContainer<?> tika;
- private static String baseUrl;
-
- @SuppressWarnings("resource")
- @BeforeClass
- public static void startTikaServer() {
- Assume.assumeFalse(
- "Skipping on s390x",
"s390x".equalsIgnoreCase(System.getProperty("os.arch")));
-
- try {
- tika = new
GenericContainer<>("apache/tika:3.2.3.0-full").withExposedPorts(9998);
- tika.start();
- baseUrl = "http://" + tika.getHost() + ":" + tika.getMappedPort(9998);
- } catch (Throwable t) {
- // Skip tests if Docker/Testcontainers are not available in the
environment
- Assume.assumeNoException("Docker/Testcontainers not available; skipping
TikaServer tests", t);
- }
- }
-
- @AfterClass
- public static void stopTikaServer() {
- if (tika != null) {
- try {
- tika.stop();
- } catch (Throwable ignore) {
- }
- tika = null;
- }
- }
+ @ClassRule
+ public static final TikaServerContainerRule tikaContainer = new
TikaServerContainerRule();
private static ExtractionRequest newRequest(
String resourceName,
@@ -109,8 +79,8 @@ public class TikaServerExtractionBackendTest extends
SolrTestCaseJ4 {
@Test
public void testExtractTextAndMetadata() throws Exception {
- Assume.assumeTrue("Tika server container not started", tika != null);
- try (TikaServerExtractionBackend backend = new
TikaServerExtractionBackend(baseUrl)) {
+ try (TikaServerExtractionBackend backend =
+ new TikaServerExtractionBackend(tikaContainer.getBaseUrl())) {
byte[] data = "Hello TestContainers".getBytes(StandardCharsets.UTF_8);
try (ByteArrayInputStream in = new ByteArrayInputStream(data)) {
ExtractionResult res = backend.extract(in, newRequest("test.txt",
"text/plain", "text"));
@@ -129,8 +99,8 @@ public class TikaServerExtractionBackendTest extends
SolrTestCaseJ4 {
@Test
public void testExtractWithSaxHandlerXml() throws Exception {
- Assume.assumeTrue("Tika server container not started", tika != null);
- try (TikaServerExtractionBackend backend = new
TikaServerExtractionBackend(baseUrl)) {
+ try (TikaServerExtractionBackend backend =
+ new TikaServerExtractionBackend(tikaContainer.getBaseUrl())) {
byte[] data = "Hello XML".getBytes(StandardCharsets.UTF_8);
ExtractionRequest request = newRequest("test.txt", "text/plain", "xml");
try (ByteArrayInputStream in = new ByteArrayInputStream(data)) {
@@ -151,8 +121,8 @@ public class TikaServerExtractionBackendTest extends
SolrTestCaseJ4 {
@Test
public void testPdfWithImageRecursive() throws Exception {
- Assume.assumeTrue("Tika server container not started", tika != null);
- try (TikaServerExtractionBackend backend = new
TikaServerExtractionBackend(baseUrl)) {
+ try (TikaServerExtractionBackend backend =
+ new TikaServerExtractionBackend(tikaContainer.getBaseUrl())) {
byte[] data =
Files.readAllBytes(getFile("extraction/pdf-with-image.pdf"));
// Enable recursive extraction and set header to extract images from PDF
ExtractionRequest request =
@@ -182,11 +152,10 @@ public class TikaServerExtractionBackendTest extends
SolrTestCaseJ4 {
@Test
public void testMaxCharsLimitEnforced() throws Exception {
- Assume.assumeTrue("Tika server container not started", tika != null);
// Set a very small max chars limit and attempt to extract more than that
long maxChars = 10L;
try (TikaServerExtractionBackend backend =
- new TikaServerExtractionBackend(baseUrl, 180, null, maxChars)) {
+ new TikaServerExtractionBackend(tikaContainer.getBaseUrl(), 180, null,
maxChars)) {
byte[] data =
("This content is definitely longer than ten characters.")
.getBytes(StandardCharsets.UTF_8);
@@ -205,10 +174,9 @@ public class TikaServerExtractionBackendTest extends
SolrTestCaseJ4 {
@Test
public void testMaxCharsLimitEnforcedWithSaxHandler() throws Exception {
- Assume.assumeTrue("Tika server container not started", tika != null);
long maxChars = 10L;
try (TikaServerExtractionBackend backend =
- new TikaServerExtractionBackend(baseUrl, 180, null, maxChars)) {
+ new TikaServerExtractionBackend(tikaContainer.getBaseUrl(), 180, null,
maxChars)) {
byte[] data =
("This content is definitely longer than ten characters.")
.getBytes(StandardCharsets.UTF_8);
diff --git
a/solr/modules/s3-repository/src/test/org/apache/solr/s3/AbstractS3ClientTest.java
b/solr/modules/s3-repository/src/test/org/apache/solr/s3/AbstractS3ClientTest.java
index a68c16d0636..24bc0e1f3c5 100644
---
a/solr/modules/s3-repository/src/test/org/apache/solr/s3/AbstractS3ClientTest.java
+++
b/solr/modules/s3-repository/src/test/org/apache/solr/s3/AbstractS3ClientTest.java
@@ -44,7 +44,7 @@ public class AbstractS3ClientTest extends SolrTestCaseJ4 {
protected static final String BUCKET_NAME = "test-bucket";
@ClassRule
- public static final S3MockContainerRule S3_MOCK_RULE = new
S3MockContainerRule(BUCKET_NAME);
+ public static final S3MockContainerRule s3MockContainer = new
S3MockContainerRule(BUCKET_NAME);
S3StorageClient client;
private SocketProxy proxy;
@@ -58,7 +58,7 @@ public class AbstractS3ClientTest extends SolrTestCaseJ4 {
// We are using a proxy in front of S3Mock to be able to test connection
loss
proxy = new SocketProxy();
- proxy.open(URI.create(S3_MOCK_RULE.getHttpEndpoint()));
+ proxy.open(URI.create(s3MockContainer.getHttpEndpoint()));
client =
new S3StorageClient(
BUCKET_NAME,
diff --git
a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3BackupRepositoryTest.java
b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3BackupRepositoryTest.java
index e75f9bef733..5d4f6c3af54 100644
---
a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3BackupRepositoryTest.java
+++
b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3BackupRepositoryTest.java
@@ -63,7 +63,7 @@ public class S3BackupRepositoryTest extends
AbstractBackupRepositoryTest {
public Path temporaryFolder;
@ClassRule
- public static final S3MockContainerRule S3_MOCK_RULE = new
S3MockContainerRule(BUCKET_NAME);
+ public static final S3MockContainerRule s3MockContainer = new
S3MockContainerRule(BUCKET_NAME);
@Before
@Override
@@ -338,18 +338,18 @@ public class S3BackupRepositoryTest extends
AbstractBackupRepositoryTest {
NamedList<Object> args = new NamedList<>();
args.add(S3BackupRepositoryConfig.REGION, Region.US_EAST_1.id());
args.add(S3BackupRepositoryConfig.BUCKET_NAME, BUCKET_NAME);
- args.add(S3BackupRepositoryConfig.ENDPOINT,
S3_MOCK_RULE.getHttpEndpoint());
+ args.add(S3BackupRepositoryConfig.ENDPOINT,
s3MockContainer.getHttpEndpoint());
return args;
}
private void pushObject(String path, String content) {
- try (S3Client s3 = S3_MOCK_RULE.createS3ClientV2()) {
+ try (S3Client s3 = s3MockContainer.createS3ClientV2()) {
s3.putObject(b -> b.bucket(BUCKET_NAME).key(path),
RequestBody.fromString(content));
}
}
private Path pullObject(String path) throws IOException {
- try (S3Client s3 = S3_MOCK_RULE.createS3ClientV2()) {
+ try (S3Client s3 = s3MockContainer.createS3ClientV2()) {
Path file = Files.createTempFile(temporaryFolder, "junit", null);
InputStream input =
s3.getObject(
diff --git
a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3IncrementalBackupTest.java
b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3IncrementalBackupTest.java
index d2afd7e8119..f20d3f89cac 100644
---
a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3IncrementalBackupTest.java
+++
b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3IncrementalBackupTest.java
@@ -50,7 +50,7 @@ public class S3IncrementalBackupTest extends
AbstractIncrementalBackupTest {
private static final String BUCKET_NAME =
S3IncrementalBackupTest.class.getSimpleName();
@ClassRule
- public static final S3MockContainerRule S3_MOCK_RULE = new
S3MockContainerRule(BUCKET_NAME);
+ public static final S3MockContainerRule s3MockContainer = new
S3MockContainerRule(BUCKET_NAME);
public static final String SOLR_XML =
"<solr>\n"
@@ -134,7 +134,7 @@ public class S3IncrementalBackupTest extends
AbstractIncrementalBackupTest {
.replace("BAD_BUCKET", BUCKET_NAME)
.replace("BUCKET", BUCKET_NAME)
.replace("REGION", Region.US_EAST_1.id())
- .replace("ENDPOINT", S3_MOCK_RULE.getHttpEndpoint()))
+ .replace("ENDPOINT", s3MockContainer.getHttpEndpoint()))
.configure();
}
diff --git
a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3InstallShardTest.java
b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3InstallShardTest.java
index b239ae4b660..af6b77e031b 100644
---
a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3InstallShardTest.java
+++
b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3InstallShardTest.java
@@ -67,7 +67,7 @@ public class S3InstallShardTest extends
AbstractInstallShardTest {
AbstractInstallShardTest.defaultSolrXmlTextWithBackupRepository(BACKUP_REPOSITORY_XML);
@ClassRule
- public static final S3MockContainerRule S3_MOCK_RULE = new
S3MockContainerRule(BUCKET_NAME);
+ public static final S3MockContainerRule s3MockContainer = new
S3MockContainerRule(BUCKET_NAME);
@BeforeClass
public static void setupClass() throws Exception {
@@ -82,7 +82,7 @@ public class S3InstallShardTest extends
AbstractInstallShardTest {
SOLR_XML
.replace("BUCKET", BUCKET_NAME)
.replace("REGION", Region.US_EAST_1.id())
- .replace("ENDPOINT", S3_MOCK_RULE.getHttpEndpoint()))
+ .replace("ENDPOINT", s3MockContainer.getHttpEndpoint()))
.configure();
bootstrapBackupRepositoryData("/");
diff --git
a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3MockContainerRule.java
b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3MockContainerRule.java
index 48eb7a84021..216483e8edf 100644
---
a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3MockContainerRule.java
+++
b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3MockContainerRule.java
@@ -24,6 +24,7 @@ import org.junit.Assume;
import org.junit.rules.ExternalResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.testcontainers.DockerClientFactory;
import org.testcontainers.utility.DockerImageName;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
@@ -55,14 +56,13 @@ public class S3MockContainerRule extends ExternalResource {
@Override
protected void before() {
+ Assume.assumeTrue(
+ "Docker/Testcontainers not available; skipping test",
+ DockerClientFactory.instance().isDockerAvailable());
s3MockContainer =
new S3MockContainer(DockerImageName.parse(S3MOCK_DOCKER_IMAGE))
.withInitialBuckets(bucketName);
- try {
- s3MockContainer.start();
- } catch (Throwable t) {
- Assume.assumeNoException("Docker/Testcontainers not available; skipping
test", t);
- }
+ s3MockContainer.start();
}
@Override
diff --git
a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3OutputStreamTest.java
b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3OutputStreamTest.java
index f887c55cd0f..4df12150956 100644
---
a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3OutputStreamTest.java
+++
b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3OutputStreamTest.java
@@ -42,13 +42,14 @@ public class S3OutputStreamTest extends SolrTestCaseJ4 {
private static final String BUCKET =
S3OutputStreamTest.class.getSimpleName();
- @ClassRule public static final S3MockContainerRule S3_MOCK_RULE = new
S3MockContainerRule(BUCKET);
+ @ClassRule
+ public static final S3MockContainerRule s3MockContainer = new
S3MockContainerRule(BUCKET);
private S3Client s3;
@Before
public void setUpClient() {
- s3 = S3_MOCK_RULE.createS3ClientV2();
+ s3 = s3MockContainer.createS3ClientV2();
}
@After