Skip to content

Commit 1362e82

Browse files
author
Nikita Salnikov-Tarnovski
committed
Merge remote-tracking branch 'upstream/master' into issue-374
2 parents af7847b + d7551de commit 1362e82

File tree

25 files changed

+728
-178
lines changed

25 files changed

+728
-178
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@ All notable changes to this project will be documented in this file.
33

44
### Fixed
55
- Fixed retrieval of Docker host IP when running inside Docker. ([\#479](https://github.com/testcontainers/testcontainers-java/issues/479))
6+
- Fixed overriding MySQL image command. ([\#534](https://github.com/testcontainers/testcontainers-java/issues/534))
67

78
### Changed
9+
- Added Kafka module ([\#546](https://github.com/testcontainers/testcontainers-java/pull/546))
10+
- Added "Death Note" to track & kill spawned containers even if the JVM was "kill -9"ed ([\#545](https://github.com/testcontainers/testcontainers-java/pull/545))
11+
- Environment variables are now stored as Map instead of List ([\#550](https://github.com/testcontainers/testcontainers-java/pull/550))
12+
- Added `withEnv(String name, Function<Optional<String>, String> mapper)` with optional previous value ([\#550](https://github.com/testcontainers/testcontainers-java/pull/550))
13+
- Added `withFileSystemBind` overloaded method with `READ_WRITE` file mode by default ([\#550](https://github.com/testcontainers/testcontainers-java/pull/550))
814
- All connections to MySQL containers don't use SSL anymore. ([\#374](https://github.com/testcontainers/testcontainers-java/issues/374))
915

1016
## [1.5.1] - 2017-12-19

core/src/main/java/org/testcontainers/DockerClientFactory.java

Lines changed: 32 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,32 @@
22

33
import com.github.dockerjava.api.DockerClient;
44
import com.github.dockerjava.api.command.CreateContainerCmd;
5-
import com.github.dockerjava.api.command.InspectContainerResponse;
65
import com.github.dockerjava.api.exception.InternalServerErrorException;
76
import com.github.dockerjava.api.exception.NotFoundException;
87
import com.github.dockerjava.api.model.*;
98
import com.github.dockerjava.core.command.ExecStartResultCallback;
109
import com.github.dockerjava.core.command.PullImageResultCallback;
1110
import com.google.common.annotations.VisibleForTesting;
11+
import com.google.common.collect.ImmutableMap;
1212
import lombok.Synchronized;
1313
import lombok.extern.slf4j.Slf4j;
14-
import org.apache.commons.io.IOUtils;
1514
import org.hamcrest.BaseMatcher;
1615
import org.hamcrest.Description;
17-
import org.rnorth.ducttape.unreliables.Unreliables;
1816
import org.rnorth.visibleassertions.VisibleAssertions;
19-
import org.testcontainers.dockerclient.*;
17+
import org.testcontainers.dockerclient.DockerClientProviderStrategy;
18+
import org.testcontainers.dockerclient.DockerMachineClientProviderStrategy;
2019
import org.testcontainers.utility.ComparableVersion;
21-
import org.testcontainers.utility.MountableFile;
20+
import org.testcontainers.utility.ResourceReaper;
2221
import org.testcontainers.utility.TestcontainersConfiguration;
2322

2423
import java.io.ByteArrayOutputStream;
25-
import java.io.IOException;
2624
import java.io.InputStream;
27-
import java.net.Socket;
28-
import java.nio.charset.Charset;
2925
import java.util.ArrayList;
3026
import java.util.List;
27+
import java.util.Map;
3128
import java.util.Optional;
3229
import java.util.ServiceLoader;
33-
import java.util.concurrent.TimeUnit;
30+
import java.util.UUID;
3431
import java.util.function.BiFunction;
3532
import java.util.function.Consumer;
3633

@@ -42,12 +39,22 @@
4239
@Slf4j
4340
public class DockerClientFactory {
4441

42+
public static final String TESTCONTAINERS_LABEL = DockerClientFactory.class.getPackage().getName();
43+
public static final String TESTCONTAINERS_SESSION_ID_LABEL = TESTCONTAINERS_LABEL + ".sessionId";
44+
45+
public static final String SESSION_ID = UUID.randomUUID().toString();
46+
47+
public static final Map<String, String> DEFAULT_LABELS = ImmutableMap.of(
48+
TESTCONTAINERS_LABEL, "true",
49+
TESTCONTAINERS_SESSION_ID_LABEL, SESSION_ID
50+
);
51+
4552
private static final String TINY_IMAGE = TestcontainersConfiguration.getInstance().getTinyImage();
4653
private static DockerClientFactory instance;
4754

4855
// Cached client configuration
4956
private DockerClientProviderStrategy strategy;
50-
private boolean preconditionsChecked = false;
57+
private boolean initialized = false;
5158
private String activeApiVersion;
5259
private String activeExecutionDriver;
5360

@@ -95,7 +102,7 @@ public DockerClient client() {
95102
log.info("Docker host IP address is {}", hostIpAddress);
96103
DockerClient client = strategy.getClient();
97104

98-
if (!preconditionsChecked) {
105+
if (!initialized) {
99106
Info dockerInfo = client.infoCmd().exec();
100107
Version version = client.versionCmd().exec();
101108
activeApiVersion = version.getApiVersion();
@@ -106,30 +113,19 @@ public DockerClient client() {
106113
" Operating System: " + dockerInfo.getOperatingSystem() + "\n" +
107114
" Total Memory: " + dockerInfo.getMemTotal() / (1024 * 1024) + " MB");
108115

109-
if (!TestcontainersConfiguration.getInstance().isDisableChecks()) {
110-
VisibleAssertions.info("Checking the system...");
111-
112-
checkDockerVersion(version.getVersion());
113-
114-
MountableFile mountableFile = MountableFile.forClasspathResource(this.getClass().getName().replace(".", "/") + ".class");
116+
String ryukContainerId = ResourceReaper.start(hostIpAddress, client);
117+
log.info("Ryuk started - will monitor and terminate Testcontainers containers on JVM exit");
115118

116-
runInsideDocker(
117-
client,
118-
cmd -> cmd
119-
.withCmd("/bin/sh", "-c", "while true; do printf 'hello' | nc -l -p 80; done")
120-
.withBinds(new Bind(mountableFile.getResolvedPath(), new Volume("/dummy"), AccessMode.ro))
121-
.withExposedPorts(new ExposedPort(80))
122-
.withPublishAllPorts(true),
123-
(dockerClient, id) -> {
119+
VisibleAssertions.info("Checking the system...");
124120

125-
checkDiskSpace(dockerClient, id);
126-
checkMountableFile(dockerClient, id);
127-
checkExposedPort(hostIpAddress, dockerClient, id);
121+
checkDockerVersion(version.getVersion());
128122

129-
return null;
130-
});
123+
if (!TestcontainersConfiguration.getInstance().isDisableChecks()) {
124+
checkDiskSpace(client, ryukContainerId);
125+
checkMountableFile(client, ryukContainerId);
131126
}
132-
preconditionsChecked = true;
127+
128+
initialized = true;
133129
}
134130

135131
return client;
@@ -178,26 +174,10 @@ private void checkMountableFile(DockerClient dockerClient, String id) {
178174
}
179175
}
180176

181-
private void checkExposedPort(String hostIpAddress, DockerClient dockerClient, String id) {
182-
String response = Unreliables.retryUntilSuccess(3, TimeUnit.SECONDS, () -> {
183-
InspectContainerResponse inspectedContainer = dockerClient.inspectContainerCmd(id).exec();
184-
185-
String portSpec = inspectedContainer.getNetworkSettings().getPorts().getBindings().values().iterator().next()[0].getHostPortSpec();
186-
187-
try (Socket socket = new Socket(hostIpAddress, Integer.parseInt(portSpec))) {
188-
return IOUtils.toString(socket.getInputStream(), Charset.defaultCharset());
189-
} catch (IOException e) {
190-
return e.getMessage();
191-
}
192-
});
193-
194-
VisibleAssertions.assertEquals("A port exposed by a docker container should be accessible", "hello", response);
195-
}
196-
197177
/**
198178
* Check whether the image is available locally and pull it otherwise
199179
*/
200-
private void checkAndPullImage(DockerClient client, String image) {
180+
public void checkAndPullImage(DockerClient client, String image) {
201181
List<Image> images = client.listImagesCmd().withImageNameFilter(image).exec();
202182
if (images.isEmpty()) {
203183
client.pullImageCmd(image).exec(new PullImageResultCallback()).awaitSuccess();
@@ -221,7 +201,8 @@ public <T> T runInsideDocker(Consumer<CreateContainerCmd> createContainerCmdCons
221201

222202
private <T> T runInsideDocker(DockerClient client, Consumer<CreateContainerCmd> createContainerCmdConsumer, BiFunction<DockerClient, String, T> block) {
223203
checkAndPullImage(client, TINY_IMAGE);
224-
CreateContainerCmd createContainerCmd = client.createContainerCmd(TINY_IMAGE);
204+
CreateContainerCmd createContainerCmd = client.createContainerCmd(TINY_IMAGE)
205+
.withLabels(DEFAULT_LABELS);
225206
createContainerCmdConsumer.accept(createContainerCmd);
226207
String id = createContainerCmd.exec().getId();
227208

@@ -263,7 +244,7 @@ DiskSpaceUsage parseAvailableDiskSpace(String dfOutput) {
263244
* @return the docker API version of the daemon that we have connected to
264245
*/
265246
public String getActiveApiVersion() {
266-
if (!preconditionsChecked) {
247+
if (!initialized) {
267248
client();
268249
}
269250
return activeApiVersion;
@@ -273,7 +254,7 @@ public String getActiveApiVersion() {
273254
* @return the docker execution driver of the daemon that we have connected to
274255
*/
275256
public String getActiveExecutionDriver() {
276-
if (!preconditionsChecked) {
257+
if (!initialized) {
277258
client();
278259
}
279260
return activeExecutionDriver;

core/src/main/java/org/testcontainers/containers/AmbassadorContainer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
* An ambassador container is used as a TCP proxy, enabling any TCP port of another linked container to be exposed
1616
* publicly, even if that container does not make the port public itself. The <code>richnorth/ambassador:latest</code>
1717
* container is used (based on HAProxy).
18+
*
19+
* @deprecated use {@link SocatContainer}
1820
*/
1921
@EqualsAndHashCode(callSuper = false)
2022
@Data
23+
@Deprecated
2124
public class AmbassadorContainer<SELF extends AmbassadorContainer<SELF>> extends GenericContainer<SELF> {
2225

2326
private final String otherContainerName;

core/src/main/java/org/testcontainers/containers/Container.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
import java.time.Duration;
1818
import java.util.List;
1919
import java.util.Map;
20+
import java.util.Optional;
2021
import java.util.concurrent.Future;
2122
import java.util.function.Consumer;
23+
import java.util.function.Function;
2224

2325
public interface Container<SELF extends Container<SELF>> extends LinkableContainer {
2426

@@ -135,6 +137,17 @@ default void addFileSystemBind(final String hostPath, final String containerPath
135137
*/
136138
SELF waitingFor(@NonNull WaitStrategy waitStrategy);
137139

140+
/**
141+
* Adds a file system binding.
142+
*
143+
* @param hostPath the file system path on the host
144+
* @param containerPath the file system path inside the container
145+
* @return this
146+
*/
147+
default SELF withFileSystemBind(String hostPath, String containerPath) {
148+
return withFileSystemBind(hostPath, containerPath, BindMode.READ_WRITE);
149+
}
150+
138151
/**
139152
* Adds a file system binding.
140153
*
@@ -171,6 +184,18 @@ default void addFileSystemBind(final String hostPath, final String containerPath
171184
*/
172185
SELF withEnv(String key, String value);
173186

187+
/**
188+
* Add an environment variable to be passed to the container.
189+
*
190+
* @param key environment variable key
191+
* @param mapper environment variable value mapper, accepts old value as an argument
192+
* @return this
193+
*/
194+
default SELF withEnv(String key, Function<Optional<String>, String> mapper) {
195+
Optional<String> oldValue = Optional.ofNullable(getEnvMap().get(key));
196+
return withEnv(key, mapper.apply(oldValue));
197+
}
198+
174199
/**
175200
* Add environment variables to be passed to the container.
176201
*
@@ -383,6 +408,11 @@ default Integer getFirstMappedPort() {
383408
*/
384409
SELF withLogConsumer(Consumer<OutputFrame> consumer);
385410

411+
/**
412+
*
413+
* @deprecated please use {@code org.testcontainers.DockerClientFactory.instance().client().infoCmd().exec()}
414+
*/
415+
@Deprecated
386416
Info fetchDockerDaemonInfo() throws IOException;
387417

388418
/**
@@ -438,8 +468,15 @@ ExecResult execInContainer(Charset outputCharset, String... command)
438468

439469
Future<String> getImage();
440470

471+
/**
472+
*
473+
* @deprecated use getEnvMap
474+
*/
475+
@Deprecated
441476
List<String> getEnv();
442477

478+
Map<String, String> getEnvMap();
479+
443480
String[] getCommandParts();
444481

445482
List<Bind> getBinds();
@@ -452,12 +489,22 @@ ExecResult execInContainer(Charset outputCharset, String... command)
452489

453490
DockerClient getDockerClient();
454491

492+
/**
493+
*
494+
* @deprecated please use {@code org.testcontainers.DockerClientFactory.instance().client().infoCmd().exec()}
495+
*/
496+
@Deprecated
455497
Info getDockerDaemonInfo();
456498

457499
String getContainerId();
458500

459501
String getContainerName();
460502

503+
/**
504+
*
505+
* @deprecated please use {@code org.testcontainers.DockerClientFactory.instance().client().inspectContainerCmd(container.getContainerId()).exec()}
506+
*/
507+
@Deprecated
461508
InspectContainerResponse getContainerInfo();
462509

463510
void setExposedPorts(List<Integer> exposedPorts);

0 commit comments

Comments
 (0)