This is an automated email from the ASF dual-hosted git repository.
reschke pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
The following commit(s) were added to refs/heads/trunk by this push:
new ae576b4646 OAK-10464: Use Testcontainers instead of
com.arakelian:docker-junit-rule (#1143)
ae576b4646 is described below
commit ae576b464625c48590108eeb8df9186b713aa234
Author: t-rana <[email protected]>
AuthorDate: Tue Oct 31 19:44:26 2023 +0530
OAK-10464: Use Testcontainers instead of com.arakelian:docker-junit-rule
(#1143)
* OAK-10464 testcontainers dependency
* OAK-10464 testcontainers dependency
* modified blob endpoint, logback, add testcontainer dependency
* migrate mongo docker rule to testcontainer
* minor dependency changes
* minor changes
* refactor dependency, removed unused ones
* revert logback changes
* revert logback changes
* removed test container dependency from child modules
* remove unused dependency
---------
Co-authored-by: smiroslav <[email protected]>
---
oak-blob-cloud-azure/pom.xml | 5 +-
.../cloud/azure/blobstorage/AzuriteDockerRule.java | 128 ++++++++++-----------
oak-it/pom.xml | 4 +-
oak-jcr/pom.xml | 4 +-
oak-lucene/pom.xml | 4 +-
oak-parent/pom.xml | 8 +-
oak-pojosr/pom.xml | 4 +-
oak-run-commons/pom.xml | 4 +-
oak-run/pom.xml | 4 +-
oak-segment-aws/pom.xml | 5 -
oak-segment-azure/pom.xml | 4 +-
oak-store-document/pom.xml | 5 -
.../plugins/document/MongoConnectionFactory.java | 2 +-
.../plugins/document/mongo/MongoDockerRule.java | 124 ++++++++++++--------
oak-upgrade/pom.xml | 8 +-
15 files changed, 161 insertions(+), 152 deletions(-)
diff --git a/oak-blob-cloud-azure/pom.xml b/oak-blob-cloud-azure/pom.xml
index b7430071a4..5da9251b3d 100644
--- a/oak-blob-cloud-azure/pom.xml
+++ b/oak-blob-cloud-azure/pom.xml
@@ -198,10 +198,9 @@
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
-
<dependency>
- <groupId>com.arakelian</groupId>
- <artifactId>docker-junit-rule</artifactId>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
diff --git
a/oak-blob-cloud-azure/src/test/java/org/apache/jackrabbit/oak/blob/cloud/azure/blobstorage/AzuriteDockerRule.java
b/oak-blob-cloud-azure/src/test/java/org/apache/jackrabbit/oak/blob/cloud/azure/blobstorage/AzuriteDockerRule.java
index f2693ebc05..3eaf27980a 100644
---
a/oak-blob-cloud-azure/src/test/java/org/apache/jackrabbit/oak/blob/cloud/azure/blobstorage/AzuriteDockerRule.java
+++
b/oak-blob-cloud-azure/src/test/java/org/apache/jackrabbit/oak/blob/cloud/azure/blobstorage/AzuriteDockerRule.java
@@ -16,55 +16,88 @@
*/
package org.apache.jackrabbit.oak.blob.cloud.azure.blobstorage;
-import com.arakelian.docker.junit.DockerRule;
-import com.arakelian.docker.junit.model.ImmutableDockerConfig;
import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
-import com.spotify.docker.client.DefaultDockerClient;
-import com.spotify.docker.client.auth.FixedRegistryAuthSupplier;
-import java.net.URISyntaxException;
-import java.security.InvalidKeyException;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.jetbrains.annotations.NotNull;
import org.junit.Assume;
-import org.junit.rules.TestRule;
+import org.junit.rules.ExternalResource;
import org.junit.runner.Description;
+import org.junit.runners.model.MultipleFailureException;
import org.junit.runners.model.Statement;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.utility.DockerImageName;
-public class AzuriteDockerRule implements TestRule {
+import java.net.URISyntaxException;
+import java.security.InvalidKeyException;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
- private static final String IMAGE =
"mcr.microsoft.com/azure-storage/azurite:3.19.0";
+public class AzuriteDockerRule extends ExternalResource {
+ private static final DockerImageName DOCKER_IMAGE_NAME =
DockerImageName.parse("mcr.microsoft.com/azure-storage/azurite:3.19.0");
public static final String ACCOUNT_KEY =
"Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
public static final String ACCOUNT_NAME = "devstoreaccount1";
+ private static final AtomicReference<Exception> STARTUP_EXCEPTION = new
AtomicReference<>();
- private static final String CONTAINER_SUFFIX =
UUID.randomUUID().toString().substring(0, 8);
+ private GenericContainer<?> azuriteContainer;
- private final DockerRule wrappedRule;
+ @Override
+ protected void before() throws Throwable {
+ azuriteContainer = new GenericContainer<>(DOCKER_IMAGE_NAME)
+ .withExposedPorts(10000)
+ .withEnv(Map.of("executable", "blob"))
+ .withStartupTimeout(Duration.ofSeconds(30));
- private static final AtomicReference<Exception> STARTUP_EXCEPTION = new
AtomicReference<>();
+ try {
+ azuriteContainer.start();
+ } catch (IllegalStateException e) {
+ STARTUP_EXCEPTION.set(e);
+ throw e;
+ }
+ }
- public AzuriteDockerRule() {
- wrappedRule = new DockerRule(ImmutableDockerConfig.builder()
- .image(IMAGE)
- .name("oak-test-azurite-" + CONTAINER_SUFFIX)
- .ports("10000")
- .addStartedListener(container -> {
+ @Override
+ protected void after() {
+ if (azuriteContainer != null) {
+ azuriteContainer.stop();
+ }
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
try {
- container.waitForPort("10000/tcp");
- container.waitForLog("Azurite Blob service is successfully
listening at http://0.0.0.0:10000");
+ before();
} catch (IllegalStateException e) {
- STARTUP_EXCEPTION.set(e);
+ Assume.assumeNoException(STARTUP_EXCEPTION.get());
throw e;
}
- })
- .addContainerConfigurer(builder -> builder.env("executable=blob"))
- .alwaysRemoveContainer(true)
- .build());
+
+ List<Throwable> errors = new ArrayList<Throwable>();
+ try {
+ base.evaluate();
+ } catch (Throwable t) {
+ errors.add(t);
+ } finally {
+ try {
+ after();
+ } catch (Throwable t) {
+ errors.add(t);
+ }
+ }
+ MultipleFailureException.assertEmpty(errors);
+ }
+ };
+ }
+
+ public String getBlobEndpoint() {
+ return "http://127.0.0.1:" + getMappedPort() + "/devstoreaccount1";
}
public CloudBlobContainer getContainer(String name) throws
URISyntaxException, StorageException, InvalidKeyException {
@@ -83,42 +116,7 @@ public class AzuriteDockerRule implements TestRule {
return CloudStorageAccount.parse("DefaultEndpointsProtocol=http;" +
";" + accountName + ";" + accountKey + ";" + blobEndpoint);
}
- @NotNull
- public String getBlobEndpoint() {
- int mappedPort = getMappedPort();
- return "http://127.0.0.1:" + mappedPort + "/devstoreaccount1";
- }
-
- @Override
- public Statement apply(Statement statement, Description description) {
- try {
- DefaultDockerClient client = DefaultDockerClient.fromEnv()
- .connectTimeoutMillis(5000L)
- .readTimeoutMillis(20000L)
- .registryAuthSupplier(new FixedRegistryAuthSupplier())
- .build();
- client.ping();
- client.pull(IMAGE);
- client.close();
- } catch (Throwable t) {
- Assume.assumeNoException(t);
- }
-
- Statement base = wrappedRule.apply(statement, description);
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- try {
- base.evaluate();
- } catch (Throwable e) {
- Assume.assumeNoException(STARTUP_EXCEPTION.get());
- throw e;
- }
- }
- };
- }
-
public int getMappedPort() {
- return
wrappedRule.getContainer().getPortBinding("10000/tcp").getPort();
+ return azuriteContainer.getMappedPort(10000);
}
}
diff --git a/oak-it/pom.xml b/oak-it/pom.xml
index 50ebf4a4f0..696e9b7576 100644
--- a/oak-it/pom.xml
+++ b/oak-it/pom.xml
@@ -258,8 +258,8 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>com.arakelian</groupId>
- <artifactId>docker-junit-rule</artifactId>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
diff --git a/oak-jcr/pom.xml b/oak-jcr/pom.xml
index 47d605cd7f..56f578ce82 100644
--- a/oak-jcr/pom.xml
+++ b/oak-jcr/pom.xml
@@ -526,8 +526,8 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>com.arakelian</groupId>
- <artifactId>docker-junit-rule</artifactId>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
diff --git a/oak-lucene/pom.xml b/oak-lucene/pom.xml
index a0686bf27d..f9f4c6c46d 100644
--- a/oak-lucene/pom.xml
+++ b/oak-lucene/pom.xml
@@ -450,8 +450,8 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>com.arakelian</groupId>
- <artifactId>docker-junit-rule</artifactId>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
diff --git a/oak-parent/pom.xml b/oak-parent/pom.xml
index 151391b263..8a9b6c7d43 100644
--- a/oak-parent/pom.xml
+++ b/oak-parent/pom.xml
@@ -704,10 +704,12 @@
<artifactId>httpmime</artifactId>
<version>4.5.14</version>
</dependency>
+ <!-- Testcontainers dependency -->
<dependency>
- <groupId>com.arakelian</groupId>
- <artifactId>docker-junit-rule</artifactId>
- <version>2.3.0</version>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
+ <version>${testcontainers.version}</version>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
diff --git a/oak-pojosr/pom.xml b/oak-pojosr/pom.xml
index 219910c98b..874bbfabcf 100644
--- a/oak-pojosr/pom.xml
+++ b/oak-pojosr/pom.xml
@@ -367,8 +367,8 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>com.arakelian</groupId>
- <artifactId>docker-junit-rule</artifactId>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
diff --git a/oak-run-commons/pom.xml b/oak-run-commons/pom.xml
index 8e477bcfb7..e4495a6b72 100644
--- a/oak-run-commons/pom.xml
+++ b/oak-run-commons/pom.xml
@@ -199,8 +199,8 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>com.arakelian</groupId>
- <artifactId>docker-junit-rule</artifactId>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
diff --git a/oak-run/pom.xml b/oak-run/pom.xml
index a82501e5a1..8f36fd848e 100644
--- a/oak-run/pom.xml
+++ b/oak-run/pom.xml
@@ -474,8 +474,8 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>com.arakelian</groupId>
- <artifactId>docker-junit-rule</artifactId>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
diff --git a/oak-segment-aws/pom.xml b/oak-segment-aws/pom.xml
index 9a4a2c5698..783294774e 100644
--- a/oak-segment-aws/pom.xml
+++ b/oak-segment-aws/pom.xml
@@ -257,11 +257,6 @@
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>com.arakelian</groupId>
- <artifactId>docker-junit-rule</artifactId>
- <scope>test</scope>
- </dependency>
<dependency>
<groupId>io.findify</groupId>
<artifactId>s3mock_2.12</artifactId>
diff --git a/oak-segment-azure/pom.xml b/oak-segment-azure/pom.xml
index 813c13791f..f150efe96b 100644
--- a/oak-segment-azure/pom.xml
+++ b/oak-segment-azure/pom.xml
@@ -208,8 +208,8 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>com.arakelian</groupId>
- <artifactId>docker-junit-rule</artifactId>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
diff --git a/oak-store-document/pom.xml b/oak-store-document/pom.xml
index 8a26e4dc83..6b0a37f921 100644
--- a/oak-store-document/pom.xml
+++ b/oak-store-document/pom.xml
@@ -331,11 +331,6 @@
<artifactId>metrics-core</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>com.arakelian</groupId>
- <artifactId>docker-junit-rule</artifactId>
- <scope>test</scope>
- </dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
diff --git
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoConnectionFactory.java
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoConnectionFactory.java
index 128df92c1a..ce07750d65 100644
---
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoConnectionFactory.java
+++
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoConnectionFactory.java
@@ -55,7 +55,7 @@ public class MongoConnectionFactory extends ExternalResource {
MongoConnection c = MongoUtils.getConnection(dbName);
if (c == null && MongoDockerRule.isDockerAvailable()) {
// fall back to docker if available
- c = new MongoConnection("localhost", mongo.getPort(), dbName);
+ c = new MongoConnection(mongo.getHost(), mongo.getPort(), dbName);
}
assumeNotNull(c);
if (c != null) {
diff --git
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDockerRule.java
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDockerRule.java
index 114755ccb6..c7d204b69d 100644
---
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDockerRule.java
+++
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDockerRule.java
@@ -16,95 +16,117 @@
*/
package org.apache.jackrabbit.oak.plugins.document.mongo;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicReference;
-
-import com.arakelian.docker.junit.DockerRule;
-import com.arakelian.docker.junit.model.ImmutableDockerConfig;
-import com.spotify.docker.client.DefaultDockerClient;
-import com.spotify.docker.client.auth.FixedRegistryAuthSupplier;
-
import org.junit.Assume;
-import org.junit.rules.TestRule;
+import org.junit.rules.ExternalResource;
import org.junit.runner.Description;
+import org.junit.runners.model.MultipleFailureException;
import org.junit.runners.model.Statement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.testcontainers.DockerClientFactory;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.images.RemoteDockerImage;
+import org.testcontainers.utility.DockerImageName;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
/**
- * A MongoDB {@link DockerRule}.
+ * A MongoDB {@link GenericContainer}.
*/
-public class MongoDockerRule implements TestRule {
+public class MongoDockerRule extends ExternalResource {
private static final Logger LOG =
LoggerFactory.getLogger(MongoDockerRule.class);
- private static final String CONFIG_NAME = "MongoDB-" +
UUID.randomUUID().toString().substring(0, 8);
-
private static final String VERSION = System.getProperty("mongo.version",
"3.6");
-
- private static final String IMAGE = "mongo:" + VERSION;
-
+ private static final String MONGO_IMAGE = "mongo:" + VERSION;
+ private static final AtomicReference<Exception> STARTUP_EXCEPTION = new
AtomicReference<>();
+ private static final int DEFAULT_MONGO_PORT = 27017;
+ private static final DockerImageName DOCKER_IMAGE_NAME =
DockerImageName.parse(MONGO_IMAGE);
private static final boolean DOCKER_AVAILABLE;
+ private static GenericContainer<?> mongoContainer;
static {
- boolean available = false;
- try (DefaultDockerClient client = DefaultDockerClient.fromEnv()
- .connectTimeoutMillis(5000L).readTimeoutMillis(20000L)
- .registryAuthSupplier(new FixedRegistryAuthSupplier())
- .build()) {
- client.ping();
- client.pull(IMAGE);
- available = true;
+
+ boolean dockerAvailable = false;
+ boolean imageAvailable = false;
+ try {
+ dockerAvailable = checkDockerAvailability();
+ if (dockerAvailable) {
+ imageAvailable = checkImageAvailability();
+ } else {
+ LOG.info("docker not available");
+ }
} catch (Throwable t) {
- LOG.info("Cannot connect to docker or pull image", t);
+ LOG.error("not able to pull specified mongo image: {}, error: ",
MONGO_IMAGE, t);
}
- DOCKER_AVAILABLE = available;
+ DOCKER_AVAILABLE = dockerAvailable && imageAvailable;
}
- private final DockerRule wrappedRule;
-
- private static final AtomicReference<Exception> STARTUP_EXCEPTION = new
AtomicReference<>();
-
- public MongoDockerRule() {
- wrappedRule = new DockerRule(ImmutableDockerConfig.builder()
- .name(CONFIG_NAME)
- .image(IMAGE)
- .ports("27017")
- .allowRunningBetweenUnitTests(true)
- .alwaysRemoveContainer(true)
- .addStartedListener(container -> {
- try {
- container.waitForPort("27017/tcp");
- } catch (IllegalStateException e) {
- STARTUP_EXCEPTION.set(e);
- throw e;
- }
- })
- .build());
+ @Override
+ protected void before() throws Throwable {
+ if (mongoContainer != null && mongoContainer.isRunning()) {
+ return;
+ }
+ mongoContainer = new GenericContainer<>(DOCKER_IMAGE_NAME)
+ .withExposedPorts(DEFAULT_MONGO_PORT)
+ .withStartupTimeout(Duration.ofMinutes(1));
+
+ try {
+ long startTime = Instant.now().toEpochMilli();
+ mongoContainer.start();
+ LOG.info("mongo container started in: " +
(Instant.now().toEpochMilli() - startTime) + " ms");
+ } catch (Exception e) {
+ LOG.error("error while starting mongoDb container, error: ", e);
+ STARTUP_EXCEPTION.set(e);
+ throw e;
+ }
}
@Override
- public Statement apply(Statement statement, Description description) {
- Statement base = wrappedRule.apply(statement, description);
+ public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
- base.evaluate();
+ before();
} catch (Throwable e) {
Assume.assumeNoException(STARTUP_EXCEPTION.get());
throw e;
}
+
+ List<Throwable> errors = new ArrayList<>();
+ try {
+ base.evaluate();
+ } catch (Throwable t) {
+ errors.add(t);
+ }
+ MultipleFailureException.assertEmpty(errors);
}
};
}
+ private static boolean checkImageAvailability() throws TimeoutException {
+ RemoteDockerImage remoteDockerImage = new
RemoteDockerImage(DOCKER_IMAGE_NAME);
+ remoteDockerImage.get(1, TimeUnit.MINUTES);
+ return true;
+ }
+
+ private static boolean checkDockerAvailability() {
+ return DockerClientFactory.instance().isDockerAvailable();
+ }
+
public int getPort() {
- return
wrappedRule.getContainer().getPortBinding("27017/tcp").getPort();
+ return mongoContainer.getMappedPort(DEFAULT_MONGO_PORT);
}
public String getHost() {
- return
wrappedRule.getContainer().getPortBinding("27017/tcp").getHost();
+ return mongoContainer.getHost();
}
public static boolean isDockerAvailable() {
diff --git a/oak-upgrade/pom.xml b/oak-upgrade/pom.xml
index 731232ba8b..3cc700ee85 100644
--- a/oak-upgrade/pom.xml
+++ b/oak-upgrade/pom.xml
@@ -220,11 +220,9 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
-
- <dependency>
- <groupId>com.arakelian</groupId>
- <artifactId>docker-junit-rule</artifactId>
- <version>2.1.0</version>
+ <dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>