Skip to content

Commit eb5eb8a

Browse files
authored
Add TestcontainersHostPropertyClientStrategy (#7053)
New strategy to use `tc.host` in `~/.testcontainers.properties` to try and connect to docker. This strategy ensure that user-defined variables such as `DOCKER_HOST`, `TESTCONTAINERS_HOST_OVERRIDE` and `TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE` do not have an effect. This strategy takes precedence over other strategies.
1 parent fc770df commit eb5eb8a

File tree

7 files changed

+168
-19
lines changed

7 files changed

+168
-19
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,11 @@ public TransportConfig getTransportConfig() {
158158

159159
@UnstableAPI
160160
public String getRemoteDockerUnixSocketPath() {
161-
String dockerSocketOverride = System.getenv("TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE");
162-
if (!StringUtils.isBlank(dockerSocketOverride)) {
163-
return dockerSocketOverride;
161+
if (this.strategy != null && this.strategy.allowUserOverrides()) {
162+
String dockerSocketOverride = System.getenv("TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE");
163+
if (!StringUtils.isBlank(dockerSocketOverride)) {
164+
return dockerSocketOverride;
165+
}
164166
}
165167

166168
URI dockerHost = getTransportConfig().getDockerHost();

core/src/main/java/org/testcontainers/dockerclient/DockerClientProviderStrategy.java

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@
5757

5858
/**
5959
* Mechanism to find a viable Docker client configuration according to the host system environment.
60+
* <p>
61+
* The order is:
62+
* <ul>
63+
* <li>{@code TestcontainersHostPropertyClientProviderStrategy}</li>
64+
* <li>{@code EnvironmentAndSystemPropertyClientProviderStrategy}</li>
65+
* <li>Persistable {@code DockerClientProviderStrategy} in <code>~/.testcontainers.properties</code></li>
66+
* <li>Other strategies order by priority</li>
67+
* </ul>
6068
*/
6169
@Slf4j
6270
public abstract class DockerClientProviderStrategy {
@@ -90,6 +98,10 @@ protected boolean isPersistable() {
9098
return true;
9199
}
92100

101+
public boolean allowUserOverrides() {
102+
return true;
103+
}
104+
93105
/**
94106
* @return highest to lowest priority value
95107
*/
@@ -217,7 +229,8 @@ public static DockerClientProviderStrategy getFirstValidStrategy(List<DockerClie
217229
List<String> configurationFailures = new ArrayList<>();
218230
List<DockerClientProviderStrategy> allStrategies = new ArrayList<>();
219231

220-
// The environment has the highest priority
232+
// Manually enforce priority independent of priority property of strategy
233+
allStrategies.add(new TestcontainersHostPropertyClientProviderStrategy());
221234
allStrategies.add(new EnvironmentAndSystemPropertyClientProviderStrategy());
222235

223236
// Next strategy to try out is the one configured using the Testcontainers configuration mechanism
@@ -401,16 +414,23 @@ public static DockerClient getClientForConfig(TransportConfig transportConfig) {
401414

402415
public synchronized String getDockerHostIpAddress() {
403416
if (dockerHostIpAddress == null) {
404-
dockerHostIpAddress = resolveDockerHostIpAddress(getDockerClient(), getTransportConfig().getDockerHost());
417+
dockerHostIpAddress =
418+
resolveDockerHostIpAddress(
419+
getDockerClient(),
420+
getTransportConfig().getDockerHost(),
421+
allowUserOverrides()
422+
);
405423
}
406424
return dockerHostIpAddress;
407425
}
408426

409427
@VisibleForTesting
410-
static String resolveDockerHostIpAddress(DockerClient client, URI dockerHost) {
411-
String hostOverride = System.getenv("TESTCONTAINERS_HOST_OVERRIDE");
412-
if (!StringUtils.isBlank(hostOverride)) {
413-
return hostOverride;
428+
static String resolveDockerHostIpAddress(DockerClient client, URI dockerHost, boolean allowUserOverrides) {
429+
if (allowUserOverrides) {
430+
String hostOverride = System.getenv("TESTCONTAINERS_HOST_OVERRIDE");
431+
if (!StringUtils.isBlank(hostOverride)) {
432+
return hostOverride;
433+
}
414434
}
415435

416436
switch (dockerHost.getScheme()) {
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.testcontainers.dockerclient;
2+
3+
import com.github.dockerjava.core.DefaultDockerClientConfig;
4+
import com.github.dockerjava.core.DockerClientConfig;
5+
import org.testcontainers.utility.TestcontainersConfiguration;
6+
7+
import java.util.Optional;
8+
9+
/**
10+
* Use <code>tc.host</code> in <code>~/.testcontainers.properties</code>
11+
* to try and locate a docker environment.
12+
*
13+
* @deprecated this class is used by the SPI and should not be used directly
14+
*/
15+
@Deprecated
16+
public final class TestcontainersHostPropertyClientProviderStrategy extends DockerClientProviderStrategy {
17+
18+
public static final int PRIORITY = EnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 10;
19+
20+
private final DockerClientConfig dockerClientConfig;
21+
22+
public TestcontainersHostPropertyClientProviderStrategy() {
23+
this(DefaultDockerClientConfig.createDefaultConfigBuilder());
24+
}
25+
26+
public TestcontainersHostPropertyClientProviderStrategy(DefaultDockerClientConfig.Builder configBuilder) {
27+
Optional<String> tcHost = Optional.ofNullable(
28+
TestcontainersConfiguration.getInstance().getUserProperty("tc.host", null)
29+
);
30+
31+
tcHost.ifPresent(configBuilder::withDockerHost);
32+
this.dockerClientConfig = configBuilder.build();
33+
}
34+
35+
@Override
36+
public String getDescription() {
37+
return "Testcontainers Host with tc.host=" + this.dockerClientConfig.getDockerHost();
38+
}
39+
40+
@Override
41+
public TransportConfig getTransportConfig() throws InvalidConfigurationException {
42+
return TransportConfig
43+
.builder()
44+
.dockerHost(dockerClientConfig.getDockerHost())
45+
.sslConfig(dockerClientConfig.getSSLConfig())
46+
.build();
47+
}
48+
49+
@Override
50+
protected int getPriority() {
51+
return PRIORITY;
52+
}
53+
54+
@Override
55+
protected boolean isPersistable() {
56+
return false;
57+
}
58+
59+
@Override
60+
public boolean allowUserOverrides() {
61+
return false;
62+
}
63+
}

core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -279,18 +279,16 @@ public String getEnvVarOrUserProperty(@NotNull final String propertyName, @Nulla
279279
}
280280

281281
/**
282-
* Gets a configured setting from an environment variable.
283-
* <p>
284-
* Note that when searching environment variables, the prefix `TESTCONTAINERS_` will usually be applied to the
285-
* property name, which will be converted to upper-case with underscore separators. This prefix will not be added
286-
* if the property name begins `docker.`.
282+
* Gets a configured setting from <code>~/.testcontainers.properties</code>.
287283
*
288284
* @param propertyName name of configuration file property (dot-separated lower case)
289285
* @return the found value, or null if not set
290286
*/
291287
@Contract("_, !null -> !null")
292288
public String getUserProperty(@NotNull final String propertyName, @Nullable final String defaultValue) {
293-
return getConfigurable(propertyName, defaultValue);
289+
return this.userProperties.get(propertyName) != null
290+
? (String) this.userProperties.get(propertyName)
291+
: defaultValue;
294292
}
295293

296294
/**

core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
org.testcontainers.dockerclient.TestcontainersHostPropertyClientProviderStrategy
12
org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy
23
org.testcontainers.dockerclient.UnixSocketClientProviderStrategy
34
org.testcontainers.dockerclient.DockerMachineClientProviderStrategy

core/src/test/java/org/testcontainers/dockerclient/DockerClientConfigUtilsTest.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ public void getDockerHostIpAddressShouldReturnLocalhostWhenUnixSocket() {
1919

2020
String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress(
2121
client,
22-
URI.create("unix:///var/run/docker.sock")
22+
URI.create("unix:///var/run/docker.sock"),
23+
true
2324
);
2425
assertThat(actual).isEqualTo("localhost");
2526
}
@@ -28,7 +29,8 @@ public void getDockerHostIpAddressShouldReturnLocalhostWhenUnixSocket() {
2829
public void getDockerHostIpAddressShouldReturnDockerHostIpWhenHttpsUri() {
2930
String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress(
3031
client,
31-
URI.create("http://12.23.34.45")
32+
URI.create("http://12.23.34.45"),
33+
true
3234
);
3335
assertThat(actual).isEqualTo("12.23.34.45");
3436
}
@@ -37,7 +39,8 @@ public void getDockerHostIpAddressShouldReturnDockerHostIpWhenHttpsUri() {
3739
public void getDockerHostIpAddressShouldReturnDockerHostIpWhenTcpUri() {
3840
String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress(
3941
client,
40-
URI.create("tcp://12.23.34.45")
42+
URI.create("tcp://12.23.34.45"),
43+
true
4144
);
4245
assertThat(actual).isEqualTo("12.23.34.45");
4346
}
@@ -46,7 +49,8 @@ public void getDockerHostIpAddressShouldReturnDockerHostIpWhenTcpUri() {
4649
public void getDockerHostIpAddressShouldReturnNullWhenUnsupportedUriScheme() {
4750
String actual = DockerClientProviderStrategy.resolveDockerHostIpAddress(
4851
client,
49-
URI.create("gopher://12.23.34.45")
52+
URI.create("gopher://12.23.34.45"),
53+
true
5054
);
5155
assertThat(actual).isNull();
5256
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package org.testcontainers.dockerclient;
2+
3+
import com.github.dockerjava.core.DefaultDockerClientConfig;
4+
import org.junit.Before;
5+
import org.junit.Rule;
6+
import org.junit.Test;
7+
import org.junit.runner.RunWith;
8+
import org.mockito.Mockito;
9+
import org.mockito.junit.MockitoJUnitRunner;
10+
import org.testcontainers.utility.MockTestcontainersConfigurationRule;
11+
import org.testcontainers.utility.TestcontainersConfiguration;
12+
13+
import java.net.URI;
14+
15+
import static org.assertj.core.api.Assertions.assertThat;
16+
import static org.mockito.ArgumentMatchers.eq;
17+
import static org.mockito.ArgumentMatchers.isNull;
18+
19+
@RunWith(MockitoJUnitRunner.class)
20+
public class TestcontainersHostPropertyClientProviderStrategyTest {
21+
22+
@Rule
23+
public MockTestcontainersConfigurationRule mockConfig = new MockTestcontainersConfigurationRule();
24+
25+
private URI defaultDockerHost;
26+
27+
private com.github.dockerjava.core.SSLConfig defaultSSLConfig;
28+
29+
@Before
30+
public void checkEnvironmentClear() {
31+
// If docker-java picks up non-default settings from the environment, our test needs to know to expect those
32+
DefaultDockerClientConfig defaultConfig = DefaultDockerClientConfig.createDefaultConfigBuilder().build();
33+
this.defaultDockerHost = defaultConfig.getDockerHost();
34+
this.defaultSSLConfig = defaultConfig.getSSLConfig();
35+
}
36+
37+
@Test
38+
public void tcHostPropertyIsProvided() {
39+
Mockito
40+
.doReturn("tcp://127.0.0.1:9000")
41+
.when(TestcontainersConfiguration.getInstance())
42+
.getUserProperty(eq("tc.host"), isNull());
43+
44+
TestcontainersHostPropertyClientProviderStrategy strategy = new TestcontainersHostPropertyClientProviderStrategy();
45+
46+
TransportConfig transportConfig = strategy.getTransportConfig();
47+
assertThat(transportConfig.getDockerHost().toString()).isEqualTo("tcp://127.0.0.1:9000");
48+
assertThat(transportConfig.getSslConfig()).isEqualTo(this.defaultSSLConfig);
49+
}
50+
51+
@Test
52+
public void tcHostPropertyIsNotProvided() {
53+
Mockito.doReturn(null).when(TestcontainersConfiguration.getInstance()).getUserProperty(eq("tc.host"), isNull());
54+
55+
TestcontainersHostPropertyClientProviderStrategy strategy = new TestcontainersHostPropertyClientProviderStrategy();
56+
57+
TransportConfig transportConfig = strategy.getTransportConfig();
58+
assertThat(transportConfig.getDockerHost()).isEqualTo(this.defaultDockerHost);
59+
assertThat(transportConfig.getSslConfig()).isEqualTo(this.defaultSSLConfig);
60+
}
61+
}

0 commit comments

Comments
 (0)