diff --git a/.github/workflows/ubuntu-master.yml b/.github/workflows/ubuntu-master.yml
index f4dcf1f..45f9b4c 100644
--- a/.github/workflows/ubuntu-master.yml
+++ b/.github/workflows/ubuntu-master.yml
@@ -30,4 +30,5 @@ jobs:
env:
TARANTOOL_SERVER_USER: root
TARANTOOL_SERVER_GROUP: root
+ URI: ${{ secrets.URI }}
run: mvn -B verify --file pom.xml
diff --git a/pom.xml b/pom.xml
index ad5b812..0d736f8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -76,7 +76,7 @@
org.junit.jupiter
junit-jupiter
- 5.6.2
+ 5.7.0
test
@@ -91,6 +91,11 @@
1.2.3
test
+
+ com.github.docker-java
+ docker-java
+ 3.2.13
+
diff --git a/src/main/java/org/testcontainers/containers/TarantoolContainer.java b/src/main/java/org/testcontainers/containers/TarantoolContainer.java
index 85579bf..214f4ed 100644
--- a/src/main/java/org/testcontainers/containers/TarantoolContainer.java
+++ b/src/main/java/org/testcontainers/containers/TarantoolContainer.java
@@ -56,6 +56,11 @@ public TarantoolContainer(String dockerImageName) {
clientHelper = new TarantoolContainerClientHelper(this);
}
+ public TarantoolContainer(TarantoolImageParams tarantoolImageParams) {
+ super(TarantoolContainerImageHelper.getImage(tarantoolImageParams));
+ clientHelper = new TarantoolContainerClientHelper(this);
+ }
+
public TarantoolContainer(Future image) {
super(image);
clientHelper = new TarantoolContainerClientHelper(this);
diff --git a/src/main/java/org/testcontainers/containers/TarantoolContainerImageHelper.java b/src/main/java/org/testcontainers/containers/TarantoolContainerImageHelper.java
new file mode 100644
index 0000000..e6a4242
--- /dev/null
+++ b/src/main/java/org/testcontainers/containers/TarantoolContainerImageHelper.java
@@ -0,0 +1,82 @@
+package org.testcontainers.containers;
+
+import com.github.dockerjava.api.DockerClient;
+import com.github.dockerjava.api.command.BuildImageResultCallback;
+import com.github.dockerjava.api.model.Image;
+import com.github.dockerjava.core.DockerClientBuilder;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Class for working with docker directly
+ *
+ * @author Oleg Kuznetsov
+ */
+class TarantoolContainerImageHelper {
+
+ private static final DockerClient dockerClient = DockerClientBuilder.getInstance().build();
+
+ private TarantoolContainerImageHelper() {
+ }
+
+ /**
+ * Checks image for existing by name and build if it not exist
+ *
+ * @param imageParams parameters for building tarantool image
+ * @return image name
+ */
+ static String getImage(TarantoolImageParams imageParams) {
+ final String sdkVersion = imageParams.getSdkVersion();
+
+ if (StringUtils.isEmpty(sdkVersion)) {
+ throw new IllegalArgumentException("SDK version is null or empty!");
+ }
+
+ if (!hasImage(sdkVersion)) {
+ buildImage(imageParams);
+ }
+
+ return sdkVersion;
+ }
+
+ /**
+ * Builds image from parameters
+ *
+ * @param imageParams parameters for building tarantool image
+ */
+ private static void buildImage(TarantoolImageParams imageParams) {
+ final String sdkVersion = imageParams.getSdkVersion();
+ final String uri = System.getenv("URI");
+
+ if (StringUtils.isEmpty(uri)) {
+ throw new IllegalStateException("URI environment variable must be specified!");
+ }
+
+ dockerClient.buildImageCmd(imageParams.getDockerfile())
+ .withTags(new HashSet<>(Collections.singletonList(sdkVersion)))
+ .withBuildArg("SDK_VERSION", sdkVersion)
+ .withBuildArg("URI", uri)
+ .exec(new BuildImageResultCallback())
+ .awaitImageId();
+ }
+
+ /**
+ * Checks image for existing by name
+ *
+ * @param imageName image name for searching
+ * @return true if image exist and false if not
+ */
+ private static boolean hasImage(String imageName) {
+ final List images = dockerClient.listImagesCmd().exec();
+ return images.stream()
+ .map(Image::getRepoTags)
+ .map(Arrays::asList)
+ .flatMap(Collection::stream)
+ .anyMatch(tag -> tag.equals(imageName + ":latest"));
+ }
+}
diff --git a/src/main/java/org/testcontainers/containers/TarantoolImageParams.java b/src/main/java/org/testcontainers/containers/TarantoolImageParams.java
new file mode 100644
index 0000000..2c8de3f
--- /dev/null
+++ b/src/main/java/org/testcontainers/containers/TarantoolImageParams.java
@@ -0,0 +1,61 @@
+package org.testcontainers.containers;
+
+import java.io.File;
+import java.net.URISyntaxException;
+
+/**
+ * Tarantool image parameters holder
+ *
+ * @author Oleg Kuznetsov
+ */
+public class TarantoolImageParams {
+
+ private final String sdkVersion;
+ private final File dockerfile;
+
+ /**
+ * Basic constructor for tarantool image parameters
+ *
+ * @param sdkVersion version of tarantool sdk which will be downloaded from specified in env variables URI,
+ * for example: tarantool-enterprise-bundle-2.8.3-21-g7d35cd2be-r470
+ */
+ public TarantoolImageParams(String sdkVersion) {
+ this.sdkVersion = sdkVersion;
+ try {
+ this.dockerfile = new File(TarantoolImageParams.class.getClassLoader()
+ .getResource("sdk/Dockerfile").toURI());
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException("Can't access to Dockerfile for testcontainers");
+ }
+ }
+
+ /**
+ * Custom constructor for tarantool image parameters
+ *
+ * @param sdkVersion version of tarantool sdk which will be downloaded from specified in env variables URI,
+ * for example: tarantool-enterprise-bundle-2.8.3-21-g7d35cd2be-r470
+ * @param dockerfile dockerfile for building custom tarantool image
+ */
+ public TarantoolImageParams(String sdkVersion, File dockerfile) {
+ this.sdkVersion = sdkVersion;
+ this.dockerfile = dockerfile;
+ }
+
+ /**
+ * Getter for sdk version
+ *
+ * @return sdk version
+ */
+ public String getSdkVersion() {
+ return sdkVersion;
+ }
+
+ /**
+ * Getter for dockerfile
+ *
+ * @return dockerfile
+ */
+ public File getDockerfile() {
+ return dockerfile;
+ }
+}
diff --git a/src/main/resources/sdk/Dockerfile b/src/main/resources/sdk/Dockerfile
new file mode 100644
index 0000000..2db13a1
--- /dev/null
+++ b/src/main/resources/sdk/Dockerfile
@@ -0,0 +1,25 @@
+FROM centos:7
+
+ARG TARANTOOL_WORKDIR="/app"
+ARG TARANTOOL_RUNDIR="/tmp/run"
+ARG TARANTOOL_DATADIR="/tmp/data"
+ARG SDK_TGT_DIR="/sdk"
+ARG URI=""
+ARG SDK_VERSION=""
+ARG SDK_TGZ=$SDK_VERSION.tar.gz
+
+ENV URI=$URI
+ENV SDK_VERSION=$SDK_VERSION
+ENV SDK_TGT_DIR=$SDK_TGT_DIR
+ENV TARANTOOL_WORKDIR=$TARANTOOL_WORKDIR
+ENV TARANTOOL_RUNDIR=$TARANTOOL_RUNDIR
+ENV TARANTOOL_DATADIR=$TARANTOOL_DATADIR
+
+RUN curl https://curl.se/ca/cacert.pem -o /etc/pki/tls/certs/ca-bundle.crt && \
+ yum -y install wget && \
+ wget $URI/$SDK_TGZ && \
+ mkdir ./tmp_sdk && tar -xf $SDK_TGZ -C ./tmp_sdk && \
+ mv ./tmp_sdk/tarantool-enterprise $SDK_TGT_DIR && rm $SDK_TGZ && \
+ cp $SDK_TGT_DIR/tarantool /usr/bin/tarantool
+
+WORKDIR $TARANTOOL_WORKDIR
diff --git a/src/main/resources/server.lua b/src/main/resources/server.lua
index e921ee1..cc6580b 100644
--- a/src/main/resources/server.lua
+++ b/src/main/resources/server.lua
@@ -5,6 +5,6 @@ box.cfg {
log_level = 6,
}
-- API user will be able to login with this password
-box.schema.user.create('api_user', { password = 'secret' })
+box.schema.user.create('api_user', { password = 'secret', if_not_exists = true })
-- API user will be able to create spaces, add or remove data, execute functions
-box.schema.user.grant('api_user', 'read,write,execute', 'universe')
+box.schema.user.grant('api_user', 'read,write,execute', 'universe', nil, { if_not_exists = true })
diff --git a/src/test/java/org/testcontainers/containers/TarantoolCartridgeContainerReplicasetsTest.java b/src/test/java/org/testcontainers/containers/TarantoolCartridgeContainerReplicasetsTest.java
index aa03637..2efbb2c 100644
--- a/src/test/java/org/testcontainers/containers/TarantoolCartridgeContainerReplicasetsTest.java
+++ b/src/test/java/org/testcontainers/containers/TarantoolCartridgeContainerReplicasetsTest.java
@@ -3,7 +3,6 @@
import org.junit.jupiter.api.Test;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.output.Slf4jLogConsumer;
-import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.MountableFile;
import java.time.Duration;
@@ -36,7 +35,7 @@ public void test_ClusterContainer_StartsSuccessfully_ifFilesAreCopiedUnderRoot()
container.start();
CartridgeContainerTestUtils.executeProfileReplaceSmokeTest(container);
- if(container.isRunning())
+ if (container.isRunning())
container.stop();
}
}
diff --git a/src/test/java/org/testcontainers/containers/TarantoolCartridgeStaticContainerTest.java b/src/test/java/org/testcontainers/containers/TarantoolCartridgeStaticContainerTest.java
index 0049aad..090667a 100644
--- a/src/test/java/org/testcontainers/containers/TarantoolCartridgeStaticContainerTest.java
+++ b/src/test/java/org/testcontainers/containers/TarantoolCartridgeStaticContainerTest.java
@@ -26,7 +26,7 @@ public class TarantoolCartridgeStaticContainerTest {
LoggerFactory.getLogger(TarantoolCartridgeStaticContainerTest.class)));
@Test
- public void test_StaticClusterContainer_StartsSuccessfully_ifDirectoryBinndingIsUsed() throws Exception {
+ public void test_StaticClusterContainer_StartsSuccessfully_ifDirectoryBindingIsUsed() throws Exception {
CartridgeContainerTestUtils.executeProfileReplaceSmokeTest(container);
}
}
diff --git a/src/test/java/org/testcontainers/containers/TarantoolSdkContainerTest.java b/src/test/java/org/testcontainers/containers/TarantoolSdkContainerTest.java
new file mode 100644
index 0000000..ee5ee96
--- /dev/null
+++ b/src/test/java/org/testcontainers/containers/TarantoolSdkContainerTest.java
@@ -0,0 +1,67 @@
+package org.testcontainers.containers;
+
+
+import io.tarantool.driver.TarantoolVersion;
+import io.tarantool.driver.api.TarantoolClient;
+import io.tarantool.driver.api.TarantoolClientFactory;
+import io.tarantool.driver.api.TarantoolResult;
+import io.tarantool.driver.api.tuple.TarantoolTuple;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.util.List;
+
+/**
+ * @author Oleg Kuznetsov
+ */
+public class TarantoolSdkContainerTest {
+
+ @Test
+ void test_should_createTarantoolContainerFromSdk() {
+ try (final TarantoolContainer tarantoolContainer = new TarantoolContainer(
+ new TarantoolImageParams("tarantool-enterprise-bundle-2.8.3-21-g7d35cd2be-r470")
+ )) {
+ tarantoolContainer.start();
+
+ final TarantoolClient> client =
+ TarantoolClientFactory.createClient()
+ .withCredentials("api_user", "secret")
+ .withAddress(tarantoolContainer.getHost(), tarantoolContainer.getMappedPort(3301))
+ .build();
+
+ final List> result = client.eval("return 'test'").join();
+ final TarantoolVersion version = client.getVersion();
+
+ Assertions.assertEquals("test", result.get(0));
+ Assertions.assertTrue(version.toString().startsWith("Tarantool 2.8.3 (Binary)"));
+ }
+ }
+
+ @Test
+ void test_should_createTarantoolContainerFromSdk_ifDockerfileSpecified() throws URISyntaxException {
+ final File dockerfile = new File(
+ TarantoolSdkContainerTest.class.getClassLoader().getResource("testsdk/Dockerfile").toURI()
+ );
+
+ try (final TarantoolContainer tarantoolContainer = new TarantoolContainer(
+ new TarantoolImageParams("testsdk", dockerfile))
+ .withDirectoryBinding("testsdk")) {
+
+ tarantoolContainer.start();
+
+ final TarantoolClient> client =
+ TarantoolClientFactory.createClient()
+ .withCredentials("api_user", "secret")
+ .withAddress(tarantoolContainer.getHost(), tarantoolContainer.getMappedPort(3301))
+ .build();
+
+ final List> result = client.eval("return 'test'").join();
+ final TarantoolVersion version = client.getVersion();
+
+ Assertions.assertEquals("test", result.get(0));
+ Assertions.assertTrue(version.toString().startsWith("Tarantool 2.7.3 (Binary)"));
+ }
+ }
+}
diff --git a/src/test/java/org/testcontainers/containers/TarantoolStaticContainerTest.java b/src/test/java/org/testcontainers/containers/TarantoolStaticContainerTest.java
index 3ea9bd0..3cdd6c3 100644
--- a/src/test/java/org/testcontainers/containers/TarantoolStaticContainerTest.java
+++ b/src/test/java/org/testcontainers/containers/TarantoolStaticContainerTest.java
@@ -15,7 +15,7 @@
public class TarantoolStaticContainerTest {
@Container
- private static TarantoolContainer container = new TarantoolContainer();
+ private static final TarantoolContainer container = new TarantoolContainer();
@Test
public void testExecuteCommand() throws Exception {
diff --git a/src/test/resources/testsdk/Dockerfile b/src/test/resources/testsdk/Dockerfile
new file mode 100644
index 0000000..d1bf0b8
--- /dev/null
+++ b/src/test/resources/testsdk/Dockerfile
@@ -0,0 +1,24 @@
+FROM centos:7
+
+ARG TARANTOOL_WORKDIR="/app"
+ARG TARANTOOL_RUNDIR="/tmp/run"
+ARG TARANTOOL_DATADIR="/tmp/data"
+ARG SDK_TGT_DIR="/sdk"
+ARG URI=""
+ARG SDK_TGZ="tarantool-enterprise-bundle-2.7.3-0-gdddf926c3-r443.tar.gz"
+
+ENV URI=$URI
+ENV SDK_VERSION="tarantool-enterprise-bundle-2.7.3-0-gdddf926c3-r443"
+ENV SDK_TGT_DIR=$SDK_TGT_DIR
+ENV TARANTOOL_WORKDIR=$TARANTOOL_WORKDIR
+ENV TARANTOOL_RUNDIR=$TARANTOOL_RUNDIR
+ENV TARANTOOL_DATADIR=$TARANTOOL_DATADIR
+
+RUN curl https://curl.se/ca/cacert.pem -o /etc/pki/tls/certs/ca-bundle.crt && \
+ yum -y install wget && \
+ wget $URI/$SDK_TGZ && \
+ mkdir ./tmp_sdk && tar -xf $SDK_TGZ -C ./tmp_sdk && \
+ mv ./tmp_sdk/tarantool-enterprise $SDK_TGT_DIR && rm $SDK_TGZ && \
+ cp $SDK_TGT_DIR/tarantool /usr/bin/tarantool
+
+WORKDIR $TARANTOOL_WORKDIR
diff --git a/src/test/resources/testsdk/server.lua b/src/test/resources/testsdk/server.lua
new file mode 100644
index 0000000..cc6580b
--- /dev/null
+++ b/src/test/resources/testsdk/server.lua
@@ -0,0 +1,10 @@
+box.cfg {
+ listen = 3301,
+ memtx_memory = 128 * 1024 * 1024, -- 128 Mb
+ -- log = 'file:/tmp/tarantool.log',
+ log_level = 6,
+}
+-- API user will be able to login with this password
+box.schema.user.create('api_user', { password = 'secret', if_not_exists = true })
+-- API user will be able to create spaces, add or remove data, execute functions
+box.schema.user.grant('api_user', 'read,write,execute', 'universe', nil, { if_not_exists = true })