diff --git a/mongodb/change-streams/pom.xml b/mongodb/change-streams/pom.xml index 9219af6b..0f6b41b8 100644 --- a/mongodb/change-streams/pom.xml +++ b/mongodb/change-streams/pom.xml @@ -31,12 +31,6 @@ test - - de.flapdoodle.embed - de.flapdoodle.embed.mongo - provided - - diff --git a/mongodb/change-streams/src/main/java/example/springdata/mongodb/Person.java b/mongodb/change-streams/src/main/java/example/springdata/mongodb/Person.java index 6d2ce3ef..f7e2a3d1 100644 --- a/mongodb/change-streams/src/main/java/example/springdata/mongodb/Person.java +++ b/mongodb/change-streams/src/main/java/example/springdata/mongodb/Person.java @@ -29,7 +29,5 @@ import org.springframework.data.mongodb.core.mapping.Field; * @author Christoph Strobl */ record Person(@Id ObjectId id, @Field("first_name") String firstname, @Field("last_name") String lastname, int age) { - public Person(String firstname, String lastname, int age) { - this(null, firstname, lastname, age); - } + } diff --git a/mongodb/change-streams/src/test/java/example/springdata/mongodb/ChangeStreamsTests.java b/mongodb/change-streams/src/test/java/example/springdata/mongodb/ChangeStreamsTests.java index 19f58fe3..dd8456c4 100644 --- a/mongodb/change-streams/src/test/java/example/springdata/mongodb/ChangeStreamsTests.java +++ b/mongodb/change-streams/src/test/java/example/springdata/mongodb/ChangeStreamsTests.java @@ -21,19 +21,19 @@ import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Query.*; import static org.springframework.data.mongodb.core.query.Update.*; -import example.springdata.mongodb.util.EmbeddedMongo; -import reactor.test.StepVerifier; - import java.time.Duration; +import com.mongodb.client.MongoClient; +import com.mongodb.client.model.changestream.ChangeStreamDocument; +import com.mongodb.reactivestreams.client.MongoClients; +import example.springdata.mongodb.util.MongoContainers; +import org.assertj.core.api.Assertions; import org.bson.Document; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; - +import org.bson.types.ObjectId; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration; import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -46,11 +46,13 @@ import org.springframework.data.mongodb.core.messaging.ChangeStreamRequest; import org.springframework.data.mongodb.core.messaging.DefaultMessageListenerContainer; import org.springframework.data.mongodb.core.messaging.Message; import org.springframework.data.mongodb.core.messaging.MessageListenerContainer; -import org.springframework.test.context.junit4.SpringRunner; - -import com.mongodb.client.MongoClient; -import com.mongodb.client.model.changestream.ChangeStreamDocument; -import com.mongodb.reactivestreams.client.MongoClients; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +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.test.StepVerifier; /** * A simple Test demonstrating required {@link Configuration} for consumption of MongoDB @@ -60,11 +62,18 @@ import com.mongodb.reactivestreams.client.MongoClients; * @author Christoph Strobl * @author Mark Paluch */ -@RunWith(SpringRunner.class) +@Testcontainers +@ExtendWith(SpringExtension.class) @DataMongoTest public class ChangeStreamsTests { - public static @ClassRule EmbeddedMongo replSet = EmbeddedMongo.replSet().configure(); + @Container // + private static MongoDBContainer mongoDBContainer = MongoContainers.getDefaultContainer(); + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); + } @Autowired MessageListenerContainer container; // for imperative style @@ -72,14 +81,14 @@ public class ChangeStreamsTests { @Autowired ReactiveMongoOperations reactiveTemplate; // for reactive style - Person gabriel = new Person("Gabriel", "Lorca", 30); - Person michael = new Person("Michael", "Burnham", 30); - Person ash = new Person("Ash", "Tyler", 35); + Person gabriel = new Person(new ObjectId(), "Gabriel", "Lorca", 30); + Person michael = new Person(new ObjectId(), "Michael", "Burnham", 30); + Person ash = new Person(new ObjectId(), "Ash", "Tyler", 35); /** * Configuration? Yes we need a bit of it - Do not worry, it won't be much! */ - @SpringBootApplication(exclude = EmbeddedMongoAutoConfiguration.class) + @SpringBootApplication() static class Config { /** @@ -90,7 +99,7 @@ public class ChangeStreamsTests { */ @Bean MongoClient mongoClient() { - return replSet.getMongoClient(); + return com.mongodb.client.MongoClients.create(mongoDBContainer.getReplicaSetUrl()); } /** @@ -100,7 +109,7 @@ public class ChangeStreamsTests { */ @Bean SimpleMongoClientDatabaseFactory mongoDbFactory() { - return new SimpleMongoClientDatabaseFactory(replSet.getMongoClient(), "changestreams"); + return new SimpleMongoClientDatabaseFactory(mongoClient(), "changestreams"); } /** @@ -110,7 +119,7 @@ public class ChangeStreamsTests { */ @Bean SimpleReactiveMongoDatabaseFactory reactiveMongoDatabaseFactory() { - return new SimpleReactiveMongoDatabaseFactory(MongoClients.create(replSet.getConnectionString()), + return new SimpleReactiveMongoDatabaseFactory(MongoClients.create(mongoDBContainer.getReplicaSetUrl()), "changestreams"); } @@ -118,7 +127,7 @@ public class ChangeStreamsTests { * Since listening to a Change Stream using the sync * MongoDB Java Driver is a blocking class, we need to move load to another {@link Thread} by simply using a * {@link MessageListenerContainer}. - *

+ *

* As this is a {@link org.springframework.context.SmartLifecycle smart lifecycle component} we do actually not need * to worry about its lifecycle, the resource allocation and freeing. * diff --git a/mongodb/transactions/pom.xml b/mongodb/transactions/pom.xml index a11745a0..a73c5640 100644 --- a/mongodb/transactions/pom.xml +++ b/mongodb/transactions/pom.xml @@ -31,12 +31,6 @@ test - - de.flapdoodle.embed - de.flapdoodle.embed.mongo - provided - - diff --git a/mongodb/transactions/src/main/java/example/springdata/mongodb/reactive/ReactiveTransitionService.java b/mongodb/transactions/src/main/java/example/springdata/mongodb/reactive/ReactiveTransitionService.java index af538e15..f92a493b 100644 --- a/mongodb/transactions/src/main/java/example/springdata/mongodb/reactive/ReactiveTransitionService.java +++ b/mongodb/transactions/src/main/java/example/springdata/mongodb/reactive/ReactiveTransitionService.java @@ -49,14 +49,10 @@ public class ReactiveTransitionService { public Mono run(Integer id) { - return template.inTransaction().execute(action -> { - return lookup(id) // - .flatMap(process -> start(action, process)) // + .flatMap(process -> start(template, process)) // .flatMap(it -> verify(it)) // - .flatMap(process -> finish(action, process)); - - }).next().map(Process::id); + .flatMap(process -> finish(template, process)).map(Process::id); } private Mono finish(ReactiveMongoOperations operations, Process process) { diff --git a/mongodb/transactions/src/test/java/example/springdata/mongodb/imperative/TransitionServiceTests.java b/mongodb/transactions/src/test/java/example/springdata/mongodb/imperative/TransitionServiceTests.java index 4549a85d..d4df792b 100644 --- a/mongodb/transactions/src/test/java/example/springdata/mongodb/imperative/TransitionServiceTests.java +++ b/mongodb/transactions/src/test/java/example/springdata/mongodb/imperative/TransitionServiceTests.java @@ -15,19 +15,21 @@ */ package example.springdata.mongodb.imperative; -import example.springdata.mongodb.Process; -import example.springdata.mongodb.State; -import example.springdata.mongodb.util.EmbeddedMongo; - import java.util.function.Consumer; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Projections; +import example.springdata.mongodb.Process; +import example.springdata.mongodb.State; +import example.springdata.mongodb.util.MongoContainers; import org.assertj.core.api.Assertions; import org.bson.Document; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; - +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -35,14 +37,14 @@ import org.springframework.data.mongodb.MongoDatabaseFactory; import org.springframework.data.mongodb.MongoTransactionManager; import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; - -import com.mongodb.client.MongoClient; -import com.mongodb.client.model.Filters; -import com.mongodb.client.model.Projections; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; /** * Test showing MongoDB Transaction usage through a synchronous (imperative) API using Spring's managed transactions. @@ -51,11 +53,17 @@ import com.mongodb.client.model.Projections; * @currentRead The Core - Peter V. Brett * @see org.springframework.transaction.annotation.Transactional */ -@RunWith(SpringRunner.class) -@ContextConfiguration +@Testcontainers +@ExtendWith(SpringExtension.class) public class TransitionServiceTests { - public static @ClassRule EmbeddedMongo replSet = EmbeddedMongo.replSet().configure(); + @Container // + private static MongoDBContainer mongoDBContainer = MongoContainers.getDefaultContainer(); + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); + } static final String DB_NAME = "spring-data-tx-examples"; @@ -73,10 +81,9 @@ public class TransitionServiceTests { return new MongoTransactionManager(dbFactory); } - @Override @Bean public MongoClient mongoClient() { - return replSet.getMongoClient(); + return MongoClients.create(mongoDBContainer.getReplicaSetUrl()); } @Override @@ -110,5 +117,4 @@ public class TransitionServiceTests { return State.valueOf(client.getDatabase(DB_NAME).getCollection("processes").find(Filters.eq("_id", process.id())) .projection(Projections.include("state")).first().get("state", String.class)); } - } diff --git a/mongodb/transactions/src/test/java/example/springdata/mongodb/reactive/ReactiveManagedTransitionServiceTests.java b/mongodb/transactions/src/test/java/example/springdata/mongodb/reactive/ReactiveManagedTransitionServiceTests.java index b7f2ff5c..4ccddc9e 100644 --- a/mongodb/transactions/src/test/java/example/springdata/mongodb/reactive/ReactiveManagedTransitionServiceTests.java +++ b/mongodb/transactions/src/test/java/example/springdata/mongodb/reactive/ReactiveManagedTransitionServiceTests.java @@ -17,16 +17,14 @@ package example.springdata.mongodb.reactive; import static org.assertj.core.api.Assertions.*; +import com.mongodb.reactivestreams.client.MongoClients; import example.springdata.mongodb.Process; +import com.mongodb.reactivestreams.client.MongoClient; import example.springdata.mongodb.State; -import example.springdata.mongodb.util.EmbeddedMongo; -import reactor.core.publisher.Flux; -import reactor.test.StepVerifier; - +import example.springdata.mongodb.util.MongoContainers; import org.bson.Document; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -35,13 +33,16 @@ import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory; import org.springframework.data.mongodb.ReactiveMongoTransactionManager; import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration; import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.ReactiveTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; - -import com.mongodb.reactivestreams.client.MongoClient; -import com.mongodb.reactivestreams.client.MongoClients; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import reactor.core.publisher.Flux; +import reactor.test.StepVerifier; /** * Test showing MongoDB Transaction usage through a reactive API. @@ -49,11 +50,17 @@ import com.mongodb.reactivestreams.client.MongoClients; * @author Christoph Strobl * @currentRead The Core - Peter V. Brett */ -@RunWith(SpringRunner.class) -@ContextConfiguration +@Testcontainers +@ExtendWith(SpringExtension.class) public class ReactiveManagedTransitionServiceTests { - public static @ClassRule EmbeddedMongo replSet = EmbeddedMongo.replSet().configure(); + @Container // + private static MongoDBContainer mongoDBContainer = MongoContainers.getDefaultContainer(); + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); + } @Autowired ReactiveManagedTransitionService managedTransitionService; @Autowired MongoClient client; @@ -74,7 +81,7 @@ public class ReactiveManagedTransitionServiceTests { @Bean @Override public MongoClient reactiveMongoClient() { - return MongoClients.create(replSet.getConnectionString()); + return MongoClients.create(mongoDBContainer.getReplicaSetUrl()); } @Override diff --git a/mongodb/transactions/src/test/java/example/springdata/mongodb/reactive/ReactiveTransitionServiceTests.java b/mongodb/transactions/src/test/java/example/springdata/mongodb/reactive/ReactiveTransitionServiceTests.java deleted file mode 100644 index 3a01446f..00000000 --- a/mongodb/transactions/src/test/java/example/springdata/mongodb/reactive/ReactiveTransitionServiceTests.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2018-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package example.springdata.mongodb.reactive; - -import static org.assertj.core.api.Assertions.*; - -import example.springdata.mongodb.Process; -import example.springdata.mongodb.State; -import example.springdata.mongodb.util.EmbeddedMongo; -import reactor.core.publisher.Flux; -import reactor.test.StepVerifier; - -import org.bson.Document; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration; -import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -import com.mongodb.reactivestreams.client.MongoClient; -import com.mongodb.reactivestreams.client.MongoClients; - -/** - * Test showing MongoDB Transaction usage through a reactive API. - * - * @author Christoph Strobl - * @currentRead The Core - Peter V. Brett - */ -@RunWith(SpringRunner.class) -@ContextConfiguration -public class ReactiveTransitionServiceTests { - - public static @ClassRule EmbeddedMongo replSet = EmbeddedMongo.replSet().configure(); - - @Autowired ReactiveTransitionService transitionService; - @Autowired MongoClient client; - - static final String DB_NAME = "spring-data-reactive-tx-examples"; - - @Configuration - @ComponentScan - @EnableReactiveMongoRepositories - static class Config extends AbstractReactiveMongoConfiguration { - - @Bean - @Override - public MongoClient reactiveMongoClient() { - return MongoClients.create(replSet.getConnectionString()); - } - - @Override - protected String getDatabaseName() { - return DB_NAME; - } - } - - @Test - public void reactiveTxCommitRollback() { - - for (var i = 0; i < 10; i++) { - transitionService.newProcess() // - .map(Process::id) // - .flatMap(transitionService::run) // - .onErrorReturn(-1).as(StepVerifier::create) // - .consumeNextWith(val -> {}) // - .verifyComplete(); - } - - Flux.from(client.getDatabase(DB_NAME).getCollection("processes").find(new Document())) // - .buffer(10) // - .as(StepVerifier::create) // - .consumeNextWith(list -> { - - for (var document : list) { - - System.out.println("document: " + document); - - if (document.getInteger("_id") % 3 == 0) { - assertThat(document.getString("state")).isEqualTo(State.CREATED.toString()); - } else { - assertThat(document.getString("state")).isEqualTo(State.DONE.toString()); - } - } - - }) // - .verifyComplete(); - } -} diff --git a/mongodb/transactions/src/test/resources/application.properties b/mongodb/transactions/src/test/resources/application.properties new file mode 100644 index 00000000..50904a88 --- /dev/null +++ b/mongodb/transactions/src/test/resources/application.properties @@ -0,0 +1 @@ +spring.data.mongodb.database=spring-data-tx-examples