Skip to content

Commit eb9f540

Browse files
authored
Merge branch 'master' into combined-pr-branch
2 parents 8e5cf40 + 98b60fb commit eb9f540

File tree

18 files changed

+360
-146
lines changed

18 files changed

+360
-146
lines changed

core/build.gradle

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,8 @@ tasks.japicmp {
4343
classExcludes = []
4444

4545
methodExcludes = [
46-
"org.testcontainers.utility.ResourceReaper#start(java.lang.String,com.github.dockerjava.api.DockerClient)",
47-
"org.testcontainers.utility.ResourceReaper#start(com.github.dockerjava.api.DockerClient)",
48-
"org.testcontainers.utility.ResourceReaper#registerNetworkForCleanup(java.lang.String)",
49-
"org.testcontainers.utility.ResourceReaper#removeNetworks(java.lang.String)",
50-
"org.testcontainers.images.builder.Transferable#of(java.lang.String)",
51-
"org.testcontainers.images.builder.Transferable#updateChecksum(java.util.zip.Checksum)"
46+
"org.testcontainers.containers.Container#getDockerClient()",
47+
"org.testcontainers.containers.ContainerState#getDockerClient()",
5248
]
5349

5450
fieldExcludes = []

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package org.testcontainers.containers;
22

3+
import com.github.dockerjava.api.DockerClient;
34
import com.github.dockerjava.api.command.InspectContainerResponse;
45
import com.github.dockerjava.api.model.Container;
56
import lombok.EqualsAndHashCode;
67
import lombok.Getter;
78
import lombok.NonNull;
8-
import org.testcontainers.DockerClientFactory;
99
import org.testcontainers.containers.wait.strategy.WaitStrategyTarget;
1010

1111
import java.util.ArrayList;
@@ -22,13 +22,15 @@ class ComposeServiceWaitStrategyTarget implements WaitStrategyTarget {
2222

2323
private final Container container;
2424
private final GenericContainer proxyContainer;
25+
private final DockerClient dockerClient;
2526
@NonNull
2627
private Map<Integer, Integer> mappedPorts;
2728
@Getter(lazy=true)
28-
private final InspectContainerResponse containerInfo = DockerClientFactory.instance().client().inspectContainerCmd(getContainerId()).exec();
29+
private final InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(getContainerId()).exec();
2930

30-
ComposeServiceWaitStrategyTarget(Container container, GenericContainer proxyContainer,
31+
ComposeServiceWaitStrategyTarget(DockerClient dockerClient, Container container, GenericContainer proxyContainer,
3132
@NonNull Map<Integer, Integer> mappedPorts) {
33+
this.dockerClient = dockerClient;
3234
this.container = container;
3335
this.proxyContainer = proxyContainer;
3436
this.mappedPorts = new HashMap<>(mappedPorts);

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ default SELF withClasspathResourceMapping(final String resourcePath, final Strin
389389
* @param consumer consumer that the frames should be sent to
390390
*/
391391
default void followOutput(Consumer<OutputFrame> consumer) {
392-
LogUtils.followOutput(DockerClientFactory.instance().client(), getContainerId(), consumer);
392+
LogUtils.followOutput(getDockerClient(), getContainerId(), consumer);
393393
}
394394

395395
/**
@@ -400,7 +400,7 @@ default void followOutput(Consumer<OutputFrame> consumer) {
400400
* @param types types that should be followed (one or both of STDOUT, STDERR)
401401
*/
402402
default void followOutput(Consumer<OutputFrame> consumer, OutputFrame.OutputType... types) {
403-
LogUtils.followOutput(DockerClientFactory.instance().client(), getContainerId(), consumer, types);
403+
LogUtils.followOutput(getDockerClient(), getContainerId(), consumer, types);
404404
}
405405

406406

@@ -439,8 +439,6 @@ default void followOutput(Consumer<OutputFrame> consumer, OutputFrame.OutputType
439439
@Deprecated
440440
Map<String, LinkableContainer> getLinkedContainers();
441441

442-
DockerClient getDockerClient();
443-
444442
void setExposedPorts(List<Integer> exposedPorts);
445443

446444
void setPortBindings(List<String> portBindings);

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ default String getContainerIpAddress() {
5252
return getHost();
5353
}
5454

55+
default DockerClient getDockerClient() {
56+
return DockerClientFactory.lazyClient();
57+
}
58+
5559
/**
5660
* Get the host that this container may be reached on (may not be the local machine).
5761
*
@@ -115,7 +119,7 @@ default boolean isHealthy() {
115119
}
116120

117121
default InspectContainerResponse getCurrentContainerInfo() {
118-
return DockerClientFactory.instance().client().inspectContainerCmd(getContainerId()).exec();
122+
return getDockerClient().inspectContainerCmd(getContainerId()).exec();
119123
}
120124

121125
/**
@@ -195,15 +199,15 @@ default List<Integer> getBoundPortNumbers() {
195199
* @return all log output from the container from start until the current instant (both stdout and stderr)
196200
*/
197201
default String getLogs() {
198-
return LogUtils.getOutput(DockerClientFactory.instance().client(), getContainerId());
202+
return LogUtils.getOutput(getDockerClient(), getContainerId());
199203
}
200204

201205
/**
202206
* @param types log types to return
203207
* @return all log output from the container from start until the current instant
204208
*/
205209
default String getLogs(OutputFrame.OutputType... types) {
206-
return LogUtils.getOutput(DockerClientFactory.instance().client(), getContainerId(), types);
210+
return LogUtils.getOutput(getDockerClient(), getContainerId(), types);
207211
}
208212

209213
/**
@@ -234,7 +238,7 @@ default Container.ExecResult execInContainer(String... command) throws Unsupport
234238
* @see ExecInContainerPattern#execInContainer(com.github.dockerjava.api.command.InspectContainerResponse, Charset, String...)
235239
*/
236240
default Container.ExecResult execInContainer(Charset outputCharset, String... command) throws UnsupportedOperationException, IOException, InterruptedException {
237-
return ExecInContainerPattern.execInContainer(getContainerInfo(), outputCharset, command);
241+
return ExecInContainerPattern.execInContainer(getDockerClient(), getContainerInfo(), outputCharset, command);
238242
}
239243

240244
/**
@@ -279,7 +283,7 @@ default void copyFileToContainer(Transferable transferable, String containerPath
279283
transferable.transferTo(tarArchive, containerPath);
280284
tarArchive.finish();
281285

282-
DockerClientFactory.instance().client()
286+
getDockerClient()
283287
.copyArchiveToContainerCmd(getContainerId())
284288
.withTarInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()))
285289
.withRemotePath("/")
@@ -316,7 +320,7 @@ default <T> T copyFileFromContainer(String containerPath, ThrowingFunction<Inpu
316320
throw new IllegalStateException("copyFileFromContainer can only be used when the Container is created.");
317321
}
318322

319-
DockerClient dockerClient = DockerClientFactory.instance().client();
323+
DockerClient dockerClient = getDockerClient();
320324
try (
321325
InputStream inputStream = dockerClient.copyArchiveFromContainerCmd(getContainerId(), containerPath).exec();
322326
TarArchiveInputStream tarInputStream = new TarArchiveInputStream(inputStream)

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,14 @@ public DockerComposeContainer(String identifier, File... composeFiles) {
124124
}
125125

126126
public DockerComposeContainer(String identifier, List<File> composeFiles) {
127-
128127
this.composeFiles = composeFiles;
129128
this.dockerComposeFiles = new DockerComposeFiles(composeFiles);
130129

131130
// Use a unique identifier so that containers created for this compose environment can be identified
132131
this.identifier = identifier;
133132
this.project = randomProjectId();
134133

135-
this.dockerClient = DockerClientFactory.instance().client();
134+
this.dockerClient = DockerClientFactory.lazyClient();
136135
}
137136

138137
@Override
@@ -269,7 +268,7 @@ private void waitUntilServiceStarted() {
269268

270269
private void createServiceInstance(Container container) {
271270
String serviceName = getServiceNameFromContainer(container);
272-
final ComposeServiceWaitStrategyTarget containerInstance = new ComposeServiceWaitStrategyTarget(container,
271+
final ComposeServiceWaitStrategyTarget containerInstance = new ComposeServiceWaitStrategyTarget(dockerClient, container,
273272
ambassadorContainer, ambassadorPortMappings.getOrDefault(serviceName, new HashMap<>()));
274273

275274
String containerId = containerInstance.getContainerId();
@@ -559,7 +558,7 @@ public Optional<ContainerState> getContainerByServiceName(String serviceName) {
559558
}
560559

561560
private void followLogs(String containerId, Consumer<OutputFrame> consumer) {
562-
LogUtils.followOutput(DockerClientFactory.instance().client(), containerId, consumer);
561+
LogUtils.followOutput(dockerClient, containerId, consumer);
563562
}
564563

565564
private SELF self() {
@@ -659,7 +658,7 @@ public void invoke() {
659658

660659
AuditLogger.doComposeLog(this.getCommandParts(), this.getEnv());
661660

662-
final Integer exitCode = this.dockerClient.inspectContainerCmd(getContainerId())
661+
final Integer exitCode = getDockerClient().inspectContainerCmd(getContainerId())
663662
.exec()
664663
.getState()
665664
.getExitCode();

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

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import java.io.IOException;
1616
import java.nio.charset.Charset;
17+
import java.nio.charset.StandardCharsets;
1718

1819
/**
1920
* Provides utility methods for executing commands in containers
@@ -22,24 +23,49 @@
2223
@Slf4j
2324
public class ExecInContainerPattern {
2425

26+
27+
/**
28+
*
29+
* @deprecated use {@link #execInContainer(DockerClient, InspectContainerResponse, String...)}
30+
*/
31+
@Deprecated
32+
public Container.ExecResult execInContainer(InspectContainerResponse containerInfo, String... command)
33+
throws UnsupportedOperationException, IOException, InterruptedException {
34+
DockerClient dockerClient = DockerClientFactory.instance().client();
35+
return execInContainer(dockerClient, containerInfo, command);
36+
}
37+
38+
/**
39+
*
40+
* @deprecated use {@link #execInContainer(DockerClient, InspectContainerResponse, Charset, String...)}
41+
*/
42+
@Deprecated
43+
public Container.ExecResult execInContainer(InspectContainerResponse containerInfo, Charset outputCharset, String... command)
44+
throws UnsupportedOperationException, IOException, InterruptedException {
45+
DockerClient dockerClient = DockerClientFactory.instance().client();
46+
return execInContainer(dockerClient, containerInfo, outputCharset, command);
47+
}
48+
2549
/**
2650
* Run a command inside a running container, as though using "docker exec", and interpreting
2751
* the output as UTF8.
2852
* <p></p>
53+
* @param dockerClient the {@link DockerClient}
2954
* @param containerInfo the container info
3055
* @param command the command to execute
31-
* @see #execInContainer(InspectContainerResponse, Charset, String...)
56+
* @see #execInContainer(DockerClient, InspectContainerResponse, Charset, String...)
3257
*/
33-
public Container.ExecResult execInContainer(InspectContainerResponse containerInfo, String... command)
58+
public Container.ExecResult execInContainer(DockerClient dockerClient, InspectContainerResponse containerInfo, String... command)
3459
throws UnsupportedOperationException, IOException, InterruptedException {
35-
return execInContainer(containerInfo, Charset.forName("UTF-8"), command);
60+
return execInContainer(dockerClient, containerInfo, StandardCharsets.UTF_8, command);
3661
}
3762

3863
/**
3964
* Run a command inside a running container, as though using "docker exec".
4065
* <p>
4166
* This functionality is not available on a docker daemon running the older "lxc" execution driver. At
4267
* the time of writing, CircleCI was using this driver.
68+
* @param dockerClient the {@link DockerClient}
4369
* @param containerInfo the container info
4470
* @param outputCharset the character set used to interpret the output.
4571
* @param command the parts of the command to run
@@ -48,7 +74,7 @@ public Container.ExecResult execInContainer(InspectContainerResponse containerIn
4874
* @throws InterruptedException if the thread waiting for the response is interrupted
4975
* @throws UnsupportedOperationException if the docker daemon you're connecting to doesn't support "exec".
5076
*/
51-
public Container.ExecResult execInContainer(InspectContainerResponse containerInfo, Charset outputCharset, String... command)
77+
public Container.ExecResult execInContainer(DockerClient dockerClient, InspectContainerResponse containerInfo, Charset outputCharset, String... command)
5278
throws UnsupportedOperationException, IOException, InterruptedException {
5379
if (!TestEnvironment.dockerExecutionDriverSupportsExec()) {
5480
// at time of writing, this is the expected result in CircleCI.
@@ -64,8 +90,6 @@ public Container.ExecResult execInContainer(InspectContainerResponse containerIn
6490
String containerId = containerInfo.getId();
6591
String containerName = containerInfo.getName();
6692

67-
DockerClient dockerClient = DockerClientFactory.instance().client();
68-
6993
log.debug("{}: Running \"exec\" command: {}", containerName, String.join(" ", command));
7094
final ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(containerId)
7195
.withAttachStdout(true).withAttachStderr(true).withCmd(command).exec();

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ private void tryStart(Instant startedAt) {
416416

417417
if (!reusable) {
418418
//noinspection deprecation
419-
createCommand.getLabels().putAll(ResourceReaper.instance().getLabels());
419+
createCommand = ResourceReaper.instance().register(this, createCommand);
420420
}
421421

422422
if (!reused) {
@@ -469,7 +469,7 @@ private void tryStart(Instant startedAt) {
469469
containerIsStarting(containerInfo, reused);
470470

471471
// Wait until the container has reached the desired running state
472-
if (!this.startupCheckStrategy.waitUntilStartupSuccessful(dockerClient, containerId)) {
472+
if (!this.startupCheckStrategy.waitUntilStartupSuccessful(this)) {
473473
// Bail out, don't wait for the port to start listening.
474474
// (Exception thrown here will be caught below and wrapped)
475475
throw new IllegalStateException("Container did not start correctly.");

core/src/main/java/org/testcontainers/containers/startupcheck/IsRunningStartupCheckStrategy.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.github.dockerjava.api.DockerClient;
44
import com.github.dockerjava.api.command.InspectContainerResponse;
5+
import org.testcontainers.containers.GenericContainer;
56
import org.testcontainers.utility.DockerStatus;
67

78
/**
@@ -10,10 +11,24 @@
1011
*/
1112
public class IsRunningStartupCheckStrategy extends StartupCheckStrategy {
1213

14+
@SuppressWarnings("deprecation")
15+
@Override
16+
public boolean waitUntilStartupSuccessful(GenericContainer<?> container) {
17+
// Optimization: container already has the initial "after start" state, check it first
18+
if (checkState(container.getContainerInfo().getState()) == StartupStatus.SUCCESSFUL) {
19+
return true;
20+
}
21+
return super.waitUntilStartupSuccessful(container);
22+
}
23+
1324
@Override
1425
public StartupStatus checkStartupState(DockerClient dockerClient, String containerId) {
1526
InspectContainerResponse.ContainerState state = getCurrentState(dockerClient, containerId);
16-
if (state.getRunning()) {
27+
return checkState(state);
28+
}
29+
30+
private StartupStatus checkState(InspectContainerResponse.ContainerState state) {
31+
if (Boolean.TRUE.equals(state.getRunning())) {
1732
return StartupStatus.SUCCESSFUL;
1833
} else if (!DockerStatus.isContainerExitCodeSuccess(state)) {
1934
return StartupStatus.FAILED;

core/src/main/java/org/testcontainers/containers/startupcheck/StartupCheckStrategy.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.rnorth.ducttape.ratelimits.RateLimiter;
66
import org.rnorth.ducttape.ratelimits.RateLimiterBuilder;
77
import org.rnorth.ducttape.unreliables.Unreliables;
8+
import org.testcontainers.containers.GenericContainer;
89

910
import java.time.Duration;
1011
import java.util.concurrent.TimeUnit;
@@ -30,6 +31,15 @@ public <SELF extends StartupCheckStrategy> SELF withTimeout(Duration timeout) {
3031
return (SELF) this;
3132
}
3233

34+
/**
35+
*
36+
* @deprecated internal API
37+
*/
38+
@Deprecated
39+
public boolean waitUntilStartupSuccessful(GenericContainer<?> container) {
40+
return waitUntilStartupSuccessful(container.getDockerClient(), container.getContainerId());
41+
}
42+
3343
public boolean waitUntilStartupSuccessful(DockerClient dockerClient, String containerId) {
3444
final Boolean[] startedOK = {null};
3545
Unreliables.retryUntilTrue((int) timeout.toMillis(), TimeUnit.MILLISECONDS, () -> {

core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public Boolean call() {
4040

4141
Instant before = Instant.now();
4242
try {
43-
ExecResult result = ExecInContainerPattern.execInContainer(waitStrategyTarget.getContainerInfo(), "/bin/sh", "-c", command.toString());
43+
ExecResult result = ExecInContainerPattern.execInContainer(waitStrategyTarget.getDockerClient(), waitStrategyTarget.getContainerInfo(), "/bin/sh", "-c", command.toString());
4444
log.trace("Check for {} took {}. Result code '{}', stdout message: '{}'", internalPorts, Duration.between(before, Instant.now()), result.getExitCode(), result.getStdout());
4545
int exitCode = result.getExitCode();
4646
if (exitCode != 0 && exitCode != 1) {

0 commit comments

Comments
 (0)