0

I'm writing integration tests using Testcontainers in a Spring Boot application. I am testing the user service, which calls the authentication service in order to encode the password when a user is created, and I'm trying to start two containers:

A postgres:17 database

A custom-built auth-service:latest container

The Postgres container starts correctly, executes init.sql, and works perfectly.

However, the auth-service container fails with this error:

Wait strategy failed. Container exited with code 1
Caused by: java.net.ConnectException: Connection refusedWaiting for URL: http://localhost:56873/auth/health
...
Timed out waiting for URL to be accessible (http://localhost:56873/auth/health should return HTTP [200])


@SpringBootTest(
        properties = {
                "logging.level.org.springframework.security=DEBUG",
        },
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
@TestPropertySource(properties = {
        "spring.jpa.hibernate.ddl-auto=create-drop",
})
class UserControllerIntegrationTests {

    static Network network = Network.newNetwork();

    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17")
            .withDatabaseName("testdb")
            .withUsername("testuser")
            .withPassword("testpass")
            .withNetwork(network)
            .withNetworkAliases("postgres-db");


    @Container
    static GenericContainer<?> authService = new GenericContainer<>("auth-service:latest")
            .withExposedPorts(8080)
            .withNetwork(network)
            .withNetworkAliases("auth-service")
            .waitingFor(Wait.forHttp("/auth/health")
                    .forStatusCode(200)
                    .withStartupTimeout(Duration.ofSeconds(20)));

    static {
        String initScriptPath = "./init.sql";
        try {
            MountableFile.forClasspathResource(initScriptPath);
            System.out.println("✅ Testcontainers: Found init script on classpath: " + initScriptPath);
            postgres.withInitScript(initScriptPath);
        } catch (IllegalArgumentException e) {
            System.err.println("❌ Testcontainers ERROR: Init script NOT found on classpath: " + initScriptPath);
            throw new RuntimeException("Failed to locate database initialization script.", e);
        }
    }

    @Autowired
    private TestRestTemplate restTemplate;

    @Value("${server.api.key}")
    private String apiKey;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private TestHelper httpTestHelper;

    @Autowired
    private JwtService jwtService;

    @Autowired
    private JwtAuthFilter jwtAuthFilter;

    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
        registry.add("api.services.auth-service", () ->
                "http://" + authService.getHost() + ":" + authService.getMappedPort(8080));
    }
1
  • I would suggest you use the Testcontainers support build into Spring Boot. But for now you probably should increase the timeout for the container as it tries to validate the startup but that apparently takes longer then the default timeout. Commented Jun 17 at 13:31

1 Answer 1

0

I'm not sure if it can help you fix your issue but I want to share with you.

Here are the steps you should follow step by step

1 ) Define Second Postgres container

2 ) Env-vars for Auth-Service pointing at that DB

3 ) Shared Network and withNetworkAliases

4 ) Increased health‐check timeout & validated path

5 ) Log dump in @BeforeAll

6 ) Dynamic property source unchanged except for adding the mapped Auth URL

Here is the full code shown below

@SpringBootTest(
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
    properties = {
        "logging.level.org.springframework.security=DEBUG"
    }
)
@Testcontainers
@TestPropertySource(properties = {
    "spring.jpa.hibernate.ddl-auto=create-drop"
})
public class UserControllerIntegrationTests {

    // Shared Docker network for containers
    static final Network network = Network.newNetwork();

    // 1) User Service DB
    @Container
    static PostgreSQLContainer<?> userDb = new PostgreSQLContainer<>("postgres:17")
        .withDatabaseName("testdb")
        .withUsername("testuser")
        .withPassword("testpass")
        .withNetwork(network)
        .withNetworkAliases("postgres-db")
        .withInitScript("init.sql");

    // 2) Auth Service DB
    @Container
    static PostgreSQLContainer<?> authDb = new PostgreSQLContainer<>("postgres:17")
        .withDatabaseName("authdb")
        .withUsername("authuser")
        .withPassword("authpass")
        .withNetwork(network)
        .withNetworkAliases("auth-db");

    // 3) Auth Service
    @Container
    static GenericContainer<?> authService = new GenericContainer<>("auth-service:latest")
        .withNetwork(network)
        .withNetworkAliases("auth-service")
        .withEnv("SPRING_DATASOURCE_URL", "jdbc:postgresql://auth-db:5432/authdb")
        .withEnv("SPRING_DATASOURCE_USERNAME", "authuser")
        .withEnv("SPRING_DATASOURCE_PASSWORD", "authpass")
        .withExposedPorts(8080)
        .waitingFor(Wait.forHttp("/auth/health").forStatusCode(200).withStartupTimeout(Duration.ofSeconds(60)));

    @Autowired
    private TestRestTemplate restTemplate;

    @Value("${server.api.key}")
    private String apiKey;

    // Add your repositories, services, helpers as needed
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private HttpTestHelper httpTestHelper;

    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", userDb::getJdbcUrl);
        registry.add("spring.datasource.username", userDb::getUsername);
        registry.add("spring.datasource.password", userDb::getPassword);
        registry.add("api.services.auth-service", () ->
            "http://" + authService.getHost() + ":" + authService.getMappedPort(8080)
        );
    }

    @BeforeAll
    static void dumpAuthLogs() {
        System.out.println("=== AUTH SERVICE LOGS ===");
        System.out.println(authService.getLogs());
    }

    @Test
    void testCreateUserEncodedPassword() {
        // Your test implementation here
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for your reply. I used your code and encountered an issue where the test tries to pull the images from dockerhub, although I have the images up, in my Docker Desktop. Do you know what goes wrong here?
@RazvanAnghel I'm sorry I have no idea about it.
it turns out there was a naming mismatch between my local docker container and the container name in the test. Now it is fixed and your solution works. Many thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.