diff --git a/src/main/java/org/testcontainers/containers/TarantoolCartridgeContainer.java b/src/main/java/org/testcontainers/containers/TarantoolCartridgeContainer.java index 8eed0f6..fe7e98e 100644 --- a/src/main/java/org/testcontainers/containers/TarantoolCartridgeContainer.java +++ b/src/main/java/org/testcontainers/containers/TarantoolCartridgeContainer.java @@ -5,7 +5,9 @@ import java.net.URL; import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -98,6 +100,7 @@ public class TarantoolCartridgeContainer extends GenericContainer buildArgs) { + this(withArguments(buildImage(dockerFile, buildImageName), buildArgs), + instancesFile, topologyConfigurationFile); } private TarantoolCartridgeContainer(Future image, String instancesFile, String topologyConfigurationFile) { @@ -153,13 +175,15 @@ private TarantoolCartridgeContainer(Future image, String instancesFile, if (instancesFile == null || instancesFile.isEmpty()) { throw new IllegalArgumentException("Instance file name must not be null or empty"); } - this.instancesFile = instancesFile; this.instanceFileParser = new CartridgeConfigParser(instancesFile); this.topologyConfigurationFile = topologyConfigurationFile; this.clientHelper = new TarantoolContainerClientHelper(this); } - private static Future withArguments(ImageFromDockerfile image) { + private static Future withArguments(ImageFromDockerfile image, final Map buildArgs) { + if (!buildArgs.isEmpty()) { + image.withBuildArgs(buildArgs); + } for (String envVariable : Arrays.asList( ENV_TARANTOOL_VERSION, ENV_TARANTOOL_SERVER_USER, @@ -178,17 +202,12 @@ private static Future withArguments(ImageFromDockerfile image) { return image; } - private static ImageFromDockerfile buildImage() { - return buildImage(DOCKERFILE); - } - - private static ImageFromDockerfile buildImage(String dockerFile) { - return new ImageFromDockerfile().withFileFromClasspath("Dockerfile", dockerFile); - } - private static ImageFromDockerfile buildImage(String dockerFile, String buildImageName) { - return new ImageFromDockerfile(buildImageName, false) - .withFileFromClasspath("Dockerfile", dockerFile); + if (buildImageName != null && !buildImageName.isEmpty()) { + return new ImageFromDockerfile(buildImageName, false) + .withFileFromClasspath("Dockerfile", dockerFile); + } + return new ImageFromDockerfile().withFileFromClasspath("Dockerfile", dockerFile); } /** @@ -206,6 +225,9 @@ public String getRouterHost() { * @return router mapped port */ public int getRouterPort() { + if (useFixedPorts) { + return routerPort; + } return getMappedPort(routerPort); } @@ -312,9 +334,23 @@ public TarantoolCartridgeContainer withDirectoryBinding(String directoryResource * @return HTTP API port */ public int getAPIPort() { + if (useFixedPorts) { + return apiPort; + } return getMappedPort(apiPort); } + /** + * Use fixed ports binding. + * Defaults to false. + * + * @return HTTP API port + */ + public TarantoolCartridgeContainer withUseFixedPorts(boolean useFixedPorts) { + this.useFixedPorts = useFixedPorts; + return this; + } + /** * Set Cartridge router hostname * @@ -377,8 +413,17 @@ public TarantoolCartridgeContainer withRouterPassword(String routerPassword) { @Override protected void configure() { - withFileSystemBind(getDirectoryBinding(), getInstanceDir(), BindMode.READ_WRITE); - withExposedPorts(instanceFileParser.getExposablePorts()); + if (!getDirectoryBinding().isEmpty()) { + withFileSystemBind(getDirectoryBinding(), getInstanceDir(), BindMode.READ_WRITE); + } + + if (useFixedPorts) { + for (Integer port : instanceFileParser.getExposablePorts()) { + addFixedExposedPort(port, port); + } + } else { + withExposedPorts(instanceFileParser.getExposablePorts()); + } } @Override diff --git a/src/main/java/org/testcontainers/containers/TarantoolContainer.java b/src/main/java/org/testcontainers/containers/TarantoolContainer.java index 932f926..85579bf 100644 --- a/src/main/java/org/testcontainers/containers/TarantoolContainer.java +++ b/src/main/java/org/testcontainers/containers/TarantoolContainer.java @@ -43,6 +43,7 @@ public class TarantoolContainer extends GenericContainer private String directoryResourcePath = SCRIPT_RESOURCE_DIRECTORY; private String scriptFileName = SCRIPT_FILENAME; private String instanceDir = INSTANCE_DIR; + private boolean useFixedPorts = false; private final TarantoolContainerClientHelper clientHelper; @@ -60,6 +61,17 @@ public TarantoolContainer(Future image) { clientHelper = new TarantoolContainerClientHelper(this); } + /** + * Use fixed ports binding. + * Defaults to false. + * + * @return HTTP API port + */ + public TarantoolContainer withUseFixedPorts(boolean useFixedPorts) { + this.useFixedPorts = useFixedPorts; + return this; + } + /** * Specify the host for connecting to Tarantool with. * @@ -259,8 +271,16 @@ protected void configure() { } String sourceDirectoryPath = normalizePath(sourceDirectory.getPath()); - withFileSystemBind(sourceDirectoryPath, getInstanceDir(), BindMode.READ_WRITE); - withExposedPorts(port); + //disable bind if directory is empty + if (!sourceDirectoryPath.isEmpty()) { + withFileSystemBind(sourceDirectoryPath, getInstanceDir(), BindMode.READ_WRITE); + } + + if (useFixedPorts) { + addFixedExposedPort(port, port); + } else { + withExposedPorts(port); + } withCommand("tarantool", normalizePath( Paths.get(getInstanceDir(), getScriptFileName()))); diff --git a/src/test/java/org/testcontainers/containers/CartridgeContainerTestUtils.java b/src/test/java/org/testcontainers/containers/CartridgeContainerTestUtils.java new file mode 100644 index 0000000..8a15cf9 --- /dev/null +++ b/src/test/java/org/testcontainers/containers/CartridgeContainerTestUtils.java @@ -0,0 +1,24 @@ +package org.testcontainers.containers; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Vladimir Rogach + */ +public class CartridgeContainerTestUtils { + + private CartridgeContainerTestUtils() { + } + + static public void executeProfileReplaceSmokeTest(TarantoolCartridgeContainer container) throws Exception { + container.executeCommand( + "return profile_replace(...)", Arrays.asList(1, "Ivanov Ivan Ivanovich", 33, 100500)).get(); + + List result = container.executeCommand("return profile_get(...)", 1).get(); + assertEquals(1, result.size()); + assertEquals(33, ((List) result.get(0)).get(3)); + } +} diff --git a/src/test/java/org/testcontainers/containers/TarantoolCartridgeContainerTest.java b/src/test/java/org/testcontainers/containers/TarantoolCartridgeContainerTest.java new file mode 100644 index 0000000..41e5db6 --- /dev/null +++ b/src/test/java/org/testcontainers/containers/TarantoolCartridgeContainerTest.java @@ -0,0 +1,66 @@ +package org.testcontainers.containers; + +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; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Vladimir Rogach + */ +public class TarantoolCartridgeContainerTest { + + @Test + public void test_ClusterContainer_StartsSuccessfully_ifFilesAreCopiedUnderRoot() throws Exception { + Map buildArgs = new HashMap() { + { + put("TARANTOOL_SERVER_USER", "root"); + put("TARANTOOL_SERVER_UID", "0"); + put("TARANTOOL_SERVER_GROUP", "root"); + put("TARANTOOL_SERVER_GID", "0"); + } + }; + TarantoolCartridgeContainer container = + new TarantoolCartridgeContainer( + "Dockerfile", + "testcontainers-java-tarantool:test", + "cartridge/instances.yml", + "cartridge/topology.lua", + buildArgs) + .withCopyFileToContainer(MountableFile.forClasspathResource("cartridge"), "/app") + .withStartupTimeout(Duration.ofSeconds(300)) + .withLogConsumer(new Slf4jLogConsumer( + LoggerFactory.getLogger(TarantoolCartridgeContainerTest.class))); + + container.start(); + CartridgeContainerTestUtils.executeProfileReplaceSmokeTest(container); + } + + @Test + public void test_ClusterContainer_StartsSuccessfully_ifFixedPortsAreConfigured() throws Exception { + TarantoolCartridgeContainer container = + new TarantoolCartridgeContainer( + "Dockerfile", + "testcontainers-java-tarantool:test", + "cartridge/instances_fixedport.yml", + "cartridge/topology_fixedport.lua") + .withDirectoryBinding("cartridge") + .withStartupTimeout(Duration.ofSeconds(300)) + .withUseFixedPorts(true) + .withAPIPort(18081) + .withRouterPort(13301) + .waitingFor( + Wait.forLogMessage(".*Listening HTTP on.*", 1) + ) + .withLogConsumer(new Slf4jLogConsumer( + LoggerFactory.getLogger(TarantoolCartridgeContainerTest.class))); + + container.start(); + CartridgeContainerTestUtils.executeProfileReplaceSmokeTest(container); + } +} diff --git a/src/test/java/org/testcontainers/containers/TarantoolCartridgeStaticContainerTest.java b/src/test/java/org/testcontainers/containers/TarantoolCartridgeStaticContainerTest.java index 36a2689..ffc8c4b 100644 --- a/src/test/java/org/testcontainers/containers/TarantoolCartridgeStaticContainerTest.java +++ b/src/test/java/org/testcontainers/containers/TarantoolCartridgeStaticContainerTest.java @@ -7,10 +7,6 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.time.Duration; -import java.util.Arrays; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; /** * @author Alexey Kuzin @@ -32,11 +28,6 @@ public class TarantoolCartridgeStaticContainerTest { @Test public void testContainerWithParameters() throws Exception { - container.executeCommand( - "return profile_replace(...)", Arrays.asList(1, "Ivanov Ivan Ivanovich", 33, 100500)).get(); - - List result = container.executeCommand("return profile_get(...)", 1).get(); - assertEquals(1, result.size()); - assertEquals(33, ((List) result.get(0)).get(3)); + CartridgeContainerTestUtils.executeProfileReplaceSmokeTest(container); } } diff --git a/src/test/resources/cartridge/instances.yml b/src/test/resources/cartridge/instances.yml index dcf0e9b..1119e19 100644 --- a/src/test/resources/cartridge/instances.yml +++ b/src/test/resources/cartridge/instances.yml @@ -27,3 +27,13 @@ testapp-stateboard: workdir: ./tmp/db_dev/3310 listen: localhost:3310 password: passwd + +testapp.router-fixedport: + workdir: ./tmp/db_dev/13301 + advertise_uri: localhost:13301 + http_port: 18081 + +testapp.storage-fixedport: + workdir: ./tmp/db_dev/13302 + advertise_uri: localhost:13302 + http_port: 18082 diff --git a/src/test/resources/cartridge/instances_fixedport.yml b/src/test/resources/cartridge/instances_fixedport.yml new file mode 100644 index 0000000..b281999 --- /dev/null +++ b/src/test/resources/cartridge/instances_fixedport.yml @@ -0,0 +1,9 @@ +testapp.router-fixedport: + workdir: ./tmp/db_dev/13301 + advertise_uri: localhost:13301 + http_port: 18081 + +testapp.storage-fixedport: + workdir: ./tmp/db_dev/13302 + advertise_uri: localhost:13302 + http_port: 18082 diff --git a/src/test/resources/cartridge/topology_fixedport.lua b/src/test/resources/cartridge/topology_fixedport.lua new file mode 100644 index 0000000..b9dc697 --- /dev/null +++ b/src/test/resources/cartridge/topology_fixedport.lua @@ -0,0 +1,11 @@ +cartridge = require('cartridge') +replicasets = {{ + alias = 'router-fixedport', + roles = {'vshard-router', 'app.roles.custom', 'app.roles.api_router'}, + join_servers = {{uri = 'localhost:13301'}} +}, { + alias = 'storage-fixedport', + roles = {'vshard-storage', 'app.roles.api_storage'}, + join_servers = {{uri = 'localhost:13302'}} +}} +return cartridge.admin_edit_topology({replicasets = replicasets})