Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
http://HostIpAddress:Port (Given IP not leading to the authEndpoint)
... leads to a connection.
Needed solution for:
bookingEndpoint.withEnv("AUTH_URL", authEndpointBaseURL);
=== Third ===
Executing the JARs without Testcontainers locally -> works as a charm, just as in gitlab pipeline
`
// Static definitions which are lifted before all tests
// Define the NATS & MySql
@ClassRule
public static GenericContainer<?> natsContainer =
new GenericContainer<>(
DockerImageName.parse("nats:alpine3.19"))
.withExposedPorts(4222) // Default MQTT port
.withNetwork(network)
.withNetworkAliases("natsmb")
.waitingFor(Wait.forListeningPort());
@ClassRule
public static MySQLContainer<?> mysqlContainer =
new MySQLContainer<>("mysql:8.2")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test")
// Adjust the service network
.withNetwork(network)
.withNetworkAliases("mysqldb");
// Define the container for the AuthEndpoint using the built image
@ClassRule
public static GenericContainer<?> authEndpoint =
new GenericContainer<>(authEndpointDockerImage)
.withExposedPorts(authEndpointPort)
// Adjust the service network
.withNetwork(network)
.withNetworkAliases("authEndpoint")
// Adjust the 'infrastructure'-connections
.withEnv("DB_URL", "jdbc:mysql://mysqldb:3306/testdb")
.withEnv("DB_USERNAME", "test")
.withEnv("DB_PASSWORD", "test")
.withEnv("NATS_URL", "nats://natsmb:4222")
.withEnv("INSTANCE_INDICATOR", "AUTH")
.withEnv("INITIAL_DELAY", "130000")
.withEnv("FIXED_INTERVAL", "12000000")
// Add a wait strategy for the AuthEndpoint, ensuring the mysqlContainer is up first
.dependsOn(mysqlContainer, mysqlContainer)
// AuthEndpoint is ready => actuator is open for connection:
.waitingFor(Wait.forHttp("/actuator").forStatusCode(200));
// Define the container for BookingEndpoint using the built image
@ClassRule
public static GenericContainer<?> bookingEndpoint =
new GenericContainer<>(bookingEndpointDockerImage)
.withExposedPorts(bookingEndpointPort)
// Adjust the service network
.withNetwork(network)
.withNetworkAliases("bookingEndpoint")
// Adjust the 'infrastructure'-connections
.withEnv("DB_URL", "jdbc:mysql://mysqldb:3306/testdb")
.withEnv("DB_USERNAME", "test")
.withEnv("DB_PASSWORD", "test")
.withEnv("NATS_URL", "nats://natsmb:4222")
.withEnv("INSTANCE_INDICATOR", "BOOKING")
.withEnv("AUTH_URL", "")
.withEnv("INITIAL_DELAY", "1000")
.withEnv("FIXED_INTERVAL", "5000")
// Add a wait strategy for the BookingEndpoint, ensuring the AuthEndpoint is up first
.dependsOn(authEndpoint)
// BookingEndpoint is ready => actuator is open for connection:
.waitingFor(Wait.forHttp("/actuator").forStatusCode(200));
static {
OffsetDateTime start = OffsetDateTime.now();
logger.info(String.format("Setup start at: %s", start));
logger.info("==============================================");
logger.info("===== Starting the message broker =====");
logger.info("==============================================");
// Start the message broker
natsContainer.start();
// === Set system properties ===
// --> MessageQueue
String natsURL = String.format("nats://%s:%s",
natsContainer.getHost(),
natsContainer.getMappedPort(4222));
System.setProperty("NATS_URL", natsURL);
// Start the database
logger.info("==============================================");
logger.info("===== Starting the database =====");
logger.info("==============================================");
mysqlContainer.start();
// === Set system properties ===
// --> Database
System.setProperty("DB_URL", mysqlContainer.getJdbcUrl());
System.setProperty("DB_USERNAME", mysqlContainer.getUsername());
System.setProperty("DB_PASSWORD", mysqlContainer.getPassword());
// Start the AuthEndpoint
logger.info("==============================================");
logger.info("===== Starting the Auth-Endpoint =====");
logger.info("==============================================");
authEndpoint.start();
authEndpointBaseURL =
"http://" + getHostIp(authEndpoint) + ":" + authEndpoint.getMappedPort(authEndpointPort);
// authEndpointBaseURL2 = "http://authEndpoint:" + authEndpoint.getMappedPort(authEndpointPort);
bookingEndpoint.withEnv("AUTH_URL", authEndpointBaseURL);
logger.info("AuthUrl given to BookingEndpoint definition via ENV: " + authEndpointBaseURL);
bookingEndpoint.start();
// === Set general system properties ===
System.setProperty("INSTANCE_INDICATOR", "VALIDATOR");
Duration duration = Duration.between(start, OffsetDateTime.now());
logger.info(String.format("Setup took %s seconds", duration.getSeconds()));
// Known startup duration is ~30 seconds locally and ~60 seconds in pipeline.
// It shall be known if Environment startup-time drastically changes.
// assertTrue(duration.getSeconds() < 90);
}
private static String getHostIp(GenericContainer<?> authEndpoint) {
if (authEndpoint.getHost().equals("localhost")) {
try {
// Get IP from Host-Machine
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
return authEndpoint.getHost();
}
Module
Core
Testcontainers version
1.19.8
Using the latest Testcontainers version?
Yes
Host OS
MacOS
Host Arch
ARM
Docker version
What happened?
=== First === Java code from the testcontainers library behaves differently.
Gitlab Pipeline with linux runner executes successfully
=== Second === The bookingEndpoint gets an IP that is not sufficient for connecting. Neither of the following ...
http://HostIpAddress:Port (Given IP not leading to the authEndpoint) ... leads to a connection. Needed solution for: bookingEndpoint.withEnv("AUTH_URL", authEndpointBaseURL);
=== Third === Executing the JARs without Testcontainers locally -> works as a charm, just as in gitlab pipeline
` // Static definitions which are lifted before all tests
`
Relevant log output
Custom Log Output:
Additional Information
https://stackoverflow.com/questions/78352477/testcontainers-container-gethost-is-behaving-differently-locally-vs-gitlab-pi