diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4b1b857..d878929 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,17 @@
## [Unreleased]
- Fix problem if topology isn't applied correctly
+- Bump testcontainers to 1.18.0
+- **[breaking change]** Update executeScript and executeCommand methods to execute code viva execInContainer
+ (now it returns yaml string in Container.ExecResult not CompletableFuture).
+- **[breaking change]** Remove TarantoolContainer containers with TarantoolClientBuilder parameter.
+- **[breaking change]** Remove getClient method from TarantoolContainerClientHelper.
+- **[breaking change]** Remove io.tarantool.cartridge-driver dependency.
+ because cartridge-java client was also removed.
+- Add executeScriptDecoded and executeCommandDecoded methods to return parsed yaml not string.
+- Add withSsl and withKeyAndCertFiles methods to TarantoolContainer and TarantoolCartridgeContainer.
+- Rewrite tests and add new cases to support new API.
+- Update org.yaml.snakeyaml to 2.0 version.
## [0.5.4] - 2023-03-31
- Use tarantool image as base instead of centos in cartridge container
diff --git a/README.md b/README.md
index e46151e..0294a4e 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ Add the Maven dependency:
io.tarantool
testcontainers-java-tarantool
- 0.5.4
+ 0.6.0
```
@@ -52,9 +52,9 @@ public class SomeTest {
@BeforeAll
public void setUp() {
// Run some setup commands
- container.executeCommand("return 1, 2").get();
+ container.executeCommand("return 1, 2");
// Or execute a script
- container.executeScript("org/testcontainers/containers/test.lua").get();
+ container.executeScript("org/testcontainers/containers/test.lua");
}
@Test
@@ -72,7 +72,7 @@ public class SomeTest {
...
// Execute some commands in Tarantool instance for verification
- List result = container.executeCommand("return 1, 2").get();
+ List result = container.executeCommand("return 1, 2");
...
}
...
@@ -181,7 +181,7 @@ public class SomeOtherTest {
// Use the created container in tests
public void testFoo() {
// Execute Lua commands in the router instance
- List result = container.executeCommand("return profile_get(...)", 1).get();
+ List result = container.executeCommand("return profile_get(1)");
// Instantiate a client connected to the router node
TarantoolCredentials credentials = new SimpleTarantoolCredentials(getRouterUsername(), getRouterPassword());
diff --git a/pom.xml b/pom.xml
index 43dff87..e896bea 100644
--- a/pom.xml
+++ b/pom.xml
@@ -53,7 +53,7 @@
- 1.17.4
+ 1.18.0
UTF-8
UTF-8
${project.basedir}/src/test/resources/logback-test.xml
@@ -81,20 +81,21 @@
testcontainers
${testcontainers.version}
-
- io.tarantool
- cartridge-driver
- 0.9.1
-
org.yaml
snakeyaml
- 1.33
+ 2.0
org.slf4j
slf4j-api
+
+ org.projectlombok
+ lombok
+ 1.18.28
+ provided
+
@@ -103,6 +104,12 @@
1.3.4
test
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.8.1
+ test
+
org.testcontainers
junit-jupiter
diff --git a/src/main/java/org/testcontainers/containers/SslContext.java b/src/main/java/org/testcontainers/containers/SslContext.java
new file mode 100644
index 0000000..1489811
--- /dev/null
+++ b/src/main/java/org/testcontainers/containers/SslContext.java
@@ -0,0 +1,32 @@
+package org.testcontainers.containers;
+
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.NonNull;
+import lombok.ToString;
+
+@Getter
+@NoArgsConstructor(staticName = "getSslContext")
+@AllArgsConstructor(staticName = "getSslContext")
+@ToString(includeFieldNames=true)
+@EqualsAndHashCode
+public class SslContext {
+ @NonNull
+ private String keyFile;
+ @NonNull
+ private String certFile;
+
+// public SslContext(@NonNull String keyFile, @NonNull String certFile) {
+// if (keyFile.isEmpty()) {
+// throw new RuntimeException("Parameter keyFile can not be empty String");
+// }
+// if (certFile.isEmpty()) {
+// throw new RuntimeException("Parameter certFile can not be empty String");
+// }
+//
+// this.keyFile = keyFile;
+// this.certFile = certFile;
+// }
+}
diff --git a/src/main/java/org/testcontainers/containers/TarantoolCartridgeContainer.java b/src/main/java/org/testcontainers/containers/TarantoolCartridgeContainer.java
index 2382ca3..42c3071 100644
--- a/src/main/java/org/testcontainers/containers/TarantoolCartridgeContainer.java
+++ b/src/main/java/org/testcontainers/containers/TarantoolCartridgeContainer.java
@@ -1,7 +1,6 @@
package org.testcontainers.containers;
import com.github.dockerjava.api.command.InspectContainerResponse;
-import io.tarantool.driver.exceptions.TarantoolConnectionException;
import org.testcontainers.containers.exceptions.CartridgeTopologyException;
import org.testcontainers.images.builder.ImageFromDockerfile;
@@ -12,7 +11,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.function.Supplier;
@@ -82,6 +80,9 @@
* specified in the http_port options, will be exposed.
*
* @author Alexey Kuzin
+ * @authorm Artyom Dubinin
+ * @author Ivan Dneprov
+ *
*/
public class TarantoolCartridgeContainer extends GenericContainer
implements TarantoolContainerOperations {
@@ -119,6 +120,7 @@ public class TarantoolCartridgeContainer extends GenericContainer buildArgs) {
super(withBuildArgs(image, buildArgs));
@@ -246,6 +263,19 @@ private static ImageFromDockerfile buildImage(String dockerFile, String buildIma
return new ImageFromDockerfile().withFileFromClasspath("Dockerfile", dockerFile);
}
+ /**
+ * Specify SSL as connection transport. And path to key and cert files inside your container for mTLS connection
+ * Warning! SSL must be set as default transport on your tarantool cluster.
+ * Supported only in Tarantool Enterprise
+ *
+ * @return this container instance
+ */
+ public TarantoolCartridgeContainer withSslContext(SslContext sslContext) {
+ checkNotRunning();
+ this.sslContext = sslContext;
+ return this;
+ }
+
/**
* Get the router host
*
@@ -328,6 +358,11 @@ public String getInstanceDir() {
return instanceDir;
}
+ @Override
+ public int getInternalPort() {
+ return routerPort;
+ }
+
/**
* Get Cartridge router HTTP API hostname
*
@@ -475,7 +510,7 @@ private boolean setupTopology() {
.substring(topologyConfigurationFile.lastIndexOf('/') + 1);
try {
- Container.ExecResult result = execInContainer("cartridge",
+ ExecResult result = execInContainer("cartridge",
"replicasets",
"--run-dir=" + TARANTOOL_RUN_DIR,
"--file=" + replicasetsFileName, "setup", "--bootstrap-vshard");
@@ -489,7 +524,7 @@ private boolean setupTopology() {
} else {
try {
- List> res = executeScript(topologyConfigurationFile).get();
+ List> res = executeScriptDecoded(topologyConfigurationFile);
if (res.size() >= 2 && res.get(1) != null && res.get(1) instanceof Map) {
HashMap, ?> error = ((HashMap, ?>) res.get(1));
// that means topology already exists
@@ -501,10 +536,6 @@ private boolean setupTopology() {
if (e.getCause() instanceof TimeoutException) {
return true;
// Do nothing, the cluster is reloading
- } else if (e.getCause() instanceof TarantoolConnectionException) {
- // Probably cluster is not ready
- logger().error("Failed to setup topology: {}", e.getMessage());
- return false;
}
} else {
throw new CartridgeTopologyException(e);
@@ -530,7 +561,7 @@ private void retryingSetupTopology() {
private void bootstrapVshard() {
try {
- executeCommand(VSHARD_BOOTSTRAP_COMMAND).get();
+ executeCommand(VSHARD_BOOTSTRAP_COMMAND);
} catch (Exception e) {
logger().error("Failed to bootstrap vshard cluster", e);
throw new RuntimeException(e);
@@ -580,8 +611,8 @@ private boolean routerIsUp() {
String healthyCmd = " local cartridge = package.loaded['cartridge']" +
" return assert(cartridge ~= nil)";
try {
- List> result = executeCommand(healthyCmd).get();
- return (Boolean) result.get(0);
+ ExecResult result = executeCommand(healthyCmd);
+ return result.getStdout().equals("---\n- true\n...\n\n");
} catch (Exception e) {
logger().warn("Error while waiting for router instance to be up: " + e.getMessage());
return false;
@@ -592,8 +623,8 @@ private boolean isCartridgeHealthy() {
String healthyCmd = " local cartridge = package.loaded['cartridge']" +
" return assert(cartridge) and assert(cartridge.is_healthy())";
try {
- List> result = executeCommand(healthyCmd).get();
- return (Boolean) result.get(0);
+ ExecResult result = executeCommand(healthyCmd);
+ return result.getStdout().equals("---\n- true\n...\n\n");
} catch (Exception e) {
logger().warn("Error while waiting for cartridge healthy state: " + e.getMessage());
return false;
@@ -601,12 +632,22 @@ private boolean isCartridgeHealthy() {
}
@Override
- public CompletableFuture> executeScript(String scriptResourcePath) throws Exception {
- return clientHelper.executeScript(scriptResourcePath);
+ public ExecResult executeScript(String scriptResourcePath) throws Exception {
+ return clientHelper.executeScript(scriptResourcePath, this.sslContext);
+ }
+
+ @Override
+ public T executeScriptDecoded(String scriptResourcePath) throws Exception {
+ return clientHelper.executeScriptDecoded(scriptResourcePath, this.sslContext);
+ }
+
+ @Override
+ public ExecResult executeCommand(String command) throws Exception {
+ return clientHelper.executeCommand(command, this.sslContext);
}
@Override
- public CompletableFuture> executeCommand(String command, Object... arguments) throws Exception {
- return clientHelper.executeCommand(command, arguments);
+ public T executeCommandDecoded(String command) throws Exception {
+ return clientHelper.executeCommandDecoded(command, this.sslContext);
}
}
diff --git a/src/main/java/org/testcontainers/containers/TarantoolContainer.java b/src/main/java/org/testcontainers/containers/TarantoolContainer.java
index 588d797..9936819 100644
--- a/src/main/java/org/testcontainers/containers/TarantoolContainer.java
+++ b/src/main/java/org/testcontainers/containers/TarantoolContainer.java
@@ -1,13 +1,10 @@
package org.testcontainers.containers;
import com.github.dockerjava.api.command.InspectContainerResponse;
-import io.tarantool.driver.api.TarantoolClientBuilder;
import org.testcontainers.containers.wait.strategy.Wait;
import java.net.URL;
import java.nio.file.Paths;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import static org.testcontainers.containers.PathUtils.normalizePath;
@@ -16,6 +13,7 @@
* Sets up a Tarantool instance and provides API for configuring it.
*
* @author Alexey Kuzin
+ * @author Ivan Dneprov
*/
public class TarantoolContainer extends GenericContainer
implements TarantoolContainerOperations {
@@ -45,6 +43,7 @@ public class TarantoolContainer extends GenericContainer
private String scriptFileName = SCRIPT_FILENAME;
private String instanceDir = INSTANCE_DIR;
private boolean useFixedPorts = false;
+ private SslContext sslContext;
private final TarantoolContainerClientHelper clientHelper;
@@ -55,15 +54,6 @@ public TarantoolContainer() {
this(String.format("%s:%s", TARANTOOL_IMAGE, DEFAULT_IMAGE_VERSION));
}
- /**
- * Constructor for {@link TarantoolContainer}
- *
- * @param clientBuilder client builder with custom client settings for setting up container
- */
- public TarantoolContainer(TarantoolClientBuilder clientBuilder) {
- this(String.format("%s:%s", TARANTOOL_IMAGE, DEFAULT_IMAGE_VERSION), clientBuilder);
- }
-
/**
* Constructor for {@link TarantoolContainer}
*
@@ -74,18 +64,6 @@ public TarantoolContainer(String dockerImageName) {
clientHelper = new TarantoolContainerClientHelper(this);
}
- /**
- * Constructor for {@link TarantoolContainer}
- *
- * @param dockerImageName docker image name for container creating
- * @param clientBuilder client builder with custom client settings for setting up container
- */
- public TarantoolContainer(String dockerImageName,
- TarantoolClientBuilder clientBuilder) {
- super(dockerImageName);
- clientHelper = new TarantoolContainerClientHelper(this, clientBuilder);
- }
-
/**
* Constructor for {@link TarantoolContainer}
*
@@ -96,18 +74,6 @@ public TarantoolContainer(TarantoolImageParams tarantoolImageParams) {
clientHelper = new TarantoolContainerClientHelper(this);
}
- /**
- * Constructor for {@link TarantoolContainer}
- *
- * @param tarantoolImageParams params for cached image creating
- * @param clientBuilder client builder with custom client settings for setting up container
- */
- public TarantoolContainer(TarantoolImageParams tarantoolImageParams,
- TarantoolClientBuilder clientBuilder) {
- super(TarantoolContainerImageHelper.getImage(tarantoolImageParams));
- clientHelper = new TarantoolContainerClientHelper(this, clientBuilder);
- }
-
/**
* Constructor for {@link TarantoolContainer}
*
@@ -118,18 +84,6 @@ public TarantoolContainer(Future image) {
clientHelper = new TarantoolContainerClientHelper(this);
}
- /**
- * Constructor for {@link TarantoolContainer}
- *
- * @param image future with image name
- * @param clientBuilder client builder with custom client settings for setting up container
- */
- public TarantoolContainer(Future image,
- TarantoolClientBuilder clientBuilder) {
- super(image);
- clientHelper = new TarantoolContainerClientHelper(this, clientBuilder);
- }
-
/**
* Use fixed ports binding.
* Defaults to false.
@@ -213,6 +167,20 @@ public TarantoolContainer withPassword(String password) {
return this;
}
+
+ /**
+ * Specify SSL as connection transport. And path to key and cert files inside your container for mTLS connection
+ * Warning! SSL must be set as default transport on your tarantool cluster.
+ * Supported only in Tarantool Enterprise
+ *
+ * @return this container instance
+ */
+ public TarantoolContainer withSslContext(SslContext sslContext) {
+ checkNotRunning();
+ this.sslContext = sslContext;
+ return this;
+ }
+
/**
* Change the log_level setting on the Tarantool instance
*
@@ -223,7 +191,7 @@ public TarantoolContainer withLogLevel(TarantoolLogLevel logLevel) {
this.logLevel = logLevel;
if (isRunning()) {
try {
- executeCommand(logLevel.toCommand()).get();
+ executeCommand(logLevel.toCommand());
} catch (Exception e) {
logger().error(String.format("Failed to set log_level to %s", logLevel.toString()), e);
throw new RuntimeException(e);
@@ -246,7 +214,7 @@ public TarantoolContainer withMemtxMemory(Integer memtxMemory) {
this.memtxMemory = memtxMemory;
if (isRunning()) {
try {
- executeCommand(String.format("box.cfg{memtx_memory=%d}", memtxMemory)).get();
+ executeCommand(String.format("box.cfg{memtx_memory=%d}", memtxMemory));
} catch (Exception e) {
logger().error(String.format("Failed to set memtx_memory to %d", memtxMemory), e);
throw new RuntimeException(e);
@@ -290,6 +258,11 @@ public String getInstanceDir() {
return instanceDir;
}
+ @Override
+ public int getInternalPort() {
+ return port;
+ }
+
/**
* Specify the server init script file name
*
@@ -380,12 +353,22 @@ protected void containerIsStopping(InspectContainerResponse containerInfo) {
}
@Override
- public CompletableFuture> executeScript(String scriptResourcePath) throws Exception {
- return clientHelper.executeScript(scriptResourcePath);
+ public Container.ExecResult executeScript(String scriptResourcePath) throws Exception {
+ return clientHelper.executeScript(scriptResourcePath, this.sslContext);
+ }
+
+ @Override
+ public T executeScriptDecoded(String scriptResourcePath) throws Exception {
+ return clientHelper.executeScriptDecoded(scriptResourcePath, this.sslContext);
+ }
+
+ @Override
+ public Container.ExecResult executeCommand(String command) throws Exception {
+ return clientHelper.executeCommand(command, this.sslContext);
}
@Override
- public CompletableFuture> executeCommand(String command, Object... arguments) throws Exception {
- return clientHelper.executeCommand(command, arguments);
+ public T executeCommandDecoded(String command) throws Exception {
+ return clientHelper.executeCommandDecoded(command, this.sslContext);
}
}
diff --git a/src/main/java/org/testcontainers/containers/TarantoolContainerClientHelper.java b/src/main/java/org/testcontainers/containers/TarantoolContainerClientHelper.java
index cfaa559..fecdcc0 100644
--- a/src/main/java/org/testcontainers/containers/TarantoolContainerClientHelper.java
+++ b/src/main/java/org/testcontainers/containers/TarantoolContainerClientHelper.java
@@ -1,18 +1,11 @@
package org.testcontainers.containers;
-import io.tarantool.driver.api.TarantoolClient;
-import io.tarantool.driver.api.TarantoolClientBuilder;
-import io.tarantool.driver.api.TarantoolClientFactory;
-import io.tarantool.driver.api.TarantoolResult;
-import io.tarantool.driver.api.retry.TarantoolRequestRetryPolicies;
-import io.tarantool.driver.api.tuple.TarantoolTuple;
import org.testcontainers.utility.MountableFile;
+import org.yaml.snakeyaml.Yaml;
+import java.io.IOException;
import java.nio.file.Paths;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.ExecutionException;
import static org.testcontainers.containers.PathUtils.normalizePath;
@@ -20,69 +13,129 @@
* Provides a wrapper around a Tarantool client with helper methods
*
* @author Alexey Kuzin
+ * @author Artyom Dubinin
+ * @author Ivan Dneprov
*/
public final class TarantoolContainerClientHelper {
private static final String TMP_DIR = "/tmp";
+ private static final Yaml yaml = new Yaml();
private final TarantoolContainerOperations extends Container>> container;
- private final AtomicReference>> clientHolder =
- new AtomicReference<>();
- private final TarantoolClientBuilder clientBuilder;
+ private final String EXECUTE_SCRIPT_ERROR_TEMPLATE =
+ "Executed script %s with exit code %d, stderr: \"%s\", stdout: \"%s\"";
+ private static final String EXECUTE_COMMAND_ERROR_TEMPLATE =
+ "Executed command \"%s\" with exit code %d, stderr: \"%s\", stdout: \"%s\"";
+ private static final String MTLS_COMMAND_TEMPLATE =
+ "echo \" " +
+ " print(require('yaml').encode( " +
+ " require('net.box').connect( " +
+ " { uri='%s:%d', params = { transport='ssl', ssl_key_file = '%s', ssl_cert_file = '%s' }}, " +
+ " { user = '%s', password = '%s' } " +
+ " ):eval('return %s')) " +
+ " ); " +
+ " os.exit(); " +
+ "\" | tarantool";
+ private static final String SSL_COMMAND_TEMPLATE =
+ "echo \" " +
+ " print(require('yaml').encode( " +
+ " require('net.box').connect( " +
+ " { uri='%s:%d', params = { transport='ssl' }}, " +
+ " { user = '%s', password = '%s' } " +
+ " ):eval('return %s')) " +
+ " ); " +
+ " os.exit(); " +
+ "\" | tarantool";
+ private static final String COMMAND_TEMPLATE = "echo \" " +
+ " print(require('yaml').encode( " +
+ " require('net.box').connect( " +
+ " { uri='%s:%d' }, " +
+ " { user = '%s', password = '%s' } " +
+ " ):eval('return %s')) " +
+ " ); " +
+ " os.exit(); " +
+ "\" | tarantool";
TarantoolContainerClientHelper(TarantoolContainerOperations extends Container>> container) {
this.container = container;
- this.clientBuilder = TarantoolClientFactory.createClient()
- .withRequestTimeout(5000)
- .withRetryingByNumberOfAttempts(15,
- TarantoolRequestRetryPolicies.retryNetworkErrors(),
- b -> b.withDelay(100));
}
+
+ public Container.ExecResult executeScript(String scriptResourcePath, SslContext sslContext) throws IOException, InterruptedException {
+ if (!container.isRunning()) {
+ throw new IllegalStateException("Cannot execute scripts in stopped container");
+ }
- TarantoolContainerClientHelper(TarantoolContainerOperations extends Container>> container,
- TarantoolClientBuilder clientBuilder) {
- this.container = container;
- this.clientBuilder = clientBuilder;
+ String scriptName = Paths.get(scriptResourcePath).getFileName().toString();
+ String containerPath = normalizePath(Paths.get(TMP_DIR, scriptName));
+ container.copyFileToContainer(MountableFile.forClasspathResource(scriptResourcePath), containerPath);
+ return executeCommand(String.format("return dofile('%s')", containerPath), sslContext);
}
- private TarantoolClient> createClient() {
- return clientBuilder
- .withCredentials(container.getUsername(), container.getPassword())
- .withAddress(container.getHost(), container.getPort())
- .build();
- }
+ public T executeScriptDecoded(String scriptResourcePath, SslContext sslContext) throws IOException, InterruptedException, ExecutionException {
+ Container.ExecResult result = executeScript(scriptResourcePath, sslContext);
- /**
- * Configure or return an already configured client connected to a Cartridge router
- *
- * @return a configured client
- */
- public TarantoolClient> getClient() {
- if (!container.isRunning()) {
- throw new IllegalStateException("Cannot connect to Tarantool instance in a stopped container");
- }
- if (clientHolder.get() == null) {
- clientHolder.compareAndSet(null, createClient());
+ if (result.getExitCode() != 0) {
+
+ if (result.getExitCode() == 3) {
+ throw new ExecutionException(String.format(EXECUTE_SCRIPT_ERROR_TEMPLATE,
+ scriptResourcePath, result.getExitCode(),
+ result.getStderr(), result.getStdout()),
+ new Throwable());
+ }
+
+ throw new IllegalStateException(String.format(EXECUTE_SCRIPT_ERROR_TEMPLATE,
+ scriptResourcePath, result.getExitCode(),
+ result.getStderr(), result.getStdout()));
}
- return clientHolder.get();
+
+ return yaml.load(result.getStdout());
}
- public CompletableFuture> executeScript(String scriptResourcePath) {
+ public Container.ExecResult executeCommand(String command, SslContext sslContext) throws IOException, InterruptedException {
if (!container.isRunning()) {
- throw new IllegalStateException("Cannot execute scripts in stopped container");
+ throw new IllegalStateException("Cannot execute commands in stopped container");
}
- String scriptName = Paths.get(scriptResourcePath).getFileName().toString();
- String containerPath = normalizePath(Paths.get(TMP_DIR, scriptName));
- container.copyFileToContainer(MountableFile.forClasspathResource(scriptResourcePath), containerPath);
- return executeCommand(String.format("return dofile('%s')", containerPath));
+ command = command.replace("\"", "\\\"");
+ command = command.replace("\'", "\\\'");
+
+ String bashCommand;
+ // No SSL
+ if (sslContext == null) {
+ bashCommand = String.format(COMMAND_TEMPLATE,
+ container.getHost(), container.getInternalPort(),
+ container.getUsername(), container.getPassword(),
+ command
+ );
+ // mTLS
+ } else if (sslContext.getKeyFile() != null && sslContext.getCertFile() != null) {
+ bashCommand = String.format(MTLS_COMMAND_TEMPLATE,
+ container.getHost(), container.getInternalPort(),
+ sslContext.getKeyFile(), sslContext.getCertFile(),
+ container.getUsername(), container.getPassword(),
+ command
+ );
+ // SSL
+ } else {
+ bashCommand = String.format(SSL_COMMAND_TEMPLATE,
+ container.getHost(), container.getInternalPort(),
+ container.getUsername(), container.getPassword(),
+ command
+ );
+ }
+
+ return container.execInContainer("sh", "-c", bashCommand);
}
- public CompletableFuture> executeCommand(String command, Object... arguments) {
- if (!container.isRunning()) {
- throw new IllegalStateException("Cannot execute commands in stopped container");
+ public T executeCommandDecoded(String command, SslContext sslContext) throws IOException, InterruptedException {
+ Container.ExecResult result = executeCommand(command, sslContext);
+
+ if (result.getExitCode() != 0) {
+ throw new IllegalStateException(String.format(EXECUTE_COMMAND_ERROR_TEMPLATE,
+ command, result.getExitCode(), result.getStderr(), result.getStdout()));
}
- return getClient().eval(command, Arrays.asList(arguments));
+ return yaml.load(result.getStdout());
}
+
}
diff --git a/src/main/java/org/testcontainers/containers/TarantoolContainerOperations.java b/src/main/java/org/testcontainers/containers/TarantoolContainerOperations.java
index 68c847a..042e562 100644
--- a/src/main/java/org/testcontainers/containers/TarantoolContainerOperations.java
+++ b/src/main/java/org/testcontainers/containers/TarantoolContainerOperations.java
@@ -7,6 +7,7 @@
* Represents operations available on a Tarantool Container
*
* @author Alexey Kuzin
+ * @author Ivan Dneprov
*/
public interface TarantoolContainerOperations> extends Container {
/**
@@ -44,6 +45,13 @@ public interface TarantoolContainerOperations> extends Co
*/
String getInstanceDir();
+ /**
+ * Get the Tarantool server internal port for connecting the client to
+ *
+ * @return a port
+ */
+ int getInternalPort();
+
/**
* Execute a local script in the Tarantool instance. The path must be classpath-relative.
* `dofile()` function is executed internally, so possible exceptions will be caught as the client exceptions.
@@ -52,15 +60,33 @@ public interface TarantoolContainerOperations> extends Co
* @return script execution result
* @throws Exception if failed to connect to the instance or execution fails
*/
- CompletableFuture> executeScript(String scriptResourcePath) throws Exception;
+ Container.ExecResult executeScript(String scriptResourcePath) throws Exception;
+
+ /**
+ * Execute a local script in the Tarantool instance. The path must be classpath-relative.
+ * `dofile()` function is executed internally, so possible exceptions will be caught as the client exceptions.
+ *
+ * @param scriptResourcePath the classpath resource path to a script
+ * @return script execution result in {@link Container.ExecResult}
+ * @throws Exception if failed to connect to the instance or execution fails
+ */
+ T executeScriptDecoded(String scriptResourcePath) throws Exception;
/**
* Execute a command in the Tarantool instance. Example of a command: `return 1 + 2, 'foo'`
*
* @param command a valid Lua command or a sequence of Lua commands
- * @param arguments command arguments
* @return command execution result
* @throws Exception if failed to connect to the instance or execution fails
*/
- CompletableFuture> executeCommand(String command, Object... arguments) throws Exception;
+ Container.ExecResult executeCommand(String command) throws Exception;
+
+ /**
+ * Execute a command in the Tarantool instance. Example of a command: `return 1 + 2, 'foo'`
+ *
+ * @param command a valid Lua command or a sequence of Lua commands
+ * @return command execution result in {@link Container.ExecResult}
+ * @throws Exception if failed to connect to the instance or execution fails
+ */
+ T executeCommandDecoded(String command) throws Exception;
}
diff --git a/src/test/java/org/testcontainers/containers/CartridgeContainerTestUtils.java b/src/test/java/org/testcontainers/containers/CartridgeContainerTestUtils.java
index 8a15cf9..4806c6b 100644
--- a/src/test/java/org/testcontainers/containers/CartridgeContainerTestUtils.java
+++ b/src/test/java/org/testcontainers/containers/CartridgeContainerTestUtils.java
@@ -1,12 +1,12 @@
package org.testcontainers.containers;
-import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author Vladimir Rogach
+ * @author Ivan Dneprov
*/
public class CartridgeContainerTestUtils {
@@ -15,9 +15,9 @@ private CartridgeContainerTestUtils() {
static public void executeProfileReplaceSmokeTest(TarantoolCartridgeContainer container) throws Exception {
container.executeCommand(
- "return profile_replace(...)", Arrays.asList(1, "Ivanov Ivan Ivanovich", 33, 100500)).get();
+ "return profile_replace({1, \"Ivanov Ivan Ivanovich\", 33, 100500})");
- List> result = container.executeCommand("return profile_get(...)", 1).get();
+ List> result = container.executeCommandDecoded("return profile_get(1)");
assertEquals(1, result.size());
assertEquals(33, ((List>) result.get(0)).get(3));
}
diff --git a/src/test/java/org/testcontainers/containers/Enterprise/TarantoolCartridgeMtlsContainerTestEnterprise.java b/src/test/java/org/testcontainers/containers/Enterprise/TarantoolCartridgeMtlsContainerTestEnterprise.java
new file mode 100644
index 0000000..b6731d4
--- /dev/null
+++ b/src/test/java/org/testcontainers/containers/Enterprise/TarantoolCartridgeMtlsContainerTestEnterprise.java
@@ -0,0 +1,66 @@
+package org.testcontainers.containers.Enterprise;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.CartridgeContainerTestUtils;
+import org.testcontainers.containers.TarantoolCartridgeContainer;
+import org.testcontainers.containers.TarantoolImageParams;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.MountableFile;
+
+import java.io.File;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author Ivan Dneprov
+ */
+@Testcontainers
+public class TarantoolCartridgeMtlsContainerTestEnterprise {
+
+ private static TarantoolCartridgeContainer containerWithSsl;
+
+ @BeforeAll
+ public static void setUp() throws Exception {
+ final File dockerfile = new File(
+ TarantoolMTlsContainerTestEnterprise.class.getClassLoader()
+ .getResource("enterprise/ssl/mtls/Dockerfile").toURI()
+ );
+ final Map buildArgs = new HashMap<>();
+ buildArgs.put("DOWNLOAD_SDK_URI", System.getenv("DOWNLOAD_SDK_URI"));
+ buildArgs.put("SDK_VERSION", System.getenv("SDK_VERSION"));
+
+ containerWithSsl = new TarantoolCartridgeContainer(
+ new TarantoolImageParams("tarantool-enterprise", dockerfile, buildArgs),
+ "cartridge/instances.yml", "cartridge/replicasets.yml")
+ .withCopyFileToContainer(MountableFile.forClasspathResource("cartridge"), "/app")
+ .withCopyFileToContainer(MountableFile.forClasspathResource("enterprise/ssl"), "/app")
+ .withStartupTimeout(Duration.ofSeconds(300))
+ .withLogConsumer(new Slf4jLogConsumer(
+ LoggerFactory.getLogger(TarantoolCartridgeMtlsContainerTestEnterprise.class)));
+
+ if (!containerWithSsl.isRunning()) {
+ containerWithSsl.start();
+ }
+ }
+
+ @Test
+ public void test_clientWithSsl_shouldWork() throws Exception {
+ HashMap result = containerWithSsl.executeCommandDecoded("box.cfg.listen");
+ HashMap params = (HashMap) result.get("params");
+ assertEquals("ssl", params.get("transport"));
+ assertEquals("server.key", params.get("ssl_key_file"));
+ assertEquals("server.crt", params.get("ssl_cert_file"));
+ assertEquals("ca.crt", params.get("ssl_ca_file"));
+ }
+
+ @Test
+ public void test_StaticClusterContainer_StartsSuccessfully_ifFilesAreCopied() throws Exception {
+ CartridgeContainerTestUtils.executeProfileReplaceSmokeTest(containerWithSsl);
+ }
+}
diff --git a/src/test/java/org/testcontainers/containers/Enterprise/TarantoolMTlsContainerTestEnterprise.java b/src/test/java/org/testcontainers/containers/Enterprise/TarantoolMTlsContainerTestEnterprise.java
new file mode 100644
index 0000000..712a101
--- /dev/null
+++ b/src/test/java/org/testcontainers/containers/Enterprise/TarantoolMTlsContainerTestEnterprise.java
@@ -0,0 +1,61 @@
+package org.testcontainers.containers.Enterprise;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.SslContext;
+import org.testcontainers.containers.TarantoolContainer;
+import org.testcontainers.containers.TarantoolImageParams;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author Ivan Dneprov
+ */
+public class TarantoolMTlsContainerTestEnterprise {
+
+ private static final Logger log = LoggerFactory.getLogger(TarantoolMTlsContainerTestEnterprise.class);
+
+ private static TarantoolContainer containerWithSsl;
+
+ @BeforeAll
+ public static void setUp() throws Exception {
+ final File dockerfile = new File(
+ TarantoolMTlsContainerTestEnterprise.class.getClassLoader()
+ .getResource("enterprise/Dockerfile").toURI()
+ );
+ final Map buildArgs = new HashMap<>();
+ buildArgs.put("DOWNLOAD_SDK_URI", System.getenv("DOWNLOAD_SDK_URI"));
+ buildArgs.put("SDK_VERSION", System.getenv("SDK_VERSION"));
+
+ containerWithSsl = new TarantoolContainer(
+ new TarantoolImageParams("tarantool-enterprise", dockerfile, buildArgs))
+ .withScriptFileName("mtls_server.lua")
+ .withUsername("test_user")
+ .withPassword("test_password")
+ .withMemtxMemory(256 * 1024 * 1024)
+ .withDirectoryBinding("enterprise/ssl/mtls")
+ .withSslContext(SslContext.getSslContext("/app/ca.key", "/app/ca.crt"))
+ .withLogConsumer(new Slf4jLogConsumer(log));
+
+ if (!containerWithSsl.isRunning()) {
+ containerWithSsl.start();
+ }
+ }
+
+ @Test
+ public void test_clientWithSsl_shouldWork() throws Exception {
+ HashMap result = containerWithSsl.executeCommandDecoded("box.cfg.listen");
+ HashMap params = (HashMap) result.get("params");
+ assertEquals("ssl", params.get("transport"));
+ assertEquals("server.key", params.get("ssl_key_file"));
+ assertEquals("server.crt", params.get("ssl_cert_file"));
+ assertEquals("ca.crt", params.get("ssl_ca_file"));
+ }
+}
diff --git a/src/test/java/org/testcontainers/containers/Enterprise/TarantoolSdkContainerTestEnterprise.java b/src/test/java/org/testcontainers/containers/Enterprise/TarantoolSdkContainerTestEnterprise.java
new file mode 100644
index 0000000..a3f18d8
--- /dev/null
+++ b/src/test/java/org/testcontainers/containers/Enterprise/TarantoolSdkContainerTestEnterprise.java
@@ -0,0 +1,41 @@
+package org.testcontainers.containers.Enterprise;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.testcontainers.containers.TarantoolContainer;
+import org.testcontainers.containers.TarantoolImageParams;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Oleg Kuznetsov
+ * @author Ivan Dneprov
+ */
+public class TarantoolSdkContainerTestEnterprise {
+
+
+ @Test
+ void test_should_createTarantoolContainerFromSdk() throws Exception {
+ final File dockerfile = new File(
+ TarantoolSdkContainerTestEnterprise.class.getClassLoader().getResource("testsdk/Dockerfile").toURI()
+ );
+ final Map buildArgs = new HashMap<>();
+ buildArgs.put("DOWNLOAD_SDK_URI", System.getenv("DOWNLOAD_SDK_URI"));
+ buildArgs.put("SDK_VERSION", "tarantool-enterprise-sdk-nogc64-2.10.6-0-r557.linux.x86_64");
+
+ try (final TarantoolContainer tarantoolContainer = new TarantoolContainer(
+ new TarantoolImageParams("tarantool-enterprise-bundle:latest", dockerfile, buildArgs))
+ .withDirectoryBinding("testsdk")) {
+
+ tarantoolContainer.start();
+
+ final String result = tarantoolContainer.executeCommandDecoded("'test'");
+ final String versionAnswer = tarantoolContainer.executeCommandDecoded("_TARANTOOL");
+
+ Assertions.assertEquals("test", result);
+ Assertions.assertEquals("2.10.6-0-g5d09e81a6-r557-nogc64", versionAnswer);
+ }
+ }
+}
diff --git a/src/test/java/org/testcontainers/containers/Enterprise/TarantoolSslContainerTestEnterprise.java b/src/test/java/org/testcontainers/containers/Enterprise/TarantoolSslContainerTestEnterprise.java
new file mode 100644
index 0000000..10f5ff1
--- /dev/null
+++ b/src/test/java/org/testcontainers/containers/Enterprise/TarantoolSslContainerTestEnterprise.java
@@ -0,0 +1,60 @@
+package org.testcontainers.containers.Enterprise;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.SslContext;
+import org.testcontainers.containers.TarantoolContainer;
+import org.testcontainers.containers.TarantoolImageParams;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author Ivan Dneprov
+ */
+public class TarantoolSslContainerTestEnterprise {
+
+ private static final Logger log = LoggerFactory.getLogger(TarantoolSslContainerTestEnterprise.class);
+
+ private static TarantoolContainer containerWithSsl;
+
+ @BeforeAll
+ public static void setUp() throws Exception {
+ final File dockerfile = new File(
+ TarantoolSslContainerTestEnterprise.class.getClassLoader()
+ .getResource("enterprise/Dockerfile").toURI()
+ );
+ final Map buildArgs = new HashMap<>();
+ buildArgs.put("DOWNLOAD_SDK_URI", System.getenv("DOWNLOAD_SDK_URI"));
+ buildArgs.put("SDK_VERSION", System.getenv("SDK_VERSION"));
+
+ containerWithSsl = new TarantoolContainer(
+ new TarantoolImageParams("tarantool-enterprise", dockerfile, buildArgs))
+ .withScriptFileName("ssl_server.lua")
+ .withUsername("test_user")
+ .withPassword("test_password")
+ .withMemtxMemory(256 * 1024 * 1024)
+ .withDirectoryBinding("enterprise/ssl")
+ .withSslContext(SslContext.getSslContext())
+ .withLogConsumer(new Slf4jLogConsumer(log));
+
+ if (!containerWithSsl.isRunning()) {
+ containerWithSsl.start();
+ }
+ }
+
+ @Test
+ public void test_clientWithSsl_shouldWork() throws Exception {
+ HashMap result = containerWithSsl.executeCommandDecoded("box.cfg.listen");
+ HashMap params = (HashMap) result.get("params");
+ assertEquals("ssl", params.get("transport"));
+ assertEquals("key.pem", params.get("ssl_key_file"));
+ assertEquals("certificate.crt", params.get("ssl_cert_file"));
+ }
+}
diff --git a/src/test/java/org/testcontainers/containers/PathUtilsTest.java b/src/test/java/org/testcontainers/containers/PathUtilsTest.java
index 4561575..dd926a6 100644
--- a/src/test/java/org/testcontainers/containers/PathUtilsTest.java
+++ b/src/test/java/org/testcontainers/containers/PathUtilsTest.java
@@ -1,8 +1,8 @@
package org.testcontainers.containers;
-import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
import static org.testcontainers.containers.PathUtils.normalizePath;
/**
@@ -14,24 +14,24 @@ class PathUtilsTest {
@Test
void normalizePathTest() {
- Assertions.assertEquals("c:/work/server.lua",
+ assertEquals("c:/work/server.lua",
normalizePath("c:/work/server.lua"));
- Assertions.assertEquals("c:/work/server.lua",
+ assertEquals("c:/work/server.lua",
normalizePath("/c:/work/server.lua"));
- Assertions.assertEquals("c:/work/server.lua",
+ assertEquals("c:/work/server.lua",
normalizePath("/c:\\work\\server.lua"));
- Assertions.assertEquals("c:/work/server.lua",
+ assertEquals("c:/work/server.lua",
normalizePath("c:\\work\\server.lua"));
- Assertions.assertEquals("c:/", normalizePath("c:\\"));
+ assertEquals("c:/", normalizePath("c:\\"));
- Assertions.assertEquals("/dummy", normalizePath("/dummy"));
+ assertEquals("/dummy", normalizePath("/dummy"));
- Assertions.assertEquals("/c", normalizePath("/c"));
+ assertEquals("/c", normalizePath("/c"));
- Assertions.assertThrows(NullPointerException.class, () -> normalizePath((String) null));
+ assertThrows(NullPointerException.class, () -> normalizePath((String) null));
}
}
diff --git a/src/test/java/org/testcontainers/containers/TarantoolCartridgeBootstrapFromLuaWithFixedPortsTest.java b/src/test/java/org/testcontainers/containers/TarantoolCartridgeBootstrapFromLuaWithFixedPortsTest.java
index 0a020b1..c292ba5 100644
--- a/src/test/java/org/testcontainers/containers/TarantoolCartridgeBootstrapFromLuaWithFixedPortsTest.java
+++ b/src/test/java/org/testcontainers/containers/TarantoolCartridgeBootstrapFromLuaWithFixedPortsTest.java
@@ -7,7 +7,6 @@
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
-import org.testcontainers.utility.MountableFile;
import java.time.Duration;
diff --git a/src/test/java/org/testcontainers/containers/TarantoolCartridgeBootstrapFromYamlTest.java b/src/test/java/org/testcontainers/containers/TarantoolCartridgeBootstrapFromYamlTest.java
index c13ceb6..4a0e7ce 100644
--- a/src/test/java/org/testcontainers/containers/TarantoolCartridgeBootstrapFromYamlTest.java
+++ b/src/test/java/org/testcontainers/containers/TarantoolCartridgeBootstrapFromYamlTest.java
@@ -1,18 +1,21 @@
package org.testcontainers.containers;
-import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.MountableFile;
+import org.testcontainers.containers.Container.ExecResult;
import java.time.Duration;
-import java.util.List;
+
+import static org.junit.Assert.assertEquals;
/**
* @author Alexey Kuzin
+ * @author Valdimir Rogach
+ * @author Ivan Dneprov
*/
@Testcontainers
public class TarantoolCartridgeBootstrapFromYamlTest {
@@ -36,7 +39,10 @@ public void test_StaticClusterContainer_StartsSuccessfully_ifFilesAreCopied() th
@Test
public void test_migrator_executesOk() throws Exception {
- List> result = container.executeCommand("return require('migrator').up()").get();
- Assertions.assertEquals("001_ddl.lua", ((List>)result.get(0)).get(0));
+ ExecResult result = container.executeCommand("return require('migrator').up()");
+ assertEquals("---\n" +
+ "- - 001_ddl.lua\n" +
+ "...\n" +
+ "\n", result.getStdout());
}
}
diff --git a/src/test/java/org/testcontainers/containers/TarantoolContainerTest.java b/src/test/java/org/testcontainers/containers/TarantoolContainerTest.java
index 8d18950..b2d68f3 100644
--- a/src/test/java/org/testcontainers/containers/TarantoolContainerTest.java
+++ b/src/test/java/org/testcontainers/containers/TarantoolContainerTest.java
@@ -1,13 +1,13 @@
package org.testcontainers.containers;
-import org.junit.jupiter.api.Test;
-
import java.util.List;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.Test;
+import static org.junit.Assert.assertEquals;
/**
* @author Alexey Kuzin
+ * @author Ivan Dneprov
*/
class TarantoolContainerTest {
@@ -15,9 +15,8 @@ class TarantoolContainerTest {
public void testExecuteScript() throws Exception {
try (TarantoolContainer container = new TarantoolContainer()) {
container.start();
-
- container.executeScript("org/testcontainers/containers/test.lua").get();
- List> result = container.executeCommand("return user_function_no_param()").get();
+ container.executeScript("org/testcontainers/containers/test.lua");
+ List> result = container.executeCommandDecoded("return user_function_no_param()");
assertEquals(1, result.size());
assertEquals(5, result.get(0));
}
@@ -35,17 +34,17 @@ public void testContainerWithParameters() throws Exception {
.withLogLevel(TarantoolLogLevel.INFO)) {
container.start();
- List> result = container.executeCommand("return box.cfg.memtx_memory").get();
+ List> result = container.executeCommandDecoded("return box.cfg.memtx_memory");
assertEquals(1, result.size());
assertEquals(memory, result.get(0));
- result = container.executeCommand("return box.cfg.log_level").get();
+ result = container.executeCommandDecoded("return box.cfg.log_level");
assertEquals(1, result.size());
assertEquals(5, result.get(0));
- result = container.executeCommand("return user_function_no_param()").get();
+ result = container.executeCommandDecoded("return user_function_no_param()");
assertEquals(result.size(), 1);
assertEquals(result.get(0), 5);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/org/testcontainers/containers/TarantoolSdkContainerTestEnterprise.java b/src/test/java/org/testcontainers/containers/TarantoolSdkContainerTestEnterprise.java
deleted file mode 100644
index 274e023..0000000
--- a/src/test/java/org/testcontainers/containers/TarantoolSdkContainerTestEnterprise.java
+++ /dev/null
@@ -1,51 +0,0 @@
-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.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Oleg Kuznetsov
- */
-public class TarantoolSdkContainerTestEnterprise {
-
- @Test
- void test_should_createTarantoolContainerFromSdk() throws URISyntaxException {
- final File dockerfile = new File(
- TarantoolSdkContainerTestEnterprise.class.getClassLoader().getResource("testsdk/Dockerfile").toURI()
- );
- final Map buildArgs = new HashMap<>();
- buildArgs.put("DOWNLOAD_SDK_URI", System.getenv("DOWNLOAD_SDK_URI"));
- buildArgs.put("SDK_VERSION", "tarantool-enterprise-bundle-2.7.3-0-gdddf926c3-r443");
-
- try (final TarantoolContainer tarantoolContainer = new TarantoolContainer(
- new TarantoolImageParams("tarantool-enterprise-bundle:latest", dockerfile, buildArgs))
- .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 3cdd6c3..7526c1a 100644
--- a/src/test/java/org/testcontainers/containers/TarantoolStaticContainerTest.java
+++ b/src/test/java/org/testcontainers/containers/TarantoolStaticContainerTest.java
@@ -6,10 +6,12 @@
import java.util.List;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.Assert.assertEquals;
/**
* @author Alexey Kuzin
+ * @author Oleg Kuznetsov
+ * @author Ivan Dneprov
*/
@Testcontainers
public class TarantoolStaticContainerTest {
@@ -19,17 +21,15 @@ public class TarantoolStaticContainerTest {
@Test
public void testExecuteCommand() throws Exception {
- List> result = container.executeCommand("return 1, 2").get();
+ List> result = container.executeCommandDecoded("return 1, 2");
assertEquals(2, result.size());
assertEquals(1, result.get(0));
}
@Test
public void testExecuteCommandWithArguments() throws Exception {
- List> result = container.executeCommand(
- "return require('fun').iter({...}):reduce(function(x, acc) return acc+x end, 0)",
- 1, 2, 3)
- .get();
+ List> result = container.executeCommandDecoded(
+ "return require('fun').iter({1, 2, 3}):reduce(function(x, acc) return acc+x end, 0)");
assertEquals(1, result.size());
assertEquals(6, result.get(0));
}
@@ -37,7 +37,7 @@ public void testExecuteCommandWithArguments() throws Exception {
@Test
public void testSetLogLevel() throws Exception {
container.withLogLevel(TarantoolLogLevel.INFO);
- List> result = container.executeCommand("return box.cfg.log_level").get();
+ List> result = container.executeCommandDecoded("return box.cfg.log_level");
assertEquals(1, result.size());
assertEquals(5, result.get(0));
}
@@ -46,7 +46,7 @@ public void testSetLogLevel() throws Exception {
public void testSetMemtxMemory() throws Exception {
int memory = 256 * 1024 * 1024;
container.withMemtxMemory(memory);
- List> result = container.executeCommand("return box.cfg.memtx_memory").get();
+ List> result = container.executeCommandDecoded("return box.cfg.memtx_memory");
assertEquals(1, result.size());
assertEquals(memory, result.get(0));
}
diff --git a/src/test/resources/enterprise/Dockerfile b/src/test/resources/enterprise/Dockerfile
new file mode 100644
index 0000000..f86d2b8
--- /dev/null
+++ b/src/test/resources/enterprise/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 DOWNLOAD_SDK_URI=""
+ARG SDK_VERSION=""
+ARG SDK_TGZ=$SDK_VERSION.tar.gz
+
+ENV DOWNLOAD_SDK_URI=$DOWNLOAD_SDK_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 $DOWNLOAD_SDK_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/enterprise/server.lua b/src/test/resources/enterprise/server.lua
new file mode 100755
index 0000000..dd8dd7f
--- /dev/null
+++ b/src/test/resources/enterprise/server.lua
@@ -0,0 +1,4 @@
+box.cfg { listen = 3301 }
+
+box.schema.user.create('test_user', { password = 'test_password', if_not_exists = true })
+box.schema.user.grant('test_user', 'read, write, execute', 'universe', nil, { if_not_exists = true })
diff --git a/src/test/resources/enterprise/ssl/Dockerfile b/src/test/resources/enterprise/ssl/Dockerfile
new file mode 100644
index 0000000..ad85ccc
--- /dev/null
+++ b/src/test/resources/enterprise/ssl/Dockerfile
@@ -0,0 +1,35 @@
+FROM centos:7
+
+ARG TARANTOOL_WORKDIR="/app"
+ARG TARANTOOL_RUNDIR="/tmp/run"
+ARG TARANTOOL_DATADIR="/tmp/data"
+ARG SDK_TGT_DIR="/sdk"
+ARG DOWNLOAD_SDK_URI=""
+ARG SDK_VERSION="tarantool-enterprise-sdk-nogc64-2.10.6-0-r557.linux.x86_64"
+ARG SDK_TGZ=$SDK_VERSION.tar.gz
+
+ENV DOWNLOAD_SDK_URI=$DOWNLOAD_SDK_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
+ENV TARANTOOL_TRANSPORT = "ssl"
+ENV TARANTOOL_SSL_SERVER_CA_FILE = "/ssl/ca.crt"
+ENV TARANTOOL_SSL_SERVER_CERT_FILE = "/ssl/server.crt"
+ENV TARANTOOL_SSL_SERVER_KEY_FILE = "/ssl/server.key"
+ENV TARANTOOL_SSL_CLIENT_CA_FILE = "/ssl/ca.crt"
+ENV TARANTOOL_SSL_CLIENT_CERT_FILE = "/ssl/client.crt"
+ENV TARANTOOL_SSL_CLIENT_KEY_FILE = "/ssl/client.key"
+
+RUN curl https://curl.se/ca/cacert.pem -o /etc/pki/tls/certs/ca-bundle.crt && \
+ yum -y install wget && \
+ wget $DOWNLOAD_SDK_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
+
+RUN /usr/bin/tarantool/cartridge version
+
+WORKDIR $TARANTOOL_WORKDIR
+CMD /usr/bin/tarantool/cartridge build && /usr/bin/tarantool/cartridge start --run-dir=$TARANTOOL_RUNDIR --data-dir=$TARANTOOL_DATADIR --cfg=$TARANTOOL_INSTANCES_FILE
diff --git a/src/test/resources/enterprise/ssl/certificate.crt b/src/test/resources/enterprise/ssl/certificate.crt
new file mode 100644
index 0000000..62ebf3a
--- /dev/null
+++ b/src/test/resources/enterprise/ssl/certificate.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDhDCCAmwCCQCbVZGkNwxnRzANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMC
+UlUxDzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MQswCQYDVQQKDAJW
+SzESMBAGA1UECwwJVGFyYW50b29sMRIwEAYDVQQDDAlUYXJhbnRvb2wxHTAbBgkq
+hkiG9w0BCQEWDnRlc3RAdGVzdC50ZXN0MB4XDTIyMDQwNzE2MDU1NFoXDTIzMDQw
+NzE2MDU1NFowgYMxCzAJBgNVBAYTAlJVMQ8wDQYDVQQIDAZNb3Njb3cxDzANBgNV
+BAcMBk1vc2NvdzELMAkGA1UECgwCVksxEjAQBgNVBAsMCVRhcmFudG9vbDESMBAG
+A1UEAwwJVGFyYW50b29sMR0wGwYJKoZIhvcNAQkBFg50ZXN0QHRlc3QudGVzdDCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM/3KMHSybroxV5nR8tm19kg
+uVlWoFzd7IXGcVbeVCdu30wBLeDQ2XvsnjYYMkHUDPWLkVosZO4de0D+vyS2CmgE
+zeurAjCrUEs4Sc/Aa+CTSRuI17EkJjPpDQNSCmp3KJfPGGAypYNT7kH2Va+HvNBR
+HHsSk3xuyXujX02DwsuUnf5XqYuuZ39S5jRZ3qvmQytmVXrOtSeNyhWz50XISTER
+ErczPVfKOIFYEZWj+9cKaTZssYZp95MCbkagKh9ZQ6E/T3TGTMEHrqYuXQC4mHI8
+PEISqnY3Vo4lpe+SBWxpJBOK5YWSTUWdPygyt71xEPkyss+C87bMsdQaY8r4TrkC
+AwEAATANBgkqhkiG9w0BAQsFAAOCAQEAj2xf7QdcSbG0nF783TGnqFK7/pBrrdDb
+zlT3NReHP70FjxPIK5alMkQBM+kn/+j1RDnjJhQQa5NKadhEHqpaRd7R2Iv9a2h8
+xQ78jB1GGygFnc5rGx3h5kOFSLjQlFcm9HYafTlasKYAjvhM4SiBQU/jgG2bHrIb
+KrElFswBsfV2VvmvyYyhwDqrtZzKayS3BMD6fls95W+hUlMtcQXFZCVlIkJj6BVc
+okM2tvkM/6ShokidAIkrq34dg4IJf3ZBXrXdiqtznMdaHAqb++Z4w3DY+hB+82qy
+rUzOXligeS/xxzhiZRuIiGgMg4WbGAv7yexRgqv2wyJiGZfIfBrEdw==
+-----END CERTIFICATE-----
diff --git a/src/test/resources/enterprise/ssl/gen.sh b/src/test/resources/enterprise/ssl/gen.sh
new file mode 100644
index 0000000..f767927
--- /dev/null
+++ b/src/test/resources/enterprise/ssl/gen.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+HOST=tarantool.io
+NEW_KEY_ARG=rsa:4096
+DAYS_ARG=36500
+CYPHER="PBE-SHA1-RC2-40"
+
+gen_ca() {
+ local ca="${1}"
+ openssl req \
+ -new \
+ -nodes \
+ -newkey "${NEW_KEY_ARG}" \
+ -keyout "${ca}.key" \
+ -days "${DAYS_ARG}" \
+ -x509 \
+ -subj "/OU=Unknown/O=Unknown/L=Unknown/ST=unknown/C=AU" \
+ -out "${ca}.crt"
+
+}
+
+gen_cert() {
+ local cert="${1}"
+ local ca="${2}"
+
+ openssl req \
+ -new \
+ -nodes \
+ -newkey "${NEW_KEY_ARG}" \
+ -subj "/CN=${HOST}/OU=Unknown/O=Unknown/L=Unknown/ST=unknown/C=AU" \
+ -keyout "${cert}.key" \
+ -out "${cert}.csr"
+
+ openssl x509 \
+ -req \
+ -days "${DAYS_ARG}" \
+ -CAcreateserial \
+ -CA "${ca}.crt" \
+ -CAkey "${ca}.key" \
+ -in "${cert}.csr" \
+ -out "${cert}.crt"
+
+ rm -f "${cert}.csr"
+ rm -f "${ca}.srl"
+}
+
+secure_key() {
+ local file="${1}"
+ local pass="${2}"
+ openssl pkcs8 \
+ -topk8 \
+ -v1 ${CYPHER} \
+ -in ${file}.key \
+ -out ${file}.pkcs8.key \
+ -passout "pass:${pass}"
+}
+
+gen_ca ca
+gen_cert server ca
+gen_cert client ca
+secure_key client 1q2w3e
diff --git a/src/test/resources/enterprise/ssl/key.pem b/src/test/resources/enterprise/ssl/key.pem
new file mode 100644
index 0000000..81493b0
--- /dev/null
+++ b/src/test/resources/enterprise/ssl/key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDP9yjB0sm66MVe
+Z0fLZtfZILlZVqBc3eyFxnFW3lQnbt9MAS3g0Nl77J42GDJB1Az1i5FaLGTuHXtA
+/r8ktgpoBM3rqwIwq1BLOEnPwGvgk0kbiNexJCYz6Q0DUgpqdyiXzxhgMqWDU+5B
+9lWvh7zQURx7EpN8bsl7o19Ng8LLlJ3+V6mLrmd/UuY0Wd6r5kMrZlV6zrUnjcoV
+s+dFyEkxERK3Mz1XyjiBWBGVo/vXCmk2bLGGafeTAm5GoCofWUOhP090xkzBB66m
+Ll0AuJhyPDxCEqp2N1aOJaXvkgVsaSQTiuWFkk1FnT8oMre9cRD5MrLPgvO2zLHU
+GmPK+E65AgMBAAECggEAVpNrOT1aU+Bhggp2/ftjcnXIE6QXgHG27H4PYv2NhRkI
+BqkbA1OOpqN7vcNW8MapWnNu4F5I6kQFsqoawtqx/Fm7rBd2AvLeq2HUgJN3lXdb
+YQYX3RvSd5vWmgJGacoPcRt651lORBzlvDojs75LYWHS/H1gPtYUNM9vdmKa7orA
+wWL1SITeR3gla0euaPItBUUNEyH4wepqG22ERqk/A7u54KRSvXp0mXRYcoDah6Y/
+nmuWwWfPbqCHgopiT3IBOsqklWIkCzLNx24OhOEXXAfgH5pw85NiPP/ZJN3moNYg
+2Tj3VUt9Po3TnmKX+Az8gG4tNQ9R2F4YbnKm2wxFAQKBgQD1B2guaee/wUR16foX
+pgOW+9TnDwTpBwHFaymzLHG2Gs3Zb0fR5HAGfV9Oxnde8Jw4bprRa5IZYzwgKgKY
+jD9Qa8u+WsYKKOObmyBPTzpJevp0cQ9pxIgR/PSj98LL5Wvitcc82fGQAbA4KK02
+6VnaSfCrW2YDrl4Wk2NBFQACGQKBgQDZRuuD2Cn1dbCPuroQmYE4Pl++ke4mDl7F
+xcOL7syu3uBbep/JwMB/ujruhtY9qBdKdLYjIO11xFtdQWhi7sMhhp3hlv8OGhR4
+b2Po3XnNZJ16/gSu4UqgSJ8ZQA8luNNMA0jUFW8Ki15O6vhvFDS/HIcLot+l3Lna
+B71+l+CFoQKBgQCCtUDOAZCuqdprTDUtCFJB6HTaDRkBdctsFI5aFgtSqVnF86bM
+QJ/B1n9Q9m4XJyMut1G/BTMad+VLAx3/YlEkBVzaXnHmWYmRKF9D72+YYxHXq7gd
+I8myTs3x6ejv+6Jhfbaar2g8+amXS5ua/z//QhIwVsFElW97e4Qm45ztgQKBgEBB
+JeL+qSHq5QUMTnwcOUedwojD9S6R71sDahnWy/cm+Ch1cg2jEAp103m4rGDddc3S
+CA8JbM/3+qDwd+NSAqjGe6g8FD9iXQ1ku6Ig5SVljODTgCULgRs3fr1j4VbherMv
+AXmewRDYOFKUUFXhHtwpnpJFX2hYhynAQjzOw1ohAoGBAIGypNhAgnhc2hyeqYC9
+Sg5JA06PFjuvrpymdcO3pfx9K7fHpU+wH17uYmzscMkFd5KrXVtqkziqMNV78hB4
++x5qgabXlrZj4lVaTJLB5nPWt1VBZXcAwSDw5QAVhZtiXmsqKHgvVzR4hNnOWILq
+1sQlocjdaPKH0EEbP84Ae2a7
+-----END PRIVATE KEY-----
diff --git a/src/test/resources/enterprise/ssl/mtls/Dockerfile b/src/test/resources/enterprise/ssl/mtls/Dockerfile
new file mode 100644
index 0000000..9d6dbb6
--- /dev/null
+++ b/src/test/resources/enterprise/ssl/mtls/Dockerfile
@@ -0,0 +1,32 @@
+FROM centos:7
+
+ARG TARANTOOL_WORKDIR="/app"
+ARG TARANTOOL_RUNDIR="/tmp/run"
+ARG TARANTOOL_DATADIR="/tmp/data"
+ARG SDK_TGT_DIR="/sdk"
+ARG DOWNLOAD_SDK_URI=""
+ARG SDK_VERSION="tarantool-enterprise-sdk-nogc64-2.10.6-0-r557.linux.x86_64"
+ARG SDK_TGZ=$SDK_VERSION.tar.gz
+
+ENV DOWNLOAD_SDK_URI=$DOWNLOAD_SDK_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
+ENV TARANTOOL_TRANSPORT = "ssl"
+ENV TARANTOOL_SSL_CA_FILE = "ca.crt"
+ENV TARANTOOL_SSL_CERT_FILE = "server.crt"
+ENV TARANTOOL_SSL_KEY_FILE = "server.key"
+
+RUN curl https://curl.se/ca/cacert.pem -o /etc/pki/tls/certs/ca-bundle.crt && \
+ yum -y install wget && \
+ wget $DOWNLOAD_SDK_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
+
+RUN /usr/bin/tarantool/cartridgee version
+
+WORKDIR $TARANTOOL_WORKDIR
+CMD /usr/bin/tarantool/cartridge build && /usr/bin/tarantool/cartridge start --run-dir=$TARANTOOL_RUNDIR --data-dir=$TARANTOOL_DATADIR --cfg=$TARANTOOL_INSTANCES_FILE
diff --git a/src/test/resources/enterprise/ssl/mtls/ca.crt b/src/test/resources/enterprise/ssl/mtls/ca.crt
new file mode 100644
index 0000000..7000d37
--- /dev/null
+++ b/src/test/resources/enterprise/ssl/mtls/ca.crt
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFjTCCA3WgAwIBAgIUD0mJoUjJsB4mrsSsBlAorJwmgcUwDQYJKoZIhvcNAQEL
+BQAwVTEQMA4GA1UECwwHVW5rbm93bjEQMA4GA1UECgwHVW5rbm93bjEQMA4GA1UE
+BwwHVW5rbm93bjEQMA4GA1UECAwHdW5rbm93bjELMAkGA1UEBhMCQVUwIBcNMjIw
+NTMxMjEwNTA2WhgPMjEyMjA1MDcyMTA1MDZaMFUxEDAOBgNVBAsMB1Vua25vd24x
+EDAOBgNVBAoMB1Vua25vd24xEDAOBgNVBAcMB1Vua25vd24xEDAOBgNVBAgMB3Vu
+a25vd24xCzAJBgNVBAYTAkFVMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
+AgEAtpV9sxa6KPfTP4r5IJAHML0SlIUX9rSzEwKnbsMuyEKUwmcZVQ1aUWrmTQ0J
+UGboOuVMBaNqmWaeqgJBTXns60/MrKSBQmOUwm1/FIBt6KQF2WZZUM13yq+UN5i/
+MHtAzHxSrecHNmzpvL9y48QJFs4ruoCzVsnLz9EmYChQCrFj1JsfLVvSpcDTFgdV
+bTHJIBF9rHFKB92qMbhDJjrSmvPKNqyaLnWP0WttNIMtE5djrqwGbHolX5JrFIKr
+9LDV2jJiMA7tFVl2cgg+uEcrxqOz421S9VYD0hl5hFF81rpdg/q7MEBHPYD2cCyl
+92mxUYqz7r9OdK7KeMlLD/sjL34IXsT4TbcbMLYcfBdBmDRAbaAlON3spU9EPUxd
+Yvhd3qKDlOP3oCXDE5MKQujz7gR3XQpX3Zdd5zxdcp/GiE9RivoKstm5/JznN+ns
+BaBzw6d4gBTzIPMmiAmUTrnWD5UEhsG/kHzk+K2WXJS8/05CIZThLgILl/vfgrMX
+3OBUsw1ePXj2Jmp1HLExtpX8U1NKA8UtU97QRX40eWvMuLGz7sKMS/VZiA9eNkMI
+hQhkjMt0JPo9gfMggVMBOjQbLV4Ni4XZeMzurtGOmlD61s7GECySKHy5pYZtXisO
+VpKABYTEyTIPPjuwN5W90h+/NI2h8xW2Z9xsE7K0flGtA1cCAwEAAaNTMFEwHQYD
+VR0OBBYEFKA+WAfH0GT8G4aM4RTplY4ECcQDMB8GA1UdIwQYMBaAFKA+WAfH0GT8
+G4aM4RTplY4ECcQDMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIB
+AG++VdNo894uxESkzjVEC6hSLdcER6EbQOM34H13MzseMIjlv/4ely/Vsh79QEXA
+fnAadrdVk/0r3BpBaO/iOLdMquePLBi/IYxfLaY8z2nwaocbMKUVmVjFuOgm+oXq
+atyc/yzVG5yyaxoC1jHIgjn81fesI0f17opqda13u+4hXTcdAbpOY7yZY8YmP2o+
+SCCfGco1BBSyKIteHLzQzpG8pZnKM0seAitZ9jD5CF9jw0tzJCWkDIhJ2dgjpigz
+Go5WBxY3FMyKQPOIP5a+5AWRV+fVWENdZu9EwEWpLqc/GxQrvhbXhJ/L2ZiYRNd8
+SNTBL7H0Sw65jHRWWSfz7osVntL+LYRPh30sF9LYTpUnp3gr4VTXLo6jaxwhvsIy
+CacNhLpgco0sM6RLcHaSxYMUtO3EttDbkcBmIyP1KHEq1mzcVcXSetS7g9efxToh
+G7NH1zVP1a8qJF5qKjXgRBASIXke9AHeAOYDI7om7qQtGuqI7nI3eg5E0qUM1gqH
+kTKXJcXn/pwCkJL8TvRZWlYNJMG2YEwdA4KFgywHGn3GaM2quNqbZosMF84vlvnp
+lrzJbrg2nD/wwQWdljJPVp5WReoPI9t08UqopR2P+zFcDh75X+3SXL8mMRIXMvFU
+eTU7QSXhc9Q6l+skY2cRgvYl++fIooebBXpCYY9uDht9
+-----END CERTIFICATE-----
diff --git a/src/test/resources/enterprise/ssl/mtls/ca.key b/src/test/resources/enterprise/ssl/mtls/ca.key
new file mode 100644
index 0000000..48c1040
--- /dev/null
+++ b/src/test/resources/enterprise/ssl/mtls/ca.key
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
+YfB9GdaUnR0F648bsknruMJrFjfZFbo=
+-----END PRIVATE KEY-----
diff --git a/src/test/resources/enterprise/ssl/mtls/mtls_server.lua b/src/test/resources/enterprise/ssl/mtls/mtls_server.lua
new file mode 100644
index 0000000..1c999b7
--- /dev/null
+++ b/src/test/resources/enterprise/ssl/mtls/mtls_server.lua
@@ -0,0 +1,12 @@
+box.cfg { listen = {
+ uri = 3301,
+ params = {
+ transport = 'ssl',
+ ssl_key_file = 'server.key',
+ ssl_cert_file = 'server.crt',
+ ssl_ca_file = 'ca.crt'
+ }
+} }
+
+box.schema.user.create('test_user', { password = 'test_password', if_not_exists = true })
+box.schema.user.grant('test_user', 'read, write, execute', 'universe', nil, { if_not_exists = true })
diff --git a/src/test/resources/enterprise/ssl/mtls/server.crt b/src/test/resources/enterprise/ssl/mtls/server.crt
new file mode 100644
index 0000000..fe661cc
--- /dev/null
+++ b/src/test/resources/enterprise/ssl/mtls/server.crt
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFSjCCAzICFAGDWf+4nbv3f7+QrRbP8Q3YhzOaMA0GCSqGSIb3DQEBCwUAMFUx
+EDAOBgNVBAsMB1Vua25vd24xEDAOBgNVBAoMB1Vua25vd24xEDAOBgNVBAcMB1Vu
+a25vd24xEDAOBgNVBAgMB3Vua25vd24xCzAJBgNVBAYTAkFVMCAXDTIyMDUzMTIx
+MDUwOVoYDzIxMjIwNTA3MjEwNTA5WjBsMRUwEwYDVQQDDAx0YXJhbnRvb2wuaW8x
+EDAOBgNVBAsMB1Vua25vd24xEDAOBgNVBAoMB1Vua25vd24xEDAOBgNVBAcMB1Vu
+a25vd24xEDAOBgNVBAgMB3Vua25vd24xCzAJBgNVBAYTAkFVMIICIjANBgkqhkiG
+9w0BAQEFAAOCAg8AMIICCgKCAgEAy8ClyS3WZlJwycdRM1Nteke6adcgScUz0hVn
+yhZJpZo4crReCTtCzOWNstlA5nnzlDT56YbnmzAwDNG6pPP00t2jVUU5wxMJSDGy
+SkDk0nxq4Rd20EDV3+GIxJ+aEEPYwMcY4RcGErG+5yrSVbWniDLcvKeMjLjODzUr
+vzSuBsRgtMt8Z6vQUaBxIdT3XupLFSZb4k883TkQE8wXjqbLmmOPoQAu1WZVAKEV
+uvxXKonYlgC00Rl7HsaEMw8zUL7P1e+qtn6GaXkdI55Lk2y/yk0UKhBWR43mDoTx
+VWyWrVnL7rFLt7Doz6F8Q5tiekjz3WpVhm2z7aGMZ/n3FE3etNVbnZg1/wqXjini
+VXCgaUKryEYKR1kgPxUJB7EHjSLIGIn1Ix6toMK6ntr+WySMUfSt0A5jsQ3WM1TY
+8YOdFuFbeiPpTD9Qq7hDPW1AyGOkh31eecqVwBJQlajRrkZBBZ8EacbR6aDgBfm4
+n3gtoUuZZYf1aW1HzlWjaVp6M5gJCbbvuGjcfpVAbq71PTM6PYHvfe2wlbfJR02V
+H7kGUUbE3A1JIGSys44FLaitY3Gy+X/Tj+bEH1uid/Q6ykcCcU/ICDoaXBQ9jbSv
+56CfIjoSUY2JXpDG/Ahli/b6pwvP9CkLGTDc0VWpuG4sB3sbzjhYyijDac48/JuJ
+HVk1mMcCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEARGdetChBKbDNaxGA+NHAtDGe
+2lVISV21j5L1EkWQhrp39bx1YsFmvV+wibYuTDTlk/XSh+MpuRvTmc8xWXIIe30Y
+PQXQPCrRd8vNjHt6i0MpW4kCe0QU/PTGOOBpD1VnJuAuebqmLuvdwCHb5uCacbVJ
+Gt9voyM3yQQNZ0A3jYcm7Y6PAEL/gxq0+F30+LwvZqaAGO6hqC7WJuiyoE9No9ri
++0vZG0F0l1ZiVWaIi5m38KfYGuhd8tAEKkTUZ2cL0Td/KOavCgJ1D8s4co3wyDZG
+qrIVKHYvl8G2YivQdXpMuh32QAog/34zI909pM0E2IzxRl6YBjP9UaAUW6LWWuWZ
+1pso3pL/+WynAUC9gsWFcnsv3Ji4ZH24nA7BemBwo5JT/5WTtMTAA4phQDH340x4
+VnHPigcvyu3eh/PDS7ZdiUSGuNcibSTrhn4bluCv5vzzmw+Atp9eccF81LxfERJY
+4H94Kw70/8LBLR/7McL/aobJ5mSpAK1nnsRdr1xE46uGpkmK4pgHfD5xkcn9AFxE
+vsCnwynYp4RNPfiLUHNzez0T4JWnJqPtSNtR2jTO3iVz04SUbUj/cltXOLzyPfyM
+VouEL2VnAmC1WCN5KC6NnzyKVLbQ7EAi4x+61lJWWkRugxrXeaVdNbgQlA1yvAlF
+cA8F69eVyPJnFsdWSq0=
+-----END CERTIFICATE-----
diff --git a/src/test/resources/enterprise/ssl/mtls/server.key b/src/test/resources/enterprise/ssl/mtls/server.key
new file mode 100644
index 0000000..f6f5117
--- /dev/null
+++ b/src/test/resources/enterprise/ssl/mtls/server.key
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
+jE5s8iIxjb4IkPziVOzgev4epyIs
+-----END PRIVATE KEY-----
diff --git a/src/test/resources/enterprise/ssl/mtls/trustStoreFile b/src/test/resources/enterprise/ssl/mtls/trustStoreFile
new file mode 100644
index 0000000..af02d8b
Binary files /dev/null and b/src/test/resources/enterprise/ssl/mtls/trustStoreFile differ
diff --git a/src/test/resources/enterprise/ssl/ssl_server.lua b/src/test/resources/enterprise/ssl/ssl_server.lua
new file mode 100644
index 0000000..4c0cc96
--- /dev/null
+++ b/src/test/resources/enterprise/ssl/ssl_server.lua
@@ -0,0 +1,11 @@
+box.cfg { listen = {
+ uri = 3301,
+ params = {
+ transport = 'ssl',
+ ssl_key_file = 'key.pem',
+ ssl_cert_file = 'certificate.crt'
+ }
+} }
+
+box.schema.user.create('test_user', { password = 'test_password', if_not_exists = true })
+box.schema.user.grant('test_user', 'read, write, execute', 'universe', nil, { if_not_exists = true })