Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 ->
Expand Down
8 changes: 4 additions & 4 deletions docker-compose.ci.yml
Original file line number Diff line number Diff line change
@@ -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"
28 changes: 23 additions & 5 deletions integration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

3 changes: 3 additions & 0 deletions integration/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify service names and configuration match docker-compose.yml.

The DockerComposeContainer configuration references service names "postgres" and "app", uses profile "app", and enables image building. Ensure these match your docker-compose.yml configuration to avoid runtime failures.

Run the following script to verify the Docker Compose configuration:


🏁 Script executed:

#!/bin/bash
# Description: Verify docker-compose.yml contains the expected service names and profile.

# Check for postgres service
echo "=== Checking for 'postgres' service ==="
rg -A 5 '^\s*postgres:' ../docker-compose.yml ../docker-compose.ci.yml

# Check for app service
echo -e "\n=== Checking for 'app' service ==="
rg -A 5 '^\s*app:' ../docker-compose.yml ../docker-compose.ci.yml

# Check for app profile usage
echo -e "\n=== Checking for 'app' profile ==="
rg 'profiles:\s*-\s*app' ../docker-compose.yml ../docker-compose.ci.yml

Length of output: 492


🏁 Script executed:

#!/bin/bash
# Locate docker-compose files in the repository
echo "=== Finding docker-compose files ==="
find . -type f -name 'docker-compose*.yml'

Length of output: 81


🏁 Script executed:

#!/bin/bash
# Verify docker-compose services and profile in the root files
echo "=== services section ==="
rg -nP -C3 'services:' docker-compose.yml docker-compose.ci.yml
echo -e "\n=== postgres service ==="
rg -nP -C3 '^\s{2}postgres:' docker-compose.yml docker-compose.ci.yml
echo -e "\n=== app service ==="
rg -nP -C3 '^\s{2}app:' docker-compose.yml docker-compose.ci.yml
echo -e "\n=== app profile ==="
rg -nP 'profiles:\s*-\s*app' docker-compose.yml docker-compose.ci.yml

Length of output: 1436


🏁 Script executed:

#!/bin/bash
echo "=== docker-compose.yml (lines 29-45) ==="
sed -n '29,45p' docker-compose.yml
echo -e "\n=== docker-compose.ci.yml (lines 1-15) ==="
sed -n '1,15p' docker-compose.ci.yml

Length of output: 854


Adjust DockerComposeContainer profile and test schema setup

  • Remove withOptions("--profile app")—no profiles: [app] defined in your compose files.
  • Disabling Flyway means the “private” schema isn’t created by migrations; either enable migrations or point currentSchema to an existing schema.
  • Credentials (user/password) and ports match your compose configuration.
🤖 Prompt for AI Agents
In integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt
around lines 26 to 31, remove the .withOptions("--profile app") call because no
profiles are defined in the compose files; then ensure the test DB setup matches
the compose: either re-enable Flyway migrations so the "private" schema is
created, or set the datasource/currentSchema used in tests to an existing schema
(e.g., "public"); finally verify the DockerComposeContainer uses the same
service names, exposed ports and credentials (user/password) as defined in
../docker-compose.yml and ../docker-compose.ci.yml and update the container
configuration accordingly.


@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" }
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Remove extraneous blank line to fix spotlessKotlinCheck failure.

The pipeline failure indicates formatting violations including an extraneous blank line near the class declaration.

 @SpringJUnitConfig(classes = [TestContainerConfiguration::class, BssFeignConfig::class, DataConfig::class])
-
 open class IntegrationTest {
🤖 Prompt for AI Agents
In integration/src/integrationTest/kotlin/hu/bsstudio/bssweb/IntegrationTest.kt
around line 16, there is an extraneous blank line causing spotlessKotlinCheck to
fail; remove that blank line so the class declaration and surrounding code
follow the project's Kotlin formatting rules (no extra empty lines) and then
re-run the formatter/check to confirm the violation is resolved.

@Autowired protected lateinit var eventRepository: DetailedEventRepository

@Autowired protected lateinit var videoRepository: DetailedVideoRepository
Expand Down
Loading