From 2b8241c5bfdcdb2e3ba171146ba61c0665ab669f Mon Sep 17 00:00:00 2001 From: Bence Csik <22349790+csikb@users.noreply.github.com> Date: Sun, 5 Oct 2025 10:13:18 +0100 Subject: [PATCH 1/7] chore: integrate Testcontainers for automatic Docker Compose management in integration tests --- .github/workflows/gradle.yml | 1 - .../bssweb/config/DefaultFeignConfig.kt | 5 +- docker-compose.ci.yml | 8 ++-- integration/README.md | 28 +++++++++-- integration/build.gradle.kts | 3 ++ .../hu/bsstudio/bssweb/IntegrationTest.kt | 47 ++++++++++++++----- 6 files changed, 66 insertions(+), 26 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index f5320486..a208db6f 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -51,7 +51,6 @@ jobs: - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} - - run: docker compose -f docker-compose.yml --profile app up --wait --build - run: "./gradlew integrationTest --continue" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: diff --git a/client/src/main/kotlin/hu/bsstudio/bssweb/config/DefaultFeignConfig.kt b/client/src/main/kotlin/hu/bsstudio/bssweb/config/DefaultFeignConfig.kt index 9ff1b9c1..f000b010 100644 --- a/client/src/main/kotlin/hu/bsstudio/bssweb/config/DefaultFeignConfig.kt +++ b/client/src/main/kotlin/hu/bsstudio/bssweb/config/DefaultFeignConfig.kt @@ -6,10 +6,7 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @Configuration -class DefaultFeignConfig( - @param:Value("\${bss.client.username}") val username: String, - @param:Value("\${bss.client.password}") val password: String, -) { +class DefaultFeignConfig() { @Bean fun interceptor() = RequestInterceptor { template -> diff --git a/docker-compose.ci.yml b/docker-compose.ci.yml index 14615108..d07a7b6a 100644 --- a/docker-compose.ci.yml +++ b/docker-compose.ci.yml @@ -1,14 +1,14 @@ services: app: - ports: !override + ports: - "8080" postgres: - ports: !override + ports: - "5432" mock-file-api: - ports: !override + ports: - "8080" volumes: [] mock-oidc: - ports: !override + ports: - "5556" diff --git a/integration/README.md b/integration/README.md index 621cac06..451f1cba 100644 --- a/integration/README.md +++ b/integration/README.md @@ -4,15 +4,33 @@ It stores the integration tests for the application. To run the integration tests, you need to have Docker installed on your machine. -Testcontainers didn't have a clean way to start the compose file before all the tests. -So it's required to start the compose file manually before running the tests. -Each test will clear the database tables. +The integration tests now use **Testcontainers with Docker Compose** to automatically start and configure the required services from your existing `docker-compose.yml`: +- PostgreSQL database +- WireMock servers for external API mocking (file-api and OIDC) + +The Docker Compose services are automatically started before the tests run and stopped after completion. +Each test will clear the database tables to ensure test isolation. Each Integration test has to extend the `IntegrationTest` class. ```shell -docker compose up -d ./gradlew integrationTest -docker compose down ``` +## What's changed from manual Docker Compose + +- **Automatic lifecycle management**: Testcontainers automatically starts/stops your Docker Compose services +- **Dynamic port mapping**: Tests use the actual exposed ports from Docker Compose +- **Same service configuration**: Uses your existing `docker-compose.yml` exactly as configured +- **Isolated test environment**: Each test run gets fresh containers +- **No manual setup required**: No need to run `docker compose up/down` manually + +## Container Configuration + +The integration tests use your existing `docker-compose.yml` services: +- **PostgreSQL 16.3**: Exact same configuration as your compose file +- **WireMock 3.13.1**: File-api and OIDC mocks with the same stub mappings +- **Automatic cleanup**: All compose services are removed after test completion + +This approach ensures your integration tests run against the exact same service configuration as your development and production environments. + diff --git a/integration/build.gradle.kts b/integration/build.gradle.kts index f84975aa..302e4ac3 100644 --- a/integration/build.gradle.kts +++ b/integration/build.gradle.kts @@ -13,4 +13,7 @@ dependencies { integrationTestImplementation("org.springframework.cloud:spring-cloud-starter-openfeign") integrationTestImplementation("org.springframework.boot:spring-boot-starter-data-jpa") integrationTestImplementation("org.springframework.boot:spring-boot-starter-json") + integrationTestImplementation("org.springframework.boot:spring-boot-testcontainers") + integrationTestImplementation("org.testcontainers:testcontainers") + integrationTestImplementation("org.testcontainers:junit-jupiter") } diff --git a/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt b/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt index 8f814d02..36f866d4 100644 --- a/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt +++ b/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt @@ -9,22 +9,45 @@ import hu.bsstudio.bssweb.video.repository.DetailedVideoRepository import hu.bsstudio.bssweb.videocrew.repository.VideoCrewRepository import org.junit.jupiter.api.BeforeEach import org.springframework.beans.factory.annotation.Autowired -import org.springframework.test.context.TestPropertySource +import org.springframework.test.context.DynamicPropertyRegistry +import org.springframework.test.context.DynamicPropertySource import org.springframework.test.context.junit.jupiter.SpringJUnitConfig +import org.testcontainers.containers.DockerComposeContainer +import org.testcontainers.junit.jupiter.Container +import org.testcontainers.junit.jupiter.Testcontainers +import java.io.File +@Testcontainers @SpringJUnitConfig(classes = [BssFeignConfig::class, DataConfig::class]) -@TestPropertySource( - properties = [ - "bss.client.url=http://localhost:8080", - "bss.client.username=user", - "bss.client.password=password", - "spring.flyway.enabled=false", - "spring.datasource.url=jdbc:postgresql://localhost:5432/bss?currentSchema=private", - "spring.datasource.username=user", - "spring.datasource.password=password", - ], -) open class IntegrationTest { + + companion object { + @Container + @JvmStatic + val compose: DockerComposeContainer<*> = DockerComposeContainer(File("../docker-compose.yml"), File("../docker-compose.ci.yml")) + .withExposedService("postgres", 5432) + .withExposedService("app", 8080) + .withOptions("--profile app") + .withBuild(true) + + @DynamicPropertySource + @JvmStatic + fun configureProperties(registry: DynamicPropertyRegistry) { + val postgresHost = compose.getServiceHost("postgres", 5432) + val postgresPort = compose.getServicePort("postgres", 5432) + val appHost = compose.getServiceHost("app", 8080) + val appPort = compose.getServicePort("app", 8080) + + registry.add("spring.datasource.url") { + "jdbc:postgresql://$postgresHost:$postgresPort/bss?currentSchema=private" + } + registry.add("spring.datasource.username") {"user" } + registry.add("spring.datasource.password") {"password" } + registry.add("spring.flyway.enabled") {"false" } + registry.add("bss.client.url") { "http://$appHost:$appPort" } + } + } + @Autowired protected lateinit var eventRepository: DetailedEventRepository @Autowired protected lateinit var videoRepository: DetailedVideoRepository From 57d6349bddbd6f57e6c2539fa9ebd6b8931583f1 Mon Sep 17 00:00:00 2001 From: Bence Csik <22349790+csikb@users.noreply.github.com> Date: Sun, 5 Oct 2025 10:15:17 +0100 Subject: [PATCH 2/7] chore: refactor DefaultFeignConfig and IntegrationTest for improved readability --- .../bssweb/config/DefaultFeignConfig.kt | 2 +- .../hu/bsstudio/bssweb/IntegrationTest.kt | 22 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/client/src/main/kotlin/hu/bsstudio/bssweb/config/DefaultFeignConfig.kt b/client/src/main/kotlin/hu/bsstudio/bssweb/config/DefaultFeignConfig.kt index f000b010..7d5defd0 100644 --- a/client/src/main/kotlin/hu/bsstudio/bssweb/config/DefaultFeignConfig.kt +++ b/client/src/main/kotlin/hu/bsstudio/bssweb/config/DefaultFeignConfig.kt @@ -6,7 +6,7 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @Configuration -class DefaultFeignConfig() { +class DefaultFeignConfig { @Bean fun interceptor() = RequestInterceptor { template -> diff --git a/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt b/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt index 36f866d4..4476367f 100644 --- a/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt +++ b/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt @@ -20,15 +20,15 @@ import java.io.File @Testcontainers @SpringJUnitConfig(classes = [BssFeignConfig::class, DataConfig::class]) open class IntegrationTest { - companion object { @Container @JvmStatic - val compose: DockerComposeContainer<*> = DockerComposeContainer(File("../docker-compose.yml"), File("../docker-compose.ci.yml")) - .withExposedService("postgres", 5432) - .withExposedService("app", 8080) - .withOptions("--profile app") - .withBuild(true) + val compose: DockerComposeContainer<*> = + DockerComposeContainer(File("../docker-compose.yml"), File("../docker-compose.ci.yml")) + .withExposedService("postgres", 5432) + .withExposedService("app", 8080) + .withOptions("--profile app") + .withBuild(true) @DynamicPropertySource @JvmStatic @@ -38,12 +38,12 @@ open class IntegrationTest { val appHost = compose.getServiceHost("app", 8080) val appPort = compose.getServicePort("app", 8080) - registry.add("spring.datasource.url") { - "jdbc:postgresql://$postgresHost:$postgresPort/bss?currentSchema=private" + registry.add("spring.datasource.url") { + "jdbc:postgresql://$postgresHost:$postgresPort/bss?currentSchema=private" } - registry.add("spring.datasource.username") {"user" } - registry.add("spring.datasource.password") {"password" } - registry.add("spring.flyway.enabled") {"false" } + registry.add("spring.datasource.username") { "user" } + registry.add("spring.datasource.password") { "password" } + registry.add("spring.flyway.enabled") { "false" } registry.add("bss.client.url") { "http://$appHost:$appPort" } } } From 547b803f7e995d2a39db24e0bdf6e95938c77a30 Mon Sep 17 00:00:00 2001 From: Bence Csik <22349790+csikb@users.noreply.github.com> Date: Sun, 5 Oct 2025 10:19:49 +0100 Subject: [PATCH 3/7] chore: enhance integration test command with verbose output --- .github/workflows/gradle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index a208db6f..f790c9b4 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -51,7 +51,7 @@ jobs: - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} - - run: "./gradlew integrationTest --continue" + - run: "./gradlew integrationTest --continue --info" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: "gradle-integration-artifacts" From 62d73f93d374760f9844107eca54d32a190e0378 Mon Sep 17 00:00:00 2001 From: Bence Csik <22349790+csikb@users.noreply.github.com> Date: Sun, 5 Oct 2025 10:26:12 +0100 Subject: [PATCH 4/7] chore: update .gitignore to include Visual Studio Code settings and local history --- .gitignore | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.gitignore b/.gitignore index 3ab5f9a7..44157c1e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,17 @@ +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + ### JetBrains template # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 From c5ba5782235fc907055613243764bc1b882f8db0 Mon Sep 17 00:00:00 2001 From: Bence Csik <22349790+csikb@users.noreply.github.com> Date: Sun, 5 Oct 2025 10:29:10 +0100 Subject: [PATCH 5/7] chore: add settings.json for automatic Java build configuration updates --- .vscode/settings.json | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..e0f15db2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "automatic" +} \ No newline at end of file From 37db8490663873c3e1c99b5a3b57906800c9ae9a Mon Sep 17 00:00:00 2001 From: Bence Csik <22349790+csikb@users.noreply.github.com> Date: Sun, 5 Oct 2025 11:36:39 +0100 Subject: [PATCH 6/7] chore: refactor integration tests to use Spring-managed Docker Compose configuration --- integration/README.md | 35 ++++++++++--- .../hu/bsstudio/bssweb/IntegrationTest.kt | 36 +------------ .../bssweb/TestContainerConfiguration.kt | 50 +++++++++++++++++++ 3 files changed, 79 insertions(+), 42 deletions(-) create mode 100644 integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/TestContainerConfiguration.kt diff --git a/integration/README.md b/integration/README.md index 451f1cba..d403ef8d 100644 --- a/integration/README.md +++ b/integration/README.md @@ -4,11 +4,29 @@ It stores the integration tests for the application. To run the integration tests, you need to have Docker installed on your machine. -The integration tests now use **Testcontainers with Docker Compose** to automatically start and configure the required services from your existing `docker-compose.yml`: +The integration tests now use **Testcontainers with Docker Compose** managed by **Spring's dependency injection** to automatically start and configure the required services from your existing `docker-compose.yml`: - PostgreSQL database +- Your Spring Boot application - WireMock servers for external API mocking (file-api and OIDC) -The Docker Compose services are automatically started before the tests run and stopped after completion. +## Architecture + +The integration test setup uses Spring's proper dependency injection patterns: + +- **`TestContainerConfiguration`**: A Spring `@TestConfiguration` that manages Docker Compose as a singleton bean +- **`SharedDockerComposeContainer`**: Thread-safe singleton holder that ensures only one Docker Compose instance +- **`ContainerPropertyConfigurer`**: Spring-managed bean for configuring dynamic properties +- **`IntegrationTest`**: Base class that uses Spring's `@DynamicPropertySource` to configure properties + +### Spring Benefits + +✅ **Proper Spring patterns**: Uses `@TestConfiguration`, `@Bean`, and `@Scope("singleton")` +✅ **Dependency injection**: Container lifecycle managed by Spring's IoC container +✅ **Thread safety**: Double-checked locking pattern for safe singleton initialization +✅ **Automatic cleanup**: Spring handles bean lifecycle and cleanup +✅ **Configuration management**: Spring manages all container-related beans + +The Docker Compose services are automatically started before the first test runs and stopped after all tests complete. Each test will clear the database tables to ensure test isolation. Each Integration test has to extend the `IntegrationTest` class. @@ -19,18 +37,21 @@ Each Integration test has to extend the `IntegrationTest` class. ## What's changed from manual Docker Compose -- **Automatic lifecycle management**: Testcontainers automatically starts/stops your Docker Compose services +- **Spring-managed lifecycle**: Docker Compose containers are managed as Spring beans +- **Singleton scope**: Spring ensures only one Docker Compose instance across all tests +- **Dependency injection**: Proper Spring IoC patterns instead of static objects +- **Thread-safe initialization**: Safe concurrent access to shared container instance - **Dynamic port mapping**: Tests use the actual exposed ports from Docker Compose - **Same service configuration**: Uses your existing `docker-compose.yml` exactly as configured -- **Isolated test environment**: Each test run gets fresh containers - **No manual setup required**: No need to run `docker compose up/down` manually ## Container Configuration The integration tests use your existing `docker-compose.yml` services: - **PostgreSQL 16.3**: Exact same configuration as your compose file -- **WireMock 3.13.1**: File-api and OIDC mocks with the same stub mappings -- **Automatic cleanup**: All compose services are removed after test completion +- **Spring Boot App**: Your actual application with all its dependencies +- **WireMock services**: File-api and OIDC mocks with the same stub mappings +- **Spring-managed cleanup**: All compose services are cleaned up by Spring's lifecycle management -This approach ensures your integration tests run against the exact same service configuration as your development and production environments. +This approach ensures your integration tests run against the exact same service configuration as your development and production environments, while using proper Spring dependency injection patterns for container management. diff --git a/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt b/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt index 4476367f..617d696b 100644 --- a/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt +++ b/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt @@ -9,44 +9,10 @@ import hu.bsstudio.bssweb.video.repository.DetailedVideoRepository import hu.bsstudio.bssweb.videocrew.repository.VideoCrewRepository import org.junit.jupiter.api.BeforeEach import org.springframework.beans.factory.annotation.Autowired -import org.springframework.test.context.DynamicPropertyRegistry -import org.springframework.test.context.DynamicPropertySource import org.springframework.test.context.junit.jupiter.SpringJUnitConfig -import org.testcontainers.containers.DockerComposeContainer -import org.testcontainers.junit.jupiter.Container -import org.testcontainers.junit.jupiter.Testcontainers -import java.io.File -@Testcontainers -@SpringJUnitConfig(classes = [BssFeignConfig::class, DataConfig::class]) +@SpringJUnitConfig(classes = [TestContainerConfiguration::class, BssFeignConfig::class, DataConfig::class]) open class IntegrationTest { - companion object { - @Container - @JvmStatic - val compose: DockerComposeContainer<*> = - DockerComposeContainer(File("../docker-compose.yml"), File("../docker-compose.ci.yml")) - .withExposedService("postgres", 5432) - .withExposedService("app", 8080) - .withOptions("--profile app") - .withBuild(true) - - @DynamicPropertySource - @JvmStatic - fun configureProperties(registry: DynamicPropertyRegistry) { - val postgresHost = compose.getServiceHost("postgres", 5432) - val postgresPort = compose.getServicePort("postgres", 5432) - val appHost = compose.getServiceHost("app", 8080) - val appPort = compose.getServicePort("app", 8080) - - registry.add("spring.datasource.url") { - "jdbc:postgresql://$postgresHost:$postgresPort/bss?currentSchema=private" - } - registry.add("spring.datasource.username") { "user" } - registry.add("spring.datasource.password") { "password" } - registry.add("spring.flyway.enabled") { "false" } - registry.add("bss.client.url") { "http://$appHost:$appPort" } - } - } @Autowired protected lateinit var eventRepository: DetailedEventRepository diff --git a/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/TestContainerConfiguration.kt b/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/TestContainerConfiguration.kt new file mode 100644 index 00000000..c92d98be --- /dev/null +++ b/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/TestContainerConfiguration.kt @@ -0,0 +1,50 @@ +package hu.bsstudio.bssweb + +import org.springframework.boot.test.context.TestConfiguration +import org.springframework.context.annotation.Bean +import org.springframework.test.context.DynamicPropertyRegistry +import org.springframework.test.context.DynamicPropertySource +import org.testcontainers.containers.DockerComposeContainer +import java.io.File + +/** + * Spring Test Configuration for managing Docker Compose containers in integration tests. + * This ensures a single Docker Compose instance is shared across all test classes using Spring's singleton scope. + */ +@TestConfiguration +class TestContainerConfiguration { + + /** + * Creates a singleton Docker Compose container managed by Spring. + * The container is started when the bean is created and automatically cleaned up by Spring. + */ + @Bean + fun dockerComposeContainer(): DockerComposeContainer<*> { + return DockerComposeContainer(File("../docker-compose.yml"), File("../docker-compose.ci.yml")) + .withExposedService("postgres", 5432) + .withExposedService("app", 8080) + .withOptions("--profile app") + .withBuild(true) + } + + /** + * Bean for configuring dynamic properties based on the Docker Compose container. + * This bean depends on the dockerComposeContainer and will be created after it. + */ + + @DynamicPropertySource + fun containerPropertyConfigurer(registry: DynamicPropertyRegistry, dockerComposeContainer: DockerComposeContainer<*>) { + val postgresHost = dockerComposeContainer.getServiceHost("postgres", 5432) + val postgresPort = dockerComposeContainer.getServicePort("postgres", 5432) + val appHost = dockerComposeContainer.getServiceHost("app", 8080) + val appPort = dockerComposeContainer.getServicePort("app", 8080) + + registry.add("spring.datasource.url") { + "jdbc:postgresql://$postgresHost:$postgresPort/bss?currentSchema=private" + } + registry.add("spring.datasource.username") { "user" } + registry.add("spring.datasource.password") { "password" } + registry.add("spring.flyway.enabled") { "false" } + registry.add("bss.client.url") { "http://$appHost:$appPort" } + } +} From 7bce6713a9a84e0340afb7c02446ae3ede254652 Mon Sep 17 00:00:00 2001 From: Bence Csik <22349790+csikb@users.noreply.github.com> Date: Sun, 5 Oct 2025 11:40:32 +0100 Subject: [PATCH 7/7] chore: clean up comments in TestContainerConfiguration for clarity --- .../bsstudio/bssweb/TestContainerConfiguration.kt | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/TestContainerConfiguration.kt b/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/TestContainerConfiguration.kt index c92d98be..add253cb 100644 --- a/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/TestContainerConfiguration.kt +++ b/integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/TestContainerConfiguration.kt @@ -7,17 +7,9 @@ import org.springframework.test.context.DynamicPropertySource import org.testcontainers.containers.DockerComposeContainer import java.io.File -/** - * Spring Test Configuration for managing Docker Compose containers in integration tests. - * This ensures a single Docker Compose instance is shared across all test classes using Spring's singleton scope. - */ @TestConfiguration class TestContainerConfiguration { - /** - * Creates a singleton Docker Compose container managed by Spring. - * The container is started when the bean is created and automatically cleaned up by Spring. - */ @Bean fun dockerComposeContainer(): DockerComposeContainer<*> { return DockerComposeContainer(File("../docker-compose.yml"), File("../docker-compose.ci.yml")) @@ -27,11 +19,6 @@ class TestContainerConfiguration { .withBuild(true) } - /** - * Bean for configuring dynamic properties based on the Docker Compose container. - * This bean depends on the dockerComposeContainer and will be created after it. - */ - @DynamicPropertySource fun containerPropertyConfigurer(registry: DynamicPropertyRegistry, dockerComposeContainer: DockerComposeContainer<*>) { val postgresHost = dockerComposeContainer.getServiceHost("postgres", 5432)