-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
109 additions
and
149 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
# Spring Boot: Data MongoDB | ||
|
||
Showcase demonstrating how Data MongoDB repositories can be tested with the help of JUnit 5, Spring | ||
Boot's `@DataMongoTest` support and either an embedded or an actual dockerized MongoDB database. | ||
Boot's `@DataMongoTest` support and a dockerized MongoDB database. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,18 @@ | ||
plugins { | ||
id("org.springframework.boot") | ||
id("io.spring.dependency-management") | ||
id("org.springframework.boot") | ||
id("io.spring.dependency-management") | ||
|
||
kotlin("jvm") | ||
kotlin("plugin.spring") | ||
kotlin("jvm") | ||
kotlin("plugin.spring") | ||
} | ||
|
||
dependencies { | ||
implementation("org.springframework.boot:spring-boot-starter-data-mongodb") | ||
implementation("org.springframework.boot:spring-boot-starter-web") | ||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin") | ||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") | ||
implementation("org.jetbrains.kotlin:kotlin-reflect") | ||
implementation("org.springframework.boot:spring-boot-starter-data-mongodb") | ||
implementation("org.springframework.boot:spring-boot-starter-web") | ||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin") | ||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") | ||
implementation("org.jetbrains.kotlin:kotlin-reflect") | ||
|
||
testImplementation("org.springframework.boot:spring-boot-starter-test") | ||
testImplementation("de.flapdoodle.embed:de.flapdoodle.embed.mongo.spring30x") | ||
testImplementation("org.testcontainers:mongodb") | ||
testImplementation("org.springframework.boot:spring-boot-starter-test") | ||
testImplementation("org.testcontainers:mongodb") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 0 additions & 18 deletions
18
examples/data-mongodb/src/test/resources/application-test.yml
This file was deleted.
Oops, something went wrong.
70 changes: 40 additions & 30 deletions
70
...src/test/kotlin/example/spring/boot/rabbitmq/utils/InitializeWithContainerizedRabbitMQ.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,63 @@ | ||
package example.spring.boot.rabbitmq.utils | ||
|
||
import org.springframework.context.ApplicationContextInitializer | ||
import org.springframework.context.ApplicationListener | ||
import org.springframework.context.ConfigurableApplicationContext | ||
import org.springframework.test.annotation.DirtiesContext | ||
import org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_CLASS | ||
import org.springframework.test.context.ContextConfiguration | ||
import org.springframework.test.context.event.AfterTestClassEvent | ||
import org.springframework.test.context.support.TestPropertySourceUtils.addInlinedPropertiesToEnvironment | ||
import org.testcontainers.containers.RabbitMQContainer | ||
import java.net.Authenticator | ||
import java.net.PasswordAuthentication | ||
import java.net.URI.create | ||
import java.net.http.HttpClient | ||
import java.net.http.HttpRequest | ||
import java.net.http.HttpRequest.BodyPublishers.noBody | ||
import java.net.http.HttpResponse.BodyHandlers.discarding | ||
import java.util.UUID.randomUUID | ||
import kotlin.annotation.AnnotationTarget.CLASS | ||
|
||
@Retention | ||
@Target(CLASS) | ||
@DirtiesContext(classMode = AFTER_CLASS) | ||
@ContextConfiguration(initializers = [RabbitMQInitializer::class]) | ||
annotation class InitializeWithContainerizedRabbitMQ | ||
|
||
class RabbitMQInitializer : ApplicationContextInitializer<ConfigurableApplicationContext> { | ||
|
||
// Unlike other initializers of this kind (e.g. our PostgreSQL and MongoDB examples) RabbitMQ does not have | ||
// anything like separated databases, namespaces or other easy to access / configure mechanisms for isolating | ||
// test (classes) from each other. | ||
|
||
// That is why we are using a new container for each test application context. | ||
|
||
// To safe on resources the test application contexts should be stopped after each test class in order for the | ||
// running container to be stopped as soon as possible. (see @DirtiesContext for how to do that) | ||
|
||
// Alternatives to this approach might be: | ||
// - Use a single container like in the other examples and make sure that each test uses new random topics and | ||
// queues to manually isolate the test from each other. | ||
// - Find some way to drop all queues and topics of the broker programmatically after each test (class). | ||
companion object { | ||
private val container: RabbitMQContainer by lazy { | ||
RabbitMQContainer("rabbitmq:3.13-management") | ||
.apply { start() } | ||
} | ||
private val httpClient: HttpClient by lazy { | ||
HttpClient.newBuilder() | ||
.authenticator(BasicAuthenticator(container.adminUsername, container.adminPassword)) | ||
.build() | ||
} | ||
} | ||
|
||
override fun initialize(applicationContext: ConfigurableApplicationContext) { | ||
val container: RabbitMQContainer = RabbitMQContainer("rabbitmq:3.11") | ||
.apply { start() } | ||
|
||
val listener = StopContainerListener(container) | ||
applicationContext.addApplicationListener(listener) | ||
|
||
val hostProperty = "spring.rabbitmq.host=${container.host}" | ||
val portProperty = "spring.rabbitmq.port=${container.amqpPort}" | ||
|
||
addInlinedPropertiesToEnvironment(applicationContext, hostProperty, portProperty) | ||
val virtualHost = createVirtualHost() | ||
|
||
addInlinedPropertiesToEnvironment( | ||
applicationContext, | ||
"spring.rabbitmq.host=${container.host}", | ||
"spring.rabbitmq.port=${container.amqpPort}", | ||
"spring.rabbitmq.username=${container.adminUsername}", | ||
"spring.rabbitmq.password=${container.adminPassword}", | ||
"spring.rabbitmq.virtual-host=$virtualHost", | ||
) | ||
} | ||
|
||
class StopContainerListener(private val container: RabbitMQContainer) : ApplicationListener<AfterTestClassEvent> { | ||
override fun onApplicationEvent(event: AfterTestClassEvent) = container.stop() | ||
private fun createVirtualHost(): String { | ||
val virtualHost = "${randomUUID()}" | ||
val request = HttpRequest.newBuilder() | ||
.PUT(noBody()) | ||
.uri(create("http://${container.host}:${container.httpPort}/api/vhosts/$virtualHost")) | ||
.build() | ||
httpClient.send(request, discarding()) | ||
return virtualHost | ||
} | ||
|
||
private class BasicAuthenticator(val username: String, val password: String) : Authenticator() { | ||
override fun getPasswordAuthentication() = PasswordAuthentication(username, password.toCharArray()) | ||
} | ||
} |