Reputation: 41
I'm working on a Kotlin project that uses Spring Boot, JOOQ for database code generation, and Testcontainers for integration testing with PostgreSQL. My build is managed with Gradle, and I am encountering an issue related to the Testcontainers setup.
Here is a portion of my build.gradle.kts configuration:
import org.jetbrains.kotlin.gradle.internal.KaptGenerateStubsTask
import org.testcontainers.containers.PostgreSQLContainer
val dbUsername = properties["db.username"] as? String ?: "user"
val dbPassword = properties["db.password"] as? String ?: "test"
plugins {
id("org.springframework.boot") version "3.0.13"
id("io.spring.dependency-management") version "1.1.5"
kotlin("jvm") version "1.9.24"
kotlin("plugin.spring") version "1.9.24"
id("org.jooq.jooq-codegen-gradle") version "3.19.7"
java
idea
application
}
group = "fr.test.data"
version = "0.0.1-SNAPSHOT"
java {
sourceCompatibility = JavaVersion.VERSION_17
}
kotlin {
jvmToolchain(17)
}
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
runtimeOnly("org.springframework.boot:spring-boot-devtools")
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.springframework.boot:spring-boot-starter-jdbc")
implementation("org.jooq:jooq:3.19.7")
implementation("org.jooq:jooq-kotlin:3.19.7")
implementation("org.jooq:jooq-jackson-extensions:3.19.7")
implementation("org.postgresql:postgresql:42.7.3")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(group = "org.mockito")
}
implementation("org.springframework.boot:spring-boot-starter-logging")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.3")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.3")
implementation("org.apache.commons:commons-collections4:4.5.0-M2")
implementation("org.apache.commons:commons-compress:1.26.2")
testImplementation("org.junit.jupiter:junit-jupiter:5.4.2")
testImplementation("org.junit.platform:junit-platform-suite:1.9.2")
testImplementation("org.junit.platform:junit-platform-launcher:1.9.2")
testImplementation("org.testcontainers:testcontainers:1.19.7")
testImplementation("org.testcontainers:junit-jupiter:1.19.7")
testImplementation("org.testcontainers:postgresql:1.19.7")
jooqCodegen("org.postgresql:postgresql:42.7.3")
jooqCodegen("org.jooq:jooq-meta-extensions:3.19.7")
}
tasks.withType<Test> {
useJUnitPlatform()
}
abstract class Containers : BuildService<Containers.Params>, AutoCloseable {
interface Params : BuildServiceParameters {
fun getUsername(): Property<String>
fun getPassword(): Property<String>
}
val instance: PostgreSQLContainer<*> = PostgreSQLContainer("postgres:14-alpine")
.withUsername(parameters.getUsername().get())
.withPassword(parameters.getPassword().get())
init {
println("Starting containers...")
instance.start()
instance.execInContainer("bash", "-c", "printf '\\set AUTOCOMMIT on\\n CREATE DATABASE test;' | psql -U postgres")
}
override fun close() {
println("Stopping containers...")
instance.close()
}
}
val containerProvider = project.gradle.sharedServices
.registerIfAbsent("containers", Containers::class.java) {
parameters.getUsername().set(dbUsername)
parameters.getPassword().set(dbPassword)
}
jooq {
executions {
create("test") {
configuration {
jdbc {
println("JOOQ is parsing its configuration...!")
username = dbUsername
password = dbPassword
url = containerProvider.get().instance.jdbcUrl + "/test"
}
generator {
name = "org.jooq.codegen.KotlinGenerator"
database {
name = "org.jooq.meta.postgres.PostgresDatabase"
inputSchema = "public"
includes = """
test_domain
""".trimIndent()
|eco_record_log|eco_record|eco_recipient|otc_storage_file|eco_record_object
""".trimIndent()
}
generate {
isRelations = true
isRoutines = true
}
target {
packageName = "fr.test.generated.jooq"
}
}
}
}
}
}
tasks.jooqCodegen {
usesService(containerProvider)
dependsOn("configureTestContainers", "update")
mustRunAfter("configureTestContainers", "update")
outputs.cacheIf { _ -> true }
}
tasks.register("update") {
doLast {
println("Running update task...")
// Custom update logic here
}
}
tasks.compileKotlin {
dependsOn("jooqCodegen")
mustRunAfter("jooqCodegen")
}
tasks.withType(KaptGenerateStubsTask::class.java).configureEach {
dependsOn("jooqCodegen")
mustRunAfter("jooqCodegen")
}
The Problem: When I run my build, I encounter the following error message related to the Docker environment used by Testcontainers:
Can't instantiate a strategy from org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy (ClassNotFoundException). This probably means that cached configuration refers to a client provider class that is not available in this version of Testcontainers. Other strategies will be tried instead. 3 actionable tasks: 2 executed, 1 up-to-date Could not find a valid Docker environment. Please check configuration. Attempted configurations were: As no valid configuration was found, execution cannot continue. See https://java.testcontainers.org/on_failure.html for more details.
FAILURE: Build failed with an exception.
Failed to create service 'containers'. Could not create an instance of type Build_gradle$Containers. > Could not find a valid Docker environment. Please see logs and check configuration
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights. Get more help at https://help.gradle.org.
BUILD FAILED in 571ms
Question: What could be causing this issue with Testcontainers failing to find a valid Docker environment, and how can I resolve it to successfully run my build?
Docker Setup: Verified that Docker is installed and running correctly on my machine. Testcontainers Version: Checked that the Testcontainers version is compatible with the Docker version. Environment Variables: Confirmed that DOCKER_HOST and other related environment variables are correctly set. Gradle Caching: Cleared Gradle caches with ./gradlew clean and retried the build.
Upvotes: 1
Views: 77