generated from aura-ascend/template-library
TestContainer Postgres
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package ltd.lulz.test.container
|
||||
|
||||
import ltd.lulz.test.container.extension.PostgresTestExtension
|
||||
import ltd.lulz.test.container.postgres.PostgresTestListener
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
import org.springframework.test.context.TestExecutionListeners
|
||||
import org.springframework.test.context.TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@ExtendWith(PostgresTestExtension::class)
|
||||
@ContextConfiguration(initializers = [PostgresTestExtension::class])
|
||||
@TestExecutionListeners(listeners = [PostgresTestListener::class], mergeMode = MERGE_WITH_DEFAULTS)
|
||||
annotation class PostgresTestContainer
|
||||
@@ -0,0 +1,21 @@
|
||||
package ltd.lulz.test.container.extension
|
||||
|
||||
import ltd.lulz.test.container.postgres.TestContainerPostgres
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback
|
||||
import org.junit.jupiter.api.extension.ExtensionContext
|
||||
import org.springframework.boot.test.util.TestPropertyValues
|
||||
import org.springframework.context.ApplicationContextInitializer
|
||||
import org.springframework.context.ConfigurableApplicationContext
|
||||
|
||||
class PostgresTestExtension : BeforeAllCallback, ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
|
||||
override fun initialize(applicationContext: ConfigurableApplicationContext) {
|
||||
TestPropertyValues.of(TestContainerPostgres.props()).applyTo(applicationContext.environment)
|
||||
}
|
||||
|
||||
override fun beforeAll(context: ExtensionContext) {
|
||||
if (!TestContainerPostgres.postgres.isRunning) {
|
||||
TestContainerPostgres.postgres.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package ltd.lulz.test.container.postgres
|
||||
|
||||
import ltd.lulz.test.container.postgres.TestContainerPostgres.sqlFile
|
||||
import ltd.lulz.test.container.util.hasAnnotation
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.springframework.test.context.TestContext
|
||||
import org.springframework.test.context.TestExecutionListener
|
||||
|
||||
class PostgresTestListener : TestExecutionListener {
|
||||
|
||||
override fun beforeTestClass(
|
||||
context: TestContext,
|
||||
) {
|
||||
if (context.testClass.hasAnnotation<Nested>()) return
|
||||
sqlFile("postgres/data.sql", context)
|
||||
}
|
||||
|
||||
override fun afterTestClass(
|
||||
context: TestContext,
|
||||
) {
|
||||
if (context.testClass.hasAnnotation<Nested>()) return
|
||||
sqlFile("postgres/reset.sql", context)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package ltd.lulz.test.container.postgres
|
||||
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStream
|
||||
import java.io.InputStreamReader
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import ltd.lulz.test.container.util.isResourceFile
|
||||
import org.springframework.r2dbc.core.DatabaseClient
|
||||
import org.springframework.r2dbc.core.await
|
||||
import org.springframework.test.context.TestContext
|
||||
import org.testcontainers.containers.PostgreSQLContainer
|
||||
import org.testcontainers.utility.DockerImageName
|
||||
|
||||
object TestContainerPostgres {
|
||||
|
||||
val postgres = PostgreSQLContainer(DockerImageName.parse("postgres:18rc1-alpine"))
|
||||
.withReuse(true)
|
||||
.apply {
|
||||
withDatabaseName("testdb")
|
||||
withUsername("test")
|
||||
withPassword("test")
|
||||
"postgres/schema.sql".isResourceFile()?.let { withInitScript(it.path) }
|
||||
}
|
||||
|
||||
fun props(): Map<String, String> = postgres.let {
|
||||
mapOf(
|
||||
"spring.r2dbc.url" to "r2dbc:postgresql://${it.host}:${it.firstMappedPort}/${it.databaseName}",
|
||||
"spring.r2dbc.username" to it.username,
|
||||
"spring.r2dbc.password" to it.password,
|
||||
)
|
||||
}
|
||||
|
||||
fun sqlFile(
|
||||
sqlFile: String,
|
||||
context: TestContext,
|
||||
): Unit = runBlocking {
|
||||
sqlFile.isResourceFile()
|
||||
?.inputStream
|
||||
?.use {
|
||||
executeSqlStatements(
|
||||
makeSqlStatements(it),
|
||||
context.applicationContext.getBean(DatabaseClient::class.java),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("TooGenericExceptionThrown", "SqlSourceToSinkFlow")
|
||||
private suspend fun executeSqlStatements(
|
||||
statements: List<String>,
|
||||
databaseClient: DatabaseClient,
|
||||
) = try {
|
||||
statements.forEach { databaseClient.sql(it).await() }
|
||||
} catch (e: Exception) {
|
||||
throw RuntimeException("Failed to execute SQL statements", e)
|
||||
}
|
||||
|
||||
private fun makeSqlStatements(
|
||||
inputStream: InputStream,
|
||||
): List<String> = BufferedReader(InputStreamReader(inputStream))
|
||||
.lines()
|
||||
.filter { it.isNotEmpty() && !it.startsWith("--") }
|
||||
.map { it.trim() }
|
||||
.toList()
|
||||
.joinToString(" ")
|
||||
.split(';')
|
||||
.filter { it.isNotBlank() }
|
||||
.map { "${it.trim()};" }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package ltd.lulz.test.container.util
|
||||
|
||||
import org.springframework.core.io.ClassPathResource
|
||||
|
||||
fun String.isResourceFile(): ClassPathResource? = ClassPathResource(this)
|
||||
.let { resource ->
|
||||
when {
|
||||
resource.exists() && resource.isReadable -> resource
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : Annotation> Class<*>.hasAnnotation(): Boolean = getAnnotation(T::class.java) != null
|
||||
Reference in New Issue
Block a user