Skip to content

Commit 0bcbdeb

Browse files
authored
Fix problems with ports and directory bindings. (#29)
* Closes #24, closes #25. Add option to bind container to fixed host ports * Add tests for dynamic cartridge container with different options * Refactor cartridge container creation
1 parent d878f27 commit 0bcbdeb

File tree

8 files changed

+206
-30
lines changed

8 files changed

+206
-30
lines changed

src/main/java/org/testcontainers/containers/TarantoolCartridgeContainer.java

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55

66
import java.net.URL;
77
import java.util.Arrays;
8+
import java.util.Collections;
89
import java.util.List;
10+
import java.util.Map;
911
import java.util.concurrent.CompletableFuture;
1012
import java.util.concurrent.ExecutionException;
1113
import java.util.concurrent.Future;
@@ -98,6 +100,7 @@ public class TarantoolCartridgeContainer extends GenericContainer<TarantoolCartr
98100
private static final String ENV_TARANTOOL_WORKDIR = "TARANTOOL_WORKDIR";
99101
private static final String ENV_TARANTOOL_RUNDIR = "TARANTOOL_RUNDIR";
100102
private static final String ENV_TARANTOOL_DATADIR = "TARANTOOL_DATADIR";
103+
private boolean useFixedPorts = false;
101104

102105
private String routerHost = ROUTER_HOST;
103106
private int routerPort = ROUTER_PORT;
@@ -106,7 +109,6 @@ public class TarantoolCartridgeContainer extends GenericContainer<TarantoolCartr
106109
private String routerPassword = CARTRIDGE_PASSWORD;
107110
private String directoryResourcePath = SCRIPT_RESOURCE_DIRECTORY;
108111
private String instanceDir = INSTANCE_DIR;
109-
private final String instancesFile;
110112
private final CartridgeConfigParser instanceFileParser;
111113
private final String topologyConfigurationFile;
112114
private final TarantoolContainerClientHelper clientHelper;
@@ -119,7 +121,7 @@ public class TarantoolCartridgeContainer extends GenericContainer<TarantoolCartr
119121
* @param topologyConfigurationFile path to a topology bootstrap script, relative to the classpath resources
120122
*/
121123
public TarantoolCartridgeContainer(String instancesFile, String topologyConfigurationFile) {
122-
this(withArguments(buildImage()), instancesFile, topologyConfigurationFile);
124+
this(DOCKERFILE, instancesFile, topologyConfigurationFile);
123125
}
124126

125127
/**
@@ -130,7 +132,7 @@ public TarantoolCartridgeContainer(String instancesFile, String topologyConfigur
130132
* @param topologyConfigurationFile path to a topology bootstrap script, relative to the classpath resources
131133
*/
132134
public TarantoolCartridgeContainer(String dockerFile, String instancesFile, String topologyConfigurationFile) {
133-
this(withArguments(buildImage(dockerFile)), instancesFile, topologyConfigurationFile);
135+
this(dockerFile, "", instancesFile, topologyConfigurationFile);
134136
}
135137

136138
/**
@@ -145,21 +147,43 @@ public TarantoolCartridgeContainer(String dockerFile, String instancesFile, Stri
145147
*/
146148
public TarantoolCartridgeContainer(String dockerFile, String buildImageName,
147149
String instancesFile, String topologyConfigurationFile) {
148-
this(withArguments(buildImage(dockerFile, buildImageName)), instancesFile, topologyConfigurationFile);
150+
this(dockerFile, buildImageName, instancesFile, topologyConfigurationFile, Collections.emptyMap());
151+
}
152+
153+
154+
/**
155+
* Create a container with specified image and specified instances file from the classpath resources. By providing
156+
* the result Cartridge container image name, you can cache the image and avoid rebuilding on each test run (the
157+
* image is tagged with the provided name and not deleted after tests finishing).
158+
*
159+
* @param dockerFile URL resource path to a Dockerfile which configures Cartridge
160+
* and other necessary services
161+
* @param buildImageName Specify a stable image name for the test container to prevent rebuilds
162+
* @param instancesFile URL resource path to instances.yml relative in the classpath
163+
* @param topologyConfigurationFile URL resource path to a topology bootstrap script in the classpath
164+
* @param buildArgs a map of arguments that will be passed to docker ARG commands on image build.
165+
* This values can be overriden by environment.
166+
*/
167+
public TarantoolCartridgeContainer(String dockerFile, String buildImageName, String instancesFile,
168+
String topologyConfigurationFile, final Map<String, String> buildArgs) {
169+
this(withArguments(buildImage(dockerFile, buildImageName), buildArgs),
170+
instancesFile, topologyConfigurationFile);
149171
}
150172

151173
private TarantoolCartridgeContainer(Future<String> image, String instancesFile, String topologyConfigurationFile) {
152174
super(image);
153175
if (instancesFile == null || instancesFile.isEmpty()) {
154176
throw new IllegalArgumentException("Instance file name must not be null or empty");
155177
}
156-
this.instancesFile = instancesFile;
157178
this.instanceFileParser = new CartridgeConfigParser(instancesFile);
158179
this.topologyConfigurationFile = topologyConfigurationFile;
159180
this.clientHelper = new TarantoolContainerClientHelper(this);
160181
}
161182

162-
private static Future<String> withArguments(ImageFromDockerfile image) {
183+
private static Future<String> withArguments(ImageFromDockerfile image, final Map<String, String> buildArgs) {
184+
if (!buildArgs.isEmpty()) {
185+
image.withBuildArgs(buildArgs);
186+
}
163187
for (String envVariable : Arrays.asList(
164188
ENV_TARANTOOL_VERSION,
165189
ENV_TARANTOOL_SERVER_USER,
@@ -178,17 +202,12 @@ private static Future<String> withArguments(ImageFromDockerfile image) {
178202
return image;
179203
}
180204

181-
private static ImageFromDockerfile buildImage() {
182-
return buildImage(DOCKERFILE);
183-
}
184-
185-
private static ImageFromDockerfile buildImage(String dockerFile) {
186-
return new ImageFromDockerfile().withFileFromClasspath("Dockerfile", dockerFile);
187-
}
188-
189205
private static ImageFromDockerfile buildImage(String dockerFile, String buildImageName) {
190-
return new ImageFromDockerfile(buildImageName, false)
191-
.withFileFromClasspath("Dockerfile", dockerFile);
206+
if (buildImageName != null && !buildImageName.isEmpty()) {
207+
return new ImageFromDockerfile(buildImageName, false)
208+
.withFileFromClasspath("Dockerfile", dockerFile);
209+
}
210+
return new ImageFromDockerfile().withFileFromClasspath("Dockerfile", dockerFile);
192211
}
193212

194213
/**
@@ -206,6 +225,9 @@ public String getRouterHost() {
206225
* @return router mapped port
207226
*/
208227
public int getRouterPort() {
228+
if (useFixedPorts) {
229+
return routerPort;
230+
}
209231
return getMappedPort(routerPort);
210232
}
211233

@@ -312,9 +334,23 @@ public TarantoolCartridgeContainer withDirectoryBinding(String directoryResource
312334
* @return HTTP API port
313335
*/
314336
public int getAPIPort() {
337+
if (useFixedPorts) {
338+
return apiPort;
339+
}
315340
return getMappedPort(apiPort);
316341
}
317342

343+
/**
344+
* Use fixed ports binding.
345+
* Defaults to false.
346+
*
347+
* @return HTTP API port
348+
*/
349+
public TarantoolCartridgeContainer withUseFixedPorts(boolean useFixedPorts) {
350+
this.useFixedPorts = useFixedPorts;
351+
return this;
352+
}
353+
318354
/**
319355
* Set Cartridge router hostname
320356
*
@@ -377,8 +413,17 @@ public TarantoolCartridgeContainer withRouterPassword(String routerPassword) {
377413

378414
@Override
379415
protected void configure() {
380-
withFileSystemBind(getDirectoryBinding(), getInstanceDir(), BindMode.READ_WRITE);
381-
withExposedPorts(instanceFileParser.getExposablePorts());
416+
if (!getDirectoryBinding().isEmpty()) {
417+
withFileSystemBind(getDirectoryBinding(), getInstanceDir(), BindMode.READ_WRITE);
418+
}
419+
420+
if (useFixedPorts) {
421+
for (Integer port : instanceFileParser.getExposablePorts()) {
422+
addFixedExposedPort(port, port);
423+
}
424+
} else {
425+
withExposedPorts(instanceFileParser.getExposablePorts());
426+
}
382427
}
383428

384429
@Override

src/main/java/org/testcontainers/containers/TarantoolContainer.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public class TarantoolContainer extends GenericContainer<TarantoolContainer>
4343
private String directoryResourcePath = SCRIPT_RESOURCE_DIRECTORY;
4444
private String scriptFileName = SCRIPT_FILENAME;
4545
private String instanceDir = INSTANCE_DIR;
46+
private boolean useFixedPorts = false;
4647

4748
private final TarantoolContainerClientHelper clientHelper;
4849

@@ -60,6 +61,17 @@ public TarantoolContainer(Future<String> image) {
6061
clientHelper = new TarantoolContainerClientHelper(this);
6162
}
6263

64+
/**
65+
* Use fixed ports binding.
66+
* Defaults to false.
67+
*
68+
* @return HTTP API port
69+
*/
70+
public TarantoolContainer withUseFixedPorts(boolean useFixedPorts) {
71+
this.useFixedPorts = useFixedPorts;
72+
return this;
73+
}
74+
6375
/**
6476
* Specify the host for connecting to Tarantool with.
6577
*
@@ -259,8 +271,16 @@ protected void configure() {
259271
}
260272
String sourceDirectoryPath = normalizePath(sourceDirectory.getPath());
261273

262-
withFileSystemBind(sourceDirectoryPath, getInstanceDir(), BindMode.READ_WRITE);
263-
withExposedPorts(port);
274+
//disable bind if directory is empty
275+
if (!sourceDirectoryPath.isEmpty()) {
276+
withFileSystemBind(sourceDirectoryPath, getInstanceDir(), BindMode.READ_WRITE);
277+
}
278+
279+
if (useFixedPorts) {
280+
addFixedExposedPort(port, port);
281+
} else {
282+
withExposedPorts(port);
283+
}
264284

265285
withCommand("tarantool", normalizePath(
266286
Paths.get(getInstanceDir(), getScriptFileName())));
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.testcontainers.containers;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
6+
import static org.junit.jupiter.api.Assertions.assertEquals;
7+
8+
/**
9+
* @author Vladimir Rogach
10+
*/
11+
public class CartridgeContainerTestUtils {
12+
13+
private CartridgeContainerTestUtils() {
14+
}
15+
16+
static public void executeProfileReplaceSmokeTest(TarantoolCartridgeContainer container) throws Exception {
17+
container.executeCommand(
18+
"return profile_replace(...)", Arrays.asList(1, "Ivanov Ivan Ivanovich", 33, 100500)).get();
19+
20+
List<?> result = container.executeCommand("return profile_get(...)", 1).get();
21+
assertEquals(1, result.size());
22+
assertEquals(33, ((List<?>) result.get(0)).get(3));
23+
}
24+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.testcontainers.containers;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.slf4j.LoggerFactory;
5+
import org.testcontainers.containers.output.Slf4jLogConsumer;
6+
import org.testcontainers.containers.wait.strategy.Wait;
7+
import org.testcontainers.utility.MountableFile;
8+
9+
import java.time.Duration;
10+
import java.util.HashMap;
11+
import java.util.Map;
12+
13+
/**
14+
* @author Vladimir Rogach
15+
*/
16+
public class TarantoolCartridgeContainerTest {
17+
18+
@Test
19+
public void test_ClusterContainer_StartsSuccessfully_ifFilesAreCopiedUnderRoot() throws Exception {
20+
Map<String, String> buildArgs = new HashMap<String, String>() {
21+
{
22+
put("TARANTOOL_SERVER_USER", "root");
23+
put("TARANTOOL_SERVER_UID", "0");
24+
put("TARANTOOL_SERVER_GROUP", "root");
25+
put("TARANTOOL_SERVER_GID", "0");
26+
}
27+
};
28+
TarantoolCartridgeContainer container =
29+
new TarantoolCartridgeContainer(
30+
"Dockerfile",
31+
"testcontainers-java-tarantool:test",
32+
"cartridge/instances.yml",
33+
"cartridge/topology.lua",
34+
buildArgs)
35+
.withCopyFileToContainer(MountableFile.forClasspathResource("cartridge"), "/app")
36+
.withStartupTimeout(Duration.ofSeconds(300))
37+
.withLogConsumer(new Slf4jLogConsumer(
38+
LoggerFactory.getLogger(TarantoolCartridgeContainerTest.class)));
39+
40+
container.start();
41+
CartridgeContainerTestUtils.executeProfileReplaceSmokeTest(container);
42+
}
43+
44+
@Test
45+
public void test_ClusterContainer_StartsSuccessfully_ifFixedPortsAreConfigured() throws Exception {
46+
TarantoolCartridgeContainer container =
47+
new TarantoolCartridgeContainer(
48+
"Dockerfile",
49+
"testcontainers-java-tarantool:test",
50+
"cartridge/instances_fixedport.yml",
51+
"cartridge/topology_fixedport.lua")
52+
.withDirectoryBinding("cartridge")
53+
.withStartupTimeout(Duration.ofSeconds(300))
54+
.withUseFixedPorts(true)
55+
.withAPIPort(18081)
56+
.withRouterPort(13301)
57+
.waitingFor(
58+
Wait.forLogMessage(".*Listening HTTP on.*", 1)
59+
)
60+
.withLogConsumer(new Slf4jLogConsumer(
61+
LoggerFactory.getLogger(TarantoolCartridgeContainerTest.class)));
62+
63+
container.start();
64+
CartridgeContainerTestUtils.executeProfileReplaceSmokeTest(container);
65+
}
66+
}

src/test/java/org/testcontainers/containers/TarantoolCartridgeStaticContainerTest.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@
77
import org.testcontainers.junit.jupiter.Testcontainers;
88

99
import java.time.Duration;
10-
import java.util.Arrays;
11-
import java.util.List;
12-
13-
import static org.junit.jupiter.api.Assertions.assertEquals;
1410

1511
/**
1612
* @author Alexey Kuzin
@@ -32,11 +28,6 @@ public class TarantoolCartridgeStaticContainerTest {
3228

3329
@Test
3430
public void testContainerWithParameters() throws Exception {
35-
container.executeCommand(
36-
"return profile_replace(...)", Arrays.asList(1, "Ivanov Ivan Ivanovich", 33, 100500)).get();
37-
38-
List<?> result = container.executeCommand("return profile_get(...)", 1).get();
39-
assertEquals(1, result.size());
40-
assertEquals(33, ((List<?>) result.get(0)).get(3));
31+
CartridgeContainerTestUtils.executeProfileReplaceSmokeTest(container);
4132
}
4233
}

src/test/resources/cartridge/instances.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,13 @@ testapp-stateboard:
2727
workdir: ./tmp/db_dev/3310
2828
listen: localhost:3310
2929
password: passwd
30+
31+
testapp.router-fixedport:
32+
workdir: ./tmp/db_dev/13301
33+
advertise_uri: localhost:13301
34+
http_port: 18081
35+
36+
testapp.storage-fixedport:
37+
workdir: ./tmp/db_dev/13302
38+
advertise_uri: localhost:13302
39+
http_port: 18082
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
testapp.router-fixedport:
2+
workdir: ./tmp/db_dev/13301
3+
advertise_uri: localhost:13301
4+
http_port: 18081
5+
6+
testapp.storage-fixedport:
7+
workdir: ./tmp/db_dev/13302
8+
advertise_uri: localhost:13302
9+
http_port: 18082
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
cartridge = require('cartridge')
2+
replicasets = {{
3+
alias = 'router-fixedport',
4+
roles = {'vshard-router', 'app.roles.custom', 'app.roles.api_router'},
5+
join_servers = {{uri = 'localhost:13301'}}
6+
}, {
7+
alias = 'storage-fixedport',
8+
roles = {'vshard-storage', 'app.roles.api_storage'},
9+
join_servers = {{uri = 'localhost:13302'}}
10+
}}
11+
return cartridge.admin_edit_topology({replicasets = replicasets})

0 commit comments

Comments
 (0)