Reputation: 515
Testcontainers container.getHost()
behaves differently in maven lifecycle step and GitLab CI-Pipeline.
container.getHost()
is replaced with localhost
container.getHost()
is replaced with the actual HostIP
Used:
Versions:
Although RestClient it considered state of the art compared to RestTemplate (spring.io: April 2024) ...
... the two are giving different error feedback (as follows).
Assume 3 java Microservices in a Junit-Testcontainers setup like:
Container1 <- Container2 <- Validator
Container2
needs Container1
and a Validator lifts both in an Junit-Testcontainers environment, watching its communication.
Validator is not a live system, just an integrationtest-system.
Accordingly:
Container1
is startedContainer1's
port is written into Container2's
env.Container2
is started.Container2
tries to contact Container1's
actuator endpoint. // Create a common network for all containers
@ClassRule
public static Network network = Network.newNetwork();
@ClassRule
public static GenericContainer<?> C1 =
new GenericContainer<>(C1DockerImage)
.withExposedPorts(C1Port)
.withNetwork(network)
.withNetworkAliases("C1")
@ClassRule
public static GenericContainer<?> C2 =
new GenericContainer<>(C2DockerImage)
.withExposedPorts(C2Port)
.withNetwork(network)
.withNetworkAliases("C2")
static {
// Start C1
C1.start();
C1BaseURL = "http://" + C1.getHost() + ":" + C1.getMappedPort(C1Port);
// Start C2
C2.withEnv("C1_URL", C1BaseURL);
C2.start();
logger.info("C1-Url given to C2 via ENV-Variable: " + C1BaseURL);
}
Accordingly:
http://localhost:51059
51059
is the host-system's port, which is mapping to C1's exposed port
.So far -> so good :)
Three (3) environments are distinguished:
Here a Testcontainers environment is started with C1 inside.
Be aware, C2 is running in IntelliJ Maven Test livecycle
Hence, C2 is not in an explicit Docker-Container.
C1's exposed port is wrapped by testcontainers and the proxy-port it given to C2.
C2 connects and everything is fine.
It works like a charm
- just as expected.
Next, the Validator
runs its IntelliJ Maven Test livecycle
.
Hence, C2 is now inside an explicit Docker-Container.
The URL given to C2 remains a pointer to http://localhost:TestcontainersProxyPortToC1
.
Assumption:
The assumption is fulfilled:
Connection refused
null
Within the GitLab CI-pipeline using the same Repository, the same Java-code, reproducable ...
http://HostIP:TestcontainersProxyPortToC1
The same code succeeds in the GitLab CI-Pipeline because localhost
is replaced with the actual machines HostIP
.
My assumption is that both ..
.. have to behave in the same manner. Both C2-containers shall succeed or fail connecting via one of ..
http://localhost:TestcontainersProxyPortToC1
http://HostIP:TestcontainersProxyPortToC1
Is there annother Testcontainers-command, which always resolves the HostIP-Address?
Any help is appreciated :)
Upvotes: 1
Views: 384
Reputation: 515
Is there annother Testcontainers-command, which always resolves the HostIP-Address?
AFAIK there is no such 'Testcontainers-command' ...
Divergent behaviour on C1.getHost()
remains (April 2024).
There is no clue, how C1.getHost()
determines when which answer has to be delivered.
The localhost's IP is LOCALLY always the Testcontainers HostIP.
But in the GitLab Ci-Pipeline the IP differs from the HostIP. Hence C1's IP is for GitLab always a DIFFERENT HostIP in contrast to the runner.
Consequently the following changes in previously given code have to be made:
C1BaseURL =
"http://" + getHostIp(C1) + ":" + C1.getMappedPort(C1Port);
The custom function looks likt this:
private static String getHostIp(GenericContainer<?> C1) {
if (C1.getHost().equals("localhost")) {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
return C1.getHost();
}
You may need to dig deeper: Getting the IP address of the current machine using Java
Upvotes: 1