package roomescape.supports import io.kotest.core.listeners.AfterSpecListener import io.kotest.core.listeners.AfterTestListener import io.kotest.core.listeners.BeforeSpecListener import io.kotest.core.spec.Spec import io.kotest.core.test.TestCase import io.kotest.core.test.TestResult import io.kotest.extensions.spring.testContextManager import jakarta.persistence.EntityManager import org.springframework.jdbc.core.JdbcTemplate import org.springframework.stereotype.Component @Component class TestDatabaseUtil( val entityManager: EntityManager, val jdbcTemplate: JdbcTemplate, ) { val tables: List by lazy { jdbcTemplate.query("SHOW TABLES") { rs, _ -> rs.getString(1).lowercase() } } fun initializeRegion() { this::class.java.getResource("/schema/region-data.sql")?.readText()?.let { jdbcTemplate.execute(it) } } fun clear(mode: CleanerMode) { entityManager.clear() jdbcTemplate.execute("SET REFERENTIAL_INTEGRITY FALSE") tables.forEach { if (mode == CleanerMode.EXCEPT_REGION && it == "region") { return@forEach } jdbcTemplate.execute("TRUNCATE TABLE $it RESTART IDENTITY") } jdbcTemplate.execute("SET REFERENTIAL_INTEGRITY TRUE") } } enum class CleanerMode { EXCEPT_REGION, ALL } class DatabaseCleanerExtension: BeforeSpecListener, AfterTestListener, AfterSpecListener { override suspend fun beforeSpec(spec: Spec) { super.beforeSpec(spec) getCleaner().initializeRegion() } override suspend fun afterTest(testCase: TestCase, result: TestResult) { super.afterTest(testCase, result) getCleaner().clear(CleanerMode.EXCEPT_REGION) } override suspend fun afterSpec(spec: Spec) { super.afterSpec(spec) getCleaner().clear(CleanerMode.ALL) } private suspend fun getCleaner(): TestDatabaseUtil { return testContextManager().testContext .applicationContext .getBean(TestDatabaseUtil::class.java) } }