diff --git a/view/mongo/pom.xml b/view/mongo/pom.xml index d9b471e43..0f2dbce60 100644 --- a/view/mongo/pom.xml +++ b/view/mongo/pom.xml @@ -49,11 +49,16 @@ test - de.flapdoodle.embed - de.flapdoodle.embed.mongo.spring30x - 4.11.0 + org.testcontainers + junit-jupiter test + + org.testcontainers + mongodb + test + + com.tngtech.jgiven jgiven-junit5 diff --git a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/PolyflowMongoTestApplication.kt b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/PolyflowMongoTestApplication.kt deleted file mode 100644 index 920a7a305..000000000 --- a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/PolyflowMongoTestApplication.kt +++ /dev/null @@ -1,7 +0,0 @@ -package io.holunda.polyflow.view.mongo - -import de.flapdoodle.embed.mongo.spring.autoconfigure.EmbeddedMongoAutoConfiguration -import org.springframework.boot.autoconfigure.SpringBootApplication - -@SpringBootApplication(exclude = [EmbeddedMongoAutoConfiguration::class]) -class PolyflowMongoTestApplication diff --git a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceChangeStreamChangeTrackingITest.kt b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceChangeStreamChangeTrackingITest.kt index efeaf08e4..8ec587121 100644 --- a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceChangeStreamChangeTrackingITest.kt +++ b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceChangeStreamChangeTrackingITest.kt @@ -1,38 +1,37 @@ package io.holunda.polyflow.view.mongo.service -import io.holunda.polyflow.view.mongo.utils.MongoLauncher -import org.junit.jupiter.api.AfterAll +import io.holunda.polyflow.view.mongo.TaskPoolMongoViewConfiguration import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.BeforeAll -import org.springframework.test.context.ActiveProfiles -import org.springframework.test.context.TestPropertySource +import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest +import org.springframework.test.context.* +import org.testcontainers.containers.MongoDBContainer +import org.testcontainers.junit.jupiter.Container +import org.testcontainers.junit.jupiter.Testcontainers @TestPropertySource( properties = [ "polyflow.view.mongo.changeTrackingMode=CHANGE_STREAM", - "spring.data.mongodb.database=TaskPoolMongoServiceChangeStreamChangeTrackingITest" ] ) @ActiveProfiles("itest-replicated") +@Testcontainers +@DataMongoTest +@ContextConfiguration(classes = [TaskPoolMongoViewConfiguration::class]) class PolyflowMongoServiceChangeStreamChangeTrackingITest : PolyflowMongoServiceITestBase() { companion object { - private val mongo = MongoLauncher.MongoInstance(true, "TaskPoolMongoServiceChangeStreamChangeTrackingITest") - - @BeforeAll + @Container @JvmStatic - fun initMongo() { - mongo.init() - } + var mongoDBContainer: MongoDBContainer = MongoDBContainer("mongo:4.4.2").withSharding() - @AfterAll + @DynamicPropertySource @JvmStatic - fun stop() { - mongo.stop() + fun setProperties(registry: DynamicPropertyRegistry) { + registry.add("spring.data.mongodb.uri") { mongoDBContainer.replicaSetUrl } } } @AfterEach fun clearMongo() { - mongo.clear() + mongoDBContainer.clear() } } diff --git a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceEventHandlerChangeTrackingITest.kt b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceEventHandlerChangeTrackingITest.kt index aef82e655..360090ed9 100644 --- a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceEventHandlerChangeTrackingITest.kt +++ b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceEventHandlerChangeTrackingITest.kt @@ -1,38 +1,45 @@ package io.holunda.polyflow.view.mongo.service -import io.holunda.polyflow.view.mongo.utils.MongoLauncher -import org.junit.jupiter.api.AfterAll +import com.mongodb.client.MongoClients +import io.holunda.polyflow.view.mongo.TaskPoolMongoViewConfiguration +import org.axonframework.extensions.mongo.MongoTemplate import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.BeforeAll -import org.springframework.test.context.ActiveProfiles -import org.springframework.test.context.TestPropertySource +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest +import org.springframework.test.context.* +import org.testcontainers.containers.MongoDBContainer +import org.testcontainers.junit.jupiter.Container +import org.testcontainers.junit.jupiter.Testcontainers + @TestPropertySource( properties = [ "polyflow.view.mongo.changeTrackingMode=EVENT_HANDLER", - "spring.data.mongodb.database=TaskPoolMongoServiceEventHandlerChangeTrackingITest" ] ) @ActiveProfiles("itest-standalone") +@Testcontainers +@DataMongoTest +@ContextConfiguration(classes = [TaskPoolMongoViewConfiguration::class]) class PolyflowMongoServiceEventHandlerChangeTrackingITest : PolyflowMongoServiceITestBase() { companion object { - private val mongo = MongoLauncher.MongoInstance(false, "TaskPoolMongoServiceEventHandlerChangeTrackingITest") - - @BeforeAll + @Container @JvmStatic - fun initMongo() { - mongo.init() - } + var mongoDBContainer: MongoDBContainer = MongoDBContainer("mongo:4.4.2") - @AfterAll + @DynamicPropertySource @JvmStatic - fun stop() { - mongo.stop() + fun setProperties(registry: DynamicPropertyRegistry) { + registry.add("spring.data.mongodb.uri") { mongoDBContainer.replicaSetUrl } } } + @Autowired + var mongoTemplate: MongoTemplate? = null + @AfterEach fun clearMongo() { - mongo.clear() + mongoDBContainer.clear() } } + diff --git a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceTestBase.kt b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceTestBase.kt index fce9f3ffa..e321bdc05 100755 --- a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceTestBase.kt +++ b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/PolyflowMongoServiceTestBase.kt @@ -1,5 +1,6 @@ package io.holunda.polyflow.view.mongo.service +import com.mongodb.client.MongoClients import com.tngtech.jgiven.integration.spring.junit5.SpringScenarioTest import com.tngtech.jgiven.junit5.JGivenExtension import io.holunda.camunda.taskpool.api.business.* @@ -9,20 +10,18 @@ import io.holunda.polyflow.view.ProtocolEntry import io.holunda.polyflow.view.Task import io.holunda.polyflow.view.TaskWithDataEntries import io.holunda.polyflow.view.auth.User -import io.holunda.polyflow.view.mongo.PolyflowMongoTestApplication import io.holunda.polyflow.view.query.data.DataEntriesForUserQuery import io.holunda.polyflow.view.query.task.* import org.camunda.bpm.engine.variable.VariableMap import org.camunda.bpm.engine.variable.Variables import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith -import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.annotation.DirtiesContext +import org.testcontainers.containers.MongoDBContainer import java.time.OffsetDateTime import java.util.* @ExtendWith(JGivenExtension::class) -@SpringBootTest(classes = [PolyflowMongoTestApplication::class]) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) abstract class PolyflowMongoServiceITestBase : SpringScenarioTest, PolyflowWhenStage<*>, PolyflowThenStage<*>>() { @@ -685,3 +684,13 @@ data class TestDataEntryData( } private fun Task.withDataEntries(dataEntries: List = listOf()) = TaskWithDataEntries(this, dataEntries) + +/** + * Clear client and db. + */ +fun MongoDBContainer.clear() { + MongoClients.create(this.connectionString).use { + val database = it.getDatabase("test") + database.drop() + } +} diff --git a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/task/TaskRepositoryExtensionImplITest.kt b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/task/TaskRepositoryExtensionImplITest.kt index 2885f5362..ab4c9fee8 100644 --- a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/task/TaskRepositoryExtensionImplITest.kt +++ b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/task/TaskRepositoryExtensionImplITest.kt @@ -1,30 +1,35 @@ package io.holunda.polyflow.view.mongo.task -import io.holunda.polyflow.view.mongo.PolyflowMongoTestApplication -import io.holunda.polyflow.view.mongo.utils.MongoLauncher +import io.holunda.polyflow.view.mongo.TaskPoolMongoViewConfiguration import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.* -import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Sort import org.springframework.test.context.ActiveProfiles +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.DynamicPropertyRegistry +import org.springframework.test.context.DynamicPropertySource import org.springframework.test.context.TestPropertySource -import org.springframework.test.context.junit.jupiter.SpringExtension +import org.testcontainers.containers.MongoDBContainer +import org.testcontainers.junit.jupiter.Container +import org.testcontainers.junit.jupiter.Testcontainers import reactor.core.publisher.Mono import java.time.Instant import java.util.* + @TestPropertySource( properties = [ "polyflow.view.mongo.changeTrackingMode=EVENT_HANDLER", - "spring.data.mongodb.database=TaskRepositoryExtensionImplITest" ] ) -@SpringBootTest(classes = [PolyflowMongoTestApplication::class]) +@Testcontainers +@DataMongoTest @ActiveProfiles("itest-standalone") -@ExtendWith(SpringExtension::class) +@ContextConfiguration(classes = [TaskPoolMongoViewConfiguration::class]) class TaskRepositoryExtensionImplITest { companion object { @@ -39,19 +44,16 @@ class TaskRepositoryExtensionImplITest { const val PRIORITY_TWO = 90 const val PRIORITY_THREE = 100 - private val mongo = MongoLauncher.MongoInstance(false, "TaskRepositoryExtensionImplITest") - - @BeforeAll + @Container @JvmStatic - fun initMongo() { - mongo.init() - } + var mongoDBContainer: MongoDBContainer = MongoDBContainer("mongo:4.4.2") - @AfterAll + @DynamicPropertySource @JvmStatic - fun stop() { - mongo.stop() + fun setProperties(registry: DynamicPropertyRegistry) { + registry.add("spring.data.mongodb.uri") { mongoDBContainer.replicaSetUrl } } + } @BeforeEach @@ -62,12 +64,6 @@ class TaskRepositoryExtensionImplITest { @Autowired lateinit var taskRepository: TaskRepository - @AfterEach - fun clearMongo() { - mongo.clear() - } - - @Test fun finds_by_everything() { val documents = prepareDocuments(task().build()) diff --git a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/utils/MongoLauncher.kt b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/utils/MongoLauncher.kt deleted file mode 100644 index b4f13a16c..000000000 --- a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/utils/MongoLauncher.kt +++ /dev/null @@ -1,176 +0,0 @@ -package io.holunda.polyflow.view.mongo.utils - -import com.mongodb.* -import com.mongodb.client.MongoClients -import de.flapdoodle.embed.mongo.commands.MongodArguments -import de.flapdoodle.embed.mongo.config.Net -import de.flapdoodle.embed.mongo.config.Storage -import de.flapdoodle.embed.mongo.distribution.Version -import de.flapdoodle.embed.mongo.transitions.Mongod -import de.flapdoodle.embed.mongo.transitions.RunningMongodProcess -import de.flapdoodle.embed.process.io.ProcessOutput -import de.flapdoodle.embed.process.io.Processors -import de.flapdoodle.embed.process.io.Slf4jLevel -import de.flapdoodle.embed.process.types.ProcessConfig -import de.flapdoodle.reverse.TransitionWalker -import de.flapdoodle.reverse.transitions.Start -import mu.KLogging -import org.awaitility.Awaitility.await -import org.bson.Document -import org.mockito.Mockito.mock -import org.slf4j.Logger -import java.io.IOException -import java.util.concurrent.TimeUnit -import javax.net.SocketFactory - - -/** - * Mongo Launcher... See https://github.com/AxonFramework/extension-mongo/blob/master/mongo/src/test/java/org/axonframework/extensions/mongo/utils/MongoLauncher.java - * @author Allard Buijze - * @author Simon Zambrovski - * @author Lars Bilger - */ -object MongoLauncher { - - - const val MONGO_DEFAULT_PORT = 27017 - const val LOCALHOST = "127.0.0.1" -// private val counter = AtomicInteger() - - private val isMongoRunning: Boolean - get() { - return try { - val mongoSocket = SocketFactory.getDefault().createSocket(LOCALHOST, MONGO_DEFAULT_PORT) - if (mongoSocket.isConnected) { - mongoSocket.close() - true - } else { - false - } - } catch (e: IOException) { - false - } - } - - fun prepareExecutable(asReplicaSet: Boolean, logger: Logger): Mongod { - if (isMongoRunning) { - return mock(Mongod::class.java) - } - - return Mongod.builder() - .net(Start.to(Net::class.java).initializedWith(Net.defaults().withPort(MONGO_DEFAULT_PORT))) - .mongodArguments( - Start.to(MongodArguments::class.java).initializedWith( - MongodArguments.builder() - .apply { if (asReplicaSet) replication(Storage.of("repembedded", 16)) } - .useNoJournal(!asReplicaSet) - .build() - ) - ) - .processOutput( - Start.to(ProcessOutput::class.java).initializedWith( - ProcessOutput.builder() - .output(Processors.logTo(logger, Slf4jLevel.DEBUG)) - .error(Processors.logTo(logger, Slf4jLevel.ERROR)) - .commands(Processors.named("[console>]", Processors.logTo(logger, Slf4jLevel.TRACE))) - .build() - ) - ) - // Increase timeout as default timeout seems not to be sufficient for shutdown in replicaSet mode - .processConfig(Start.to(ProcessConfig::class.java).initializedWith(ProcessConfig.defaults().withStopTimeoutInMillis(11000))) - .build() - - - // TODO check if there is a good reason for this fileNaming change and if there is, find out how to do it in the new version -// val command = Command.MongoD -// val downloadConfig = Defaults -// .downloadConfigFor(command) -// .fileNaming { prefix, postfix -> prefix + "_mongo_taskview_" + counter.getAndIncrement() + "_" + postfix } -// .build() - -// val artifactStore = Defaults -// .extractedArtifactStoreFor(command) -// .withDownloadConfig(downloadConfig) - -// val runtimeConfig = Defaults -// .runtimeConfigFor(command, logger) -// .artifactStore(artifactStore) -// .build() - -// val runtime = MongodStarter.getInstance(runtimeConfig) -// return runtime.prepare(mongodConfig) - } - - open class MongoInstance( - private val asReplicaSet: Boolean, - private val databaseName: String - ) { - - companion object : KLogging() - - private var mongod: TransitionWalker.ReachedState? = null - private var mongoExecutable: Mongod? = null - - /** - * Inits server. - */ - fun init() { - if (isMongoRunning) { - // There was already an existing mongo instance that we are reusing. Clear it in case there is any leftover data from a previous test run - clear() - } else { - this.mongoExecutable = prepareExecutable(asReplicaSet, logger) - this.mongod = mongoExecutable!!.start(Version.Main.V4_4) - if (asReplicaSet) { - - MongoClients.create( - MongoClientSettings - .builder() - .applyConnectionString(ConnectionString("mongodb://$LOCALHOST:$MONGO_DEFAULT_PORT")) - .readPreference(ReadPreference.nearest()) - .writeConcern(WriteConcern.W2) - .build() - ).use { mongo -> - - val config = Document( - mapOf("_id" to "repembedded", - "members" to BasicDBList().apply { - add(Document("_id", 0).append("host", "$LOCALHOST:$MONGO_DEFAULT_PORT")) - }) - ) - logger.info { "MongoDB Replica Config: $config" } - - val adminDatabase = mongo.getDatabase("admin") - adminDatabase.runCommand(Document("replSetInitiate", config)) - - await().atMost(5, TimeUnit.SECONDS).until { - val replStatus = adminDatabase.runCommand(Document("replSetGetStatus", 1)) - logger.info { "MongoDB Replica Set Status: $replStatus" } - "PRIMARY" == replStatus.getList("members", Document::class.java).first().getString("stateStr") - } - } - } - } - } - - /** - * Clear client and db. - */ - fun clear() { - MongoClients.create("mongodb://$LOCALHOST:$MONGO_DEFAULT_PORT").use { - val database = it.getDatabase(databaseName) - database.drop() - } - } - - /** - * Stops server. - */ - fun stop() { - mongod?.current()?.stop() - await().atMost(5, TimeUnit.SECONDS).until { - !isMongoRunning - } - } - } -}