diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupportTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupportTests.java index 2fd2542e9..1081317dd 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupportTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupportTests.java @@ -18,6 +18,7 @@ package org.springframework.data.mongodb.core; import static org.assertj.core.api.Assertions.*; import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Query.*; +import static org.springframework.data.mongodb.test.util.DirtiesStateExtension.*; import lombok.AllArgsConstructor; import lombok.Data; @@ -31,9 +32,9 @@ import java.util.stream.Stream; import org.bson.BsonString; import org.bson.BsonValue; import org.bson.Document; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Value; @@ -50,6 +51,7 @@ import org.springframework.data.mongodb.core.mapping.DocumentReference; import org.springframework.data.mongodb.core.mapping.Field; import org.springframework.data.mongodb.core.query.BasicQuery; import org.springframework.data.mongodb.core.query.NearQuery; +import org.springframework.data.mongodb.test.util.DirtiesStateExtension; import org.springframework.data.mongodb.test.util.MongoTemplateExtension; import org.springframework.data.mongodb.test.util.MongoTestTemplate; import org.springframework.data.mongodb.test.util.Template; @@ -60,8 +62,9 @@ import org.springframework.data.mongodb.test.util.Template; * @author Christoph Strobl * @author Mark Paluch */ -@ExtendWith(MongoTemplateExtension.class) -class ExecutableFindOperationSupportTests { +@ExtendWith({ MongoTemplateExtension.class, DirtiesStateExtension.class }) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ExecutableFindOperationSupportTests implements StateFunctions { private static final String STAR_WARS = "star-wars"; private static final String STAR_WARS_PLANETS = "star-wars-universe"; @@ -75,11 +78,13 @@ class ExecutableFindOperationSupportTests { private Planet alderan; private Planet dantooine; - @BeforeEach - void setUp() { - + @Override + public void clear() { template.flush(); + } + @Override + public void setupState() { template.indexOps(Planet.class).ensureIndex( new GeospatialIndex("coordinates").typed(GeoSpatialIndexType.GEO_2DSPHERE).named("planet-coordinate-idx")); @@ -118,6 +123,7 @@ class ExecutableFindOperationSupportTests { } @Test // DATAMONGO-2041 + @DirtiesState void findAllWithProjectionOnEmbeddedType() { luke.father = new Person(); @@ -364,6 +370,7 @@ class ExecutableFindOperationSupportTests { } @Test // DATAMONGO-1734 + @DirtiesState void existsShouldReturnFalseIfNoElementExistsInCollection() { template.remove(new BasicQuery("{}"), STAR_WARS); @@ -491,6 +498,7 @@ class ExecutableFindOperationSupportTests { } @Test // DATAMONGO-1761 + @DirtiesState void distinctReturnsValuesMappedToTheirJavaTypeEvenWhenNotExplicitlyDefinedByTheDomainType() { template.save(new Document("darth", "vader"), STAR_WARS); @@ -499,6 +507,7 @@ class ExecutableFindOperationSupportTests { } @Test // DATAMONGO-1761 + @DirtiesState void distinctReturnsMappedDomainTypeForProjections() { luke.father = new Person(); @@ -511,6 +520,7 @@ class ExecutableFindOperationSupportTests { } @Test // DATAMONGO-1761 + @DirtiesState void distinctAlllowsQueryUsingObjectSourceType() { luke.father = new Person(); @@ -523,6 +533,7 @@ class ExecutableFindOperationSupportTests { } @Test // DATAMONGO-1761 + @DirtiesState void distinctReturnsMappedDomainTypeExtractedFromPropertyWhenNoExplicitTypePresent() { luke.father = new Person(); @@ -570,6 +581,7 @@ class ExecutableFindOperationSupportTests { @Test // GH-2860 @Disabled("GH-3913") + @DirtiesState void propertyProjectionOnDbRef() { WithRefs source = new WithRefs(); @@ -586,6 +598,7 @@ class ExecutableFindOperationSupportTests { } @Test // GH-2860 + @DirtiesState void projectionOnDocRef() { WithRefs source = new WithRefs(); @@ -602,6 +615,7 @@ class ExecutableFindOperationSupportTests { } @Test // GH-2860 + @DirtiesState void propertyProjectionOnDocRef() { WithRefs source = new WithRefs(); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableUpdateOperationSupportTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableUpdateOperationSupportTests.java index d1692e908..8f3d7362e 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableUpdateOperationSupportTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableUpdateOperationSupportTests.java @@ -58,7 +58,7 @@ class ExecutableUpdateOperationSupportTests { @BeforeEach void setUp() { - template.flush(); + template.remove(Person.class).all(); han = new Person(); han.firstname = "han"; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupportTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupportTests.java index e2bc8eb1a..95cf75e17 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupportTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupportTests.java @@ -18,6 +18,7 @@ package org.springframework.data.mongodb.core; import static org.assertj.core.api.Assertions.*; import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Query.*; +import static org.springframework.data.mongodb.test.util.DirtiesStateExtension.*; import lombok.AllArgsConstructor; import lombok.Data; @@ -35,9 +36,10 @@ import java.util.function.Consumer; import org.bson.BsonString; import org.bson.BsonValue; import org.bson.Document; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.beans.factory.annotation.Value; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -50,6 +52,7 @@ import org.springframework.data.mongodb.core.query.BasicQuery; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.NearQuery; import org.springframework.data.mongodb.test.util.Client; +import org.springframework.data.mongodb.test.util.DirtiesStateExtension; import org.springframework.data.mongodb.test.util.MongoClientExtension; import com.mongodb.client.MongoClient; @@ -61,8 +64,9 @@ import com.mongodb.client.MongoClient; * @author Christoph Strobl * @author Juergen Zimmermann */ -@ExtendWith(MongoClientExtension.class) -class ReactiveFindOperationSupportTests { +@ExtendWith({ MongoClientExtension.class, DirtiesStateExtension.class }) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ReactiveFindOperationSupportTests implements StateFunctions { private static final String STAR_WARS = "star-wars"; private MongoTemplate blocking; @@ -74,15 +78,25 @@ class ReactiveFindOperationSupportTests { private Person han; private Person luke; - @BeforeEach void setUp() { - blocking = new MongoTemplate(new SimpleMongoClientDatabaseFactory(client, "ExecutableFindOperationSupportTests")); + template = new ReactiveMongoTemplate(reactiveClient, "ExecutableFindOperationSupportTests"); + } + + @Override + public void clear() { + if (blocking == null) { + setUp(); + } recreateCollection(STAR_WARS, false); + } + @Override + public void setupState() { + if (blocking == null) { + setUp(); + } insertObjects(); - - template = new ReactiveMongoTemplate(reactiveClient, "ExecutableFindOperationSupportTests"); } void insertObjects() { @@ -244,6 +258,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1719 + @DirtiesState void findAllNearBy() { blocking.indexOps(Planet.class).ensureIndex( @@ -264,6 +279,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1719 + @DirtiesState void findAllNearByWithCollectionAndProjection() { blocking.indexOps(Planet.class).ensureIndex( @@ -287,6 +303,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1719 + @DirtiesState void findAllNearByReturningGeoResultContentAsClosedInterfaceProjection() { blocking.indexOps(Planet.class).ensureIndex( @@ -310,6 +327,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1719 + @DirtiesState void findAllNearByReturningGeoResultContentAsOpenInterfaceProjection() { blocking.indexOps(Planet.class).ensureIndex( @@ -333,6 +351,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-2080 + @ProvidesState void tail() throws InterruptedException { recreateCollection(STAR_WARS, true); @@ -361,6 +380,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-2080 + @ProvidesState void tailWithProjection() { recreateCollection(STAR_WARS, true); @@ -374,6 +394,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-2080 + @ProvidesState void tailWithClosedInterfaceProjection() { recreateCollection(STAR_WARS, true); @@ -391,6 +412,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-2080 + @ProvidesState void tailWithOpenInterfaceProjection() { recreateCollection(STAR_WARS, true); @@ -431,6 +453,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1719 + @DirtiesState void existsShouldReturnFalseIfNoElementExistsInCollection() { blocking.remove(new BasicQuery("{}"), STAR_WARS); @@ -462,6 +485,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1761 + @DirtiesState void distinctReturnsSimpleFieldValuesCorrectlyForCollectionHavingReturnTypeSpecifiedThatCanBeConvertedDirectlyByACodec() { Person anakin = new Person(); @@ -476,6 +500,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1761 + @DirtiesState void distinctReturnsSimpleFieldValuesCorrectly() { Person anakin = new Person(); @@ -504,6 +529,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1761 + @DirtiesState void distinctReturnsComplexValuesCorrectly() { Sith sith = new Sith(); @@ -521,6 +547,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1761 + @DirtiesState void distinctReturnsComplexValuesCorrectlyHavingReturnTypeSpecified() { Sith sith = new Sith(); @@ -538,6 +565,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1761 + @DirtiesState void distinctReturnsComplexValuesCorrectlyReturnTypeDocumentSpecified() { Sith sith = new Sith(); @@ -573,6 +601,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1761 + @DirtiesState void distinctReturnsValuesMappedToTheirJavaTypeEvenWhenNotExplicitlyDefinedByTheDomainType() { blocking.save(new Document("darth", "vader"), STAR_WARS); @@ -583,6 +612,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1761 + @DirtiesState void distinctReturnsMappedDomainTypeForProjections() { luke.father = new Person(); @@ -596,6 +626,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1761 + @DirtiesState void distinctAlllowsQueryUsingObjectSourceType() { luke.father = new Person(); @@ -609,6 +640,7 @@ class ReactiveFindOperationSupportTests { } @Test // DATAMONGO-1761 + @DirtiesState void distinctReturnsMappedDomainTypeExtractedFromPropertyWhenNoExplicitTypePresent() { luke.father = new Person(); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUpdateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUpdateTests.java index 47302bf21..0022f2c18 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUpdateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUpdateTests.java @@ -186,7 +186,6 @@ public class ReactiveMongoTemplateUpdateTests { two.author = new Author("Grace", "Hopper"); template.insertAll(Arrays.asList(one, two)).then().as(StepVerifier::create).verifyComplete(); - ; AggregationUpdate update = AggregationUpdate.update() .replaceWith(ReplaceWithOperation.replaceWithValueOf("author")); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java index 940cf3a99..153bb7235 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java @@ -44,15 +44,15 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.core.io.ClassPathResource; -import org.springframework.dao.DataAccessException; import org.springframework.data.annotation.Id; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.geo.Box; import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Point; -import org.springframework.data.mongodb.core.CollectionCallback; +import org.springframework.data.mongodb.core.BulkOperations; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.TestEntities; import org.springframework.data.mongodb.core.Venue; @@ -72,10 +72,7 @@ import org.springframework.data.mongodb.test.util.MongoVersion; import org.springframework.data.mongodb.test.util.Template; import org.springframework.data.util.CloseableIterator; -import com.mongodb.MongoException; import com.mongodb.client.MongoCollection; -import com.mongodb.client.model.InsertOneModel; -import com.mongodb.client.model.WriteModel; /** * Tests for {@link MongoTemplate#aggregate(Aggregation, Class, Class)}. @@ -97,6 +94,7 @@ public class AggregationTests { private static final Log LOGGER = LogFactory.getLog(AggregationTests.class); private static boolean initialized = false; + private static List documents = parseDocuments(); @Template // private static MongoTestTemplate mongoTemplate; @@ -134,30 +132,8 @@ public class AggregationTests { if (!initialized) { mongoTemplate.dropCollection(ZipInfo.class); - mongoTemplate.execute(ZipInfo.class, new CollectionCallback() { - - @Override - public Void doInCollection(MongoCollection collection) throws MongoException, DataAccessException { - - List> docs = new ArrayList<>(); - Scanner scanner = null; - try { - scanner = new Scanner(new BufferedInputStream(new ClassPathResource("zips.json").getInputStream())); - while (scanner.hasNextLine()) { - String zipInfoRecord = scanner.nextLine(); - docs.add(new InsertOneModel<>(Document.parse(zipInfoRecord))); - } - } catch (Exception e) { - if (scanner != null) { - scanner.close(); - } - throw new RuntimeException("Could not load mongodb sample dataset!", e); - } - - collection.bulkWrite(docs); - return null; - } - }); + + mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, ZipInfo.class).insert(documents).execute(); long count = mongoTemplate.count(new Query(), ZipInfo.class); assertThat(count).isEqualTo(29467L); @@ -166,6 +142,27 @@ public class AggregationTests { } } + static List parseDocuments() { + + Scanner scanner = null; + List documents = new ArrayList<>(30000); + + try { + scanner = new Scanner(new BufferedInputStream(new ClassPathResource("zips.json").getInputStream())); + while (scanner.hasNextLine()) { + String zipInfoRecord = scanner.nextLine(); + documents.add(Document.parse(zipInfoRecord)); + } + } catch (Exception e) { + if (scanner != null) { + scanner.close(); + } + throw new RuntimeException("Could not load mongodb sample dataset!", e); + } + + return documents; + } + @Test // DATAMONGO-586 void shouldHandleMissingInputCollection() { assertThatIllegalArgumentException() diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java index 7f325ed2a..a62beee44 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java @@ -35,13 +35,13 @@ import java.util.stream.Stream; import org.assertj.core.api.Assertions; import org.bson.Document; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.IncorrectResultSizeDataAccessException; -import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Example; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -69,6 +69,9 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import org.springframework.data.mongodb.repository.Person.Sex; import org.springframework.data.mongodb.repository.SampleEvaluationContextExtension.SampleSecurityContextHolder; +import org.springframework.data.mongodb.test.util.DirtiesStateExtension; +import org.springframework.data.mongodb.test.util.DirtiesStateExtension.DirtiesState; +import org.springframework.data.mongodb.test.util.DirtiesStateExtension.ProvidesState; import org.springframework.data.mongodb.test.util.EnableIfMongoServerVersion; import org.springframework.data.querydsl.QSort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -84,8 +87,9 @@ import org.springframework.test.util.ReflectionTestUtils; * @author Fırat KÜÇÜK * @author Edward Prentice */ -@ExtendWith(SpringExtension.class) -public abstract class AbstractPersonRepositoryIntegrationTests { +@ExtendWith({ SpringExtension.class, DirtiesStateExtension.class }) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public abstract class AbstractPersonRepositoryIntegrationTests implements DirtiesStateExtension.StateFunctions { @Autowired protected PersonRepository repository; @@ -96,8 +100,11 @@ public abstract class AbstractPersonRepositoryIntegrationTests { List all; - @BeforeEach - public void setUp() throws InterruptedException { + public void clear() { + repository.deleteAll(); + } + + public void setupState() { repository.deleteAll(); @@ -143,6 +150,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test + @DirtiesState void deletesPersonCorrectly() { repository.delete(dave); @@ -153,6 +161,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test + @DirtiesState void deletesPersonByIdCorrectly() { repository.deleteById(dave.getId()); @@ -716,6 +725,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-821 + @DirtiesState void findUsingAnnotatedQueryOnDBRef() { operations.remove(new org.springframework.data.mongodb.core.query.Query(), User.class); @@ -734,6 +744,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-566 + @DirtiesState void deleteByShouldReturnListOfDeletedElementsWhenRetunTypeIsCollectionLike() { List result = repository.deleteByLastname("Beauford"); @@ -742,6 +753,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-566 + @DirtiesState void deleteByShouldRemoveElementsMatchingDerivedQuery() { repository.deleteByLastname("Beauford"); @@ -750,11 +762,13 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-566 + @DirtiesState void deleteByShouldReturnNumberOfDocumentsRemovedIfReturnTypeIsLong() { assertThat(repository.deletePersonByLastname("Beauford")).isEqualTo(1L); } @Test // DATAMONGO-1997 + @DirtiesState void deleteByShouldResultWrappedInOptionalCorrectly() { assertThat(repository.deleteOptionalByLastname("Beauford")).isPresent(); @@ -762,16 +776,19 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-566 + @DirtiesState void deleteByShouldReturnZeroInCaseNoDocumentHasBeenRemovedAndReturnTypeIsNumber() { assertThat(repository.deletePersonByLastname("dorfuaeB")).isEqualTo(0L); } @Test // DATAMONGO-566 + @DirtiesState void deleteByShouldReturnEmptyListInCaseNoDocumentHasBeenRemovedAndReturnTypeIsCollectionLike() { assertThat(repository.deleteByLastname("dorfuaeB")).isEmpty(); } @Test // DATAMONGO-566 + @DirtiesState void deleteByUsingAnnotatedQueryShouldReturnListOfDeletedElementsWhenRetunTypeIsCollectionLike() { List result = repository.removeByLastnameUsingAnnotatedQuery("Beauford"); @@ -780,6 +797,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-566 + @DirtiesState void deleteByUsingAnnotatedQueryShouldRemoveElementsMatchingDerivedQuery() { repository.removeByLastnameUsingAnnotatedQuery("Beauford"); @@ -788,11 +806,13 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-566 + @DirtiesState void deleteByUsingAnnotatedQueryShouldReturnNumberOfDocumentsRemovedIfReturnTypeIsLong() { assertThat(repository.removePersonByLastnameUsingAnnotatedQuery("Beauford")).isEqualTo(1L); } @Test // DATAMONGO-893 + @ProvidesState void findByNestedPropertyInCollectionShouldFindMatchingDocuments() { Person p = new Person("Mary", "Poppins"); @@ -807,6 +827,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-745 + @ProvidesState void findByCustomQueryFirstnamesInListAndLastname() { repository.save(new Person("foo", "bar")); @@ -823,6 +844,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-745 + @ProvidesState void findByCustomQueryLastnameAndStreetInList() { repository.save(new Person("foo", "bar").withAddress(new Address("street1", "1", "SB"))); @@ -840,6 +862,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-950 + @ProvidesState void shouldLimitCollectionQueryToMaxResultsWhenPresent() { repository.saveAll(Arrays.asList(new Person("Bob-1", "Dylan"), new Person("Bob-2", "Dylan"), @@ -849,6 +872,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-950, DATAMONGO-1464 + @ProvidesState void shouldNotLimitPagedQueryWhenPageRequestWithinBounds() { repository.saveAll(Arrays.asList(new Person("Bob-1", "Dylan"), new Person("Bob-2", "Dylan"), @@ -859,6 +883,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-950 + @ProvidesState void shouldLimitPagedQueryWhenPageRequestExceedsUpperBoundary() { repository.saveAll(Arrays.asList(new Person("Bob-1", "Dylan"), new Person("Bob-2", "Dylan"), @@ -868,6 +893,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-950, DATAMONGO-1464 + @ProvidesState void shouldReturnEmptyWhenPageRequestedPageIsTotallyOutOfScopeForLimit() { repository.saveAll(Arrays.asList(new Person("Bob-1", "Dylan"), new Person("Bob-2", "Dylan"), @@ -889,6 +915,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-972 + @DirtiesState void shouldExecuteFindOnDbRefCorrectly() { operations.remove(new org.springframework.data.mongodb.core.query.Query(), User.class); @@ -920,10 +947,9 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-1057 + @ProvidesState void sliceShouldTraverseElementsWithoutSkippingOnes() { - repository.deleteAll(); - List persons = new ArrayList(100); for (int i = 0; i < 100; i++) { // format firstname to assert sorting retains proper order @@ -956,6 +982,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-1085 + @ProvidesState void shouldSupportSortingByQueryDslOrderSpecifier() { repository.deleteAll(); @@ -979,10 +1006,9 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-1085 + @ProvidesState void shouldSupportSortingWithQSortByQueryDslOrderSpecifier() { - repository.deleteAll(); - List persons = new ArrayList(); for (int i = 0; i < 3; i++) { @@ -1001,10 +1027,9 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-1085 + @ProvidesState void shouldSupportSortingWithQSort() { - repository.deleteAll(); - List persons = new ArrayList(); for (int i = 0; i < 3; i++) { @@ -1034,6 +1059,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-1110 + @DirtiesState void executesGeoNearQueryForResultsCorrectlyWhenGivenMinAndMaxDistance() { Point point = new Point(-73.99171, 40.738868); @@ -1075,6 +1101,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-1911 + @DirtiesState void findByUUIDShouldReturnCorrectResult() { dave.setUniqueId(UUID.randomUUID()); @@ -1152,6 +1179,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-1539 + @DirtiesState void deletesPersonsByFirstname() { repository.deleteByThePersonsFirstname("Dave"); @@ -1212,6 +1240,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-2149 + @DirtiesState void annotatedQueryShouldAllowSliceInFieldsProjectionWithDbRef() { operations.remove(new Query(), User.class); @@ -1235,6 +1264,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-2149 + @DirtiesState void annotatedQueryShouldAllowPositionalParameterInFieldsProjection() { Set
addressList = IntStream.range(0, 10).mapToObj(it -> new Address("street-" + it, "zip", "lnz")) @@ -1250,6 +1280,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-2149, DATAMONGO-2154, DATAMONGO-2199 + @DirtiesState void annotatedQueryShouldAllowPositionalParameterInFieldsProjectionWithDbRef() { List userList = IntStream.range(0, 10).mapToObj(it -> { @@ -1358,6 +1389,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-1677 + @DirtiesState void findWithMoreThan10Arguments() { alicia.setSkills(Arrays.asList("musician", "singer", "composer", "actress", "pianist")); @@ -1384,6 +1416,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-1902 + @DirtiesState void findByValueInsideUnwrapped() { Person bart = new Person("bart", "simpson"); @@ -1401,6 +1434,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // DATAMONGO-1902 + @DirtiesState void findByUnwrapped() { Person bart = new Person("bart", "simpson"); @@ -1441,6 +1475,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // GH-3633 + @DirtiesState void annotatedQueryWithNullEqualityCheckShouldWork() { operations.updateFirst(Query.query(Criteria.where("id").is(dave.getId())), Update.update("age", null), @@ -1451,6 +1486,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // GH-3602 + @DirtiesState void executesQueryWithDocumentReferenceCorrectly() { Person josh = new Person("Josh", "Long"); @@ -1466,6 +1502,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // GH-3656 + @DirtiesState void resultProjectionWithOptionalIsExcecutedCorrectly() { carter.setAddress(new Address("batman", "robin", "gotham")); @@ -1479,11 +1516,14 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // GH-2107 + @DirtiesState void shouldAllowToUpdateAllElements() { - assertThat(repository.findAndUpdateViaMethodArgAllByLastname("Matthews", new Update().inc("visits", 1337))).isEqualTo(2); + assertThat(repository.findAndUpdateViaMethodArgAllByLastname("Matthews", new Update().inc("visits", 1337))) + .isEqualTo(2); } @Test // GH-2107 + @DirtiesState void annotatedUpdateIsAppliedCorrectly() { assertThat(repository.findAndIncrementVisitsByLastname("Matthews", 1337)).isEqualTo(2); @@ -1492,6 +1532,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // GH-2107 + @DirtiesState void mixAnnotatedUpdateWithAnnotatedQuery() { assertThat(repository.updateAllByLastname("Matthews", 1337)).isEqualTo(2); @@ -1500,6 +1541,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // GH-2107 + @DirtiesState void annotatedUpdateWithSpELIsAppliedCorrectly() { assertThat(repository.findAndIncrementVisitsUsingSpELByLastname("Matthews", 1337)).isEqualTo(2); @@ -1509,6 +1551,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { @Test // GH-2107 @EnableIfMongoServerVersion(isGreaterThanEqual = "4.2") + @DirtiesState void annotatedAggregationUpdateIsAppliedCorrectly() { repository.findAndIncrementVisitsViaPipelineByLastname("Matthews", 1337); @@ -1517,6 +1560,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // GH-2107 + @DirtiesState void shouldAllowToUpdateAllElementsWithVoidReturn() { repository.findAndUpdateViaMethodArgAllByLastname("Matthews", new Update().inc("visits", 1337)); @@ -1525,11 +1569,13 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test // GH-2107 + @DirtiesState void allowsToUseComplexTypesInUpdate() { Address address = new Address("1007 Mountain Drive", "53540", "Gotham"); assertThat(repository.findAndPushShippingAddressByEmail(dave.getEmail(), address)).isEqualTo(1); - assertThat(repository.findById(dave.getId()).map(Person::getShippingAddresses)).contains(Collections.singleton(address)); + assertThat(repository.findById(dave.getId()).map(Person::getShippingAddresses)) + .contains(Collections.singleton(address)); } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java index 3ff11afbb..2b33b4b44 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java @@ -20,10 +20,10 @@ import static org.springframework.data.domain.Sort.Direction.*; import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Query.*; import static org.springframework.data.mongodb.test.util.Assertions.assertThat; +import static org.springframework.data.mongodb.test.util.DirtiesStateExtension.*; import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.data.mongodb.test.util.EnableIfMongoServerVersion; import reactor.core.Disposable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -35,17 +35,16 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; import org.reactivestreams.Publisher; + import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.dao.IncorrectResultSizeDataAccessException; -import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -64,17 +63,14 @@ import org.springframework.data.mongodb.core.query.UpdateDefinition; import org.springframework.data.mongodb.repository.Person.Sex; import org.springframework.data.mongodb.repository.support.ReactiveMongoRepositoryFactory; import org.springframework.data.mongodb.repository.support.SimpleReactiveMongoRepository; -import org.springframework.data.mongodb.test.util.Client; -import org.springframework.data.mongodb.test.util.MongoClientExtension; -import org.springframework.data.mongodb.test.util.MongoTestUtils; +import org.springframework.data.mongodb.test.util.DirtiesStateExtension; +import org.springframework.data.mongodb.test.util.EnableIfMongoServerVersion; +import org.springframework.data.mongodb.test.util.ReactiveMongoClientClosingTestConfiguration; import org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor; import org.springframework.data.repository.Repository; import org.springframework.data.repository.query.ReactiveQueryMethodEvaluationContextProvider; -import org.springframework.data.mongodb.test.util.ReactiveMongoClientClosingTestConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; -import com.mongodb.reactivestreams.client.MongoClient; - /** * Test for {@link ReactiveMongoRepository} query methods. * @@ -82,12 +78,11 @@ import com.mongodb.reactivestreams.client.MongoClient; * @author Christoph Strobl * @author Jens Schauder */ -@ExtendWith({ MongoClientExtension.class, SpringExtension.class }) -class ReactiveMongoRepositoryTests { +@ExtendWith({ SpringExtension.class, DirtiesStateExtension.class }) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ReactiveMongoRepositoryTests implements DirtiesStateExtension.StateFunctions { private static final int PERSON_COUNT = 7; - private static @Client MongoClient mongoClient; - @Autowired ReactiveMongoTemplate template; @Autowired ReactivePersonRepository repository; @@ -100,12 +95,6 @@ class ReactiveMongoRepositoryTests { @Configuration static class Config extends ReactiveMongoClientClosingTestConfiguration { - @Bean - @Override - public MongoClient reactiveMongoClient() { - return mongoClient; - } - @Override protected String getDatabaseName() { return "reactive"; @@ -144,15 +133,13 @@ class ReactiveMongoRepositoryTests { } } - @BeforeAll - static void cleanDb() { - - MongoTestUtils.createOrReplaceCollectionNow("reactive", "person", mongoClient); - MongoTestUtils.createOrReplaceCollectionNow("reactive", "capped", mongoClient); + @Override + public void clear() { + repository.deleteAll().as(StepVerifier::create).verifyComplete(); } - @BeforeEach - void setUp() throws Exception { + @Override + public void setupState() { repository.deleteAll().as(StepVerifier::create).verifyComplete(); @@ -160,7 +147,11 @@ class ReactiveMongoRepositoryTests { oliver = new Person("Oliver August", "Matthews", 4); carter = new Person("Carter", "Beauford", 49); carter.setSkills(Arrays.asList("Drums", "percussion", "vocals")); - Thread.sleep(10); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } boyd = new Person("Boyd", "Tinsley", 45); boyd.setSkills(Arrays.asList("Violin", "Electric Violin", "Viola", "Mandolin", "Vocals", "Guitar")); stefan = new Person("Stefan", "Lessard", 34); @@ -295,6 +286,7 @@ class ReactiveMongoRepositoryTests { } @Test // DATAMONGO-1444 + @DirtiesState void findsPeopleByLocationWithinCircle() { Point point = new Point(-73.99171, 40.738868); @@ -307,6 +299,7 @@ class ReactiveMongoRepositoryTests { } @Test // DATAMONGO-1444 + @DirtiesState void findsPeopleByPageableLocationWithinCircle() { Point point = new Point(-73.99171, 40.738868); @@ -320,6 +313,7 @@ class ReactiveMongoRepositoryTests { } @Test // DATAMONGO-1444 + @DirtiesState void findsPeopleGeoresultByLocationWithinBox() { Point point = new Point(-73.99171, 40.738868); @@ -335,6 +329,7 @@ class ReactiveMongoRepositoryTests { } @Test // DATAMONGO-1444 + @DirtiesState void findsPeoplePageableGeoresultByLocationWithinBox() throws InterruptedException { Point point = new Point(-73.99171, 40.738868); @@ -355,6 +350,7 @@ class ReactiveMongoRepositoryTests { } @Test // DATAMONGO-1444 + @DirtiesState void findsPeopleByLocationWithinBox() throws InterruptedException { Point point = new Point(-73.99171, 40.738868); @@ -404,12 +400,9 @@ class ReactiveMongoRepositoryTests { } @Test // DATAMONGO-2181 + @ProvidesState void considersRepositoryCollectionName() { - repository.deleteAll() // - .as(StepVerifier::create) // - .verifyComplete(); - contactRepository.deleteAll() // .as(StepVerifier::create) // .verifyComplete(); @@ -450,8 +443,7 @@ class ReactiveMongoRepositoryTests { .collectList() // .as(StepVerifier::create) // .assertNext(actual -> { - assertThat(actual) - .contains("Lessard", "Keys", "Tinsley", "Beauford", "Moore", "Matthews"); + assertThat(actual).contains("Lessard", "Keys", "Tinsley", "Beauford", "Moore", "Matthews"); }).verifyComplete(); } @@ -554,6 +546,7 @@ class ReactiveMongoRepositoryTests { } @Test // DATAMONGO-2403 + @DirtiesState void annotatedAggregationExtractingSimpleValueIsEmptyForEmptyDocument() { Person p = new Person("project-on-lastanme", null); @@ -565,6 +558,7 @@ class ReactiveMongoRepositoryTests { } @Test // DATAMONGO-2403 + @DirtiesState void annotatedAggregationSkipsEmptyDocumentsWhenExtractingSimpleValue() { String firstname = "project-on-lastanme"; @@ -584,6 +578,7 @@ class ReactiveMongoRepositoryTests { } @Test // DATAMONGO-2406 + @DirtiesState void deleteByShouldHandleVoidResultTypeCorrectly() { repository.deleteByLastname(dave.getLastname()) // @@ -596,6 +591,7 @@ class ReactiveMongoRepositoryTests { } @Test // DATAMONGO-1997 + @DirtiesState void deleteByShouldAllowDeletedCountAsResult() { repository.deleteCountByLastname(dave.getLastname()) // @@ -605,6 +601,7 @@ class ReactiveMongoRepositoryTests { } @Test // DATAMONGO-1997 + @DirtiesState void deleteByShouldAllowSingleDocumentRemovalCorrectly() { repository.deleteSinglePersonByLastname(carter.getLastname()) // @@ -618,6 +615,7 @@ class ReactiveMongoRepositoryTests { } @Test // DATAMONGO-2652 + @DirtiesState void deleteAllById() { repository.deleteAllById(Arrays.asList(carter.id, dave.id)) // @@ -630,74 +628,57 @@ class ReactiveMongoRepositoryTests { } @Test // GH-2107 + @DirtiesState void shouldAllowToUpdateAllElements() { repository.findAndUpdateViaMethodArgAllByLastname("Matthews", new Update().inc("visits", 1337)) - .as(StepVerifier::create) - .expectNext(2L) - .verifyComplete(); + .as(StepVerifier::create).expectNext(2L).verifyComplete(); } @Test // GH-2107 + @DirtiesState void mixAnnotatedUpdateWithAnnotatedQuery() { - repository.updateAllByLastname("Matthews", 1337) - .as(StepVerifier::create) - .expectNext(2L) - .verifyComplete(); + repository.updateAllByLastname("Matthews", 1337).as(StepVerifier::create).expectNext(2L).verifyComplete(); - repository.findByLastname("Matthews") - .map(Person::getVisits) - .as(StepVerifier::create) - .expectNext(1337, 1337) + repository.findByLastname("Matthews").map(Person::getVisits).as(StepVerifier::create).expectNext(1337, 1337) .verifyComplete(); } @Test // GH-2107 + @DirtiesState void annotatedUpdateWithSpELIsAppliedCorrectly() { - repository.findAndIncrementVisitsUsingSpELByLastname("Matthews", 1337) - .as(StepVerifier::create) - .expectNext(2L) + repository.findAndIncrementVisitsUsingSpELByLastname("Matthews", 1337).as(StepVerifier::create).expectNext(2L) .verifyComplete(); - repository.findByLastname("Matthews") - .map(Person::getVisits) - .as(StepVerifier::create) - .expectNext(1337, 1337) + repository.findByLastname("Matthews").map(Person::getVisits).as(StepVerifier::create).expectNext(1337, 1337) .verifyComplete(); } @Test // GH-2107 + @DirtiesState @EnableIfMongoServerVersion(isGreaterThanEqual = "4.2") void annotatedAggregationUpdateIsAppliedCorrectly() { - repository.findAndIncrementVisitsViaPipelineByLastname("Matthews", 1337) - .as(StepVerifier::create) - .verifyComplete(); + repository.findAndIncrementVisitsViaPipelineByLastname("Matthews", 1337).as(StepVerifier::create).verifyComplete(); - repository.findByLastname("Matthews") - .map(Person::getVisits) - .as(StepVerifier::create) - .expectNext(1337, 1337) + repository.findByLastname("Matthews").map(Person::getVisits).as(StepVerifier::create).expectNext(1337, 1337) .verifyComplete(); } @Test // GH-2107 + @DirtiesState void shouldAllowToUpdateAllElementsWithVoidReturn() { - repository.findAndIncrementVisitsByLastname("Matthews", 1337) - .as(StepVerifier::create) - .expectNext(2L) + repository.findAndIncrementVisitsByLastname("Matthews", 1337).as(StepVerifier::create).expectNext(2L) .verifyComplete(); - repository.findByLastname("Matthews") - .map(Person::getVisits) - .as(StepVerifier::create) - .expectNext(1337, 1337) + repository.findByLastname("Matthews").map(Person::getVisits).as(StepVerifier::create).expectNext(1337, 1337) .verifyComplete(); } @Test // GH-2107 + @DirtiesState void allowsToUseComplexTypesInUpdate() { Address address = new Address("1007 Mountain Drive", "53540", "Gotham"); @@ -707,10 +688,8 @@ class ReactiveMongoRepositoryTests { .expectNext(1L) // .verifyComplete(); - repository.findById(dave.getId()).map(Person::getShippingAddresses) - .as(StepVerifier::create) - .consumeNextWith(it -> assertThat(it).containsExactly(address)) - .verifyComplete(); + repository.findById(dave.getId()).map(Person::getShippingAddresses).as(StepVerifier::create) + .consumeNextWith(it -> assertThat(it).containsExactly(address)).verifyComplete(); } interface ReactivePersonRepository @@ -799,7 +778,8 @@ class ReactiveMongoRepositoryTests { @org.springframework.data.mongodb.repository.Update("{ '$inc' : { 'visits' : ?1 } }") Mono updateAllByLastname(String lastname, int increment); - @org.springframework.data.mongodb.repository.Update( pipeline = {"{ '$set' : { 'visits' : { '$add' : [ '$visits', ?1 ] } } }"}) + @org.springframework.data.mongodb.repository.Update( + pipeline = { "{ '$set' : { 'visits' : { '$add' : [ '$visits', ?1 ] } } }" }) Mono findAndIncrementVisitsViaPipelineByLastname(String lastname, int increment); @org.springframework.data.mongodb.repository.Update("{ '$inc' : { 'visits' : ?#{[1]} } }") diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/config/MongoNamespaceIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/config/MongoNamespaceIntegrationTests.java index 4f5ee3082..f6a66e616 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/config/MongoNamespaceIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/config/MongoNamespaceIntegrationTests.java @@ -47,9 +47,7 @@ class MongoNamespaceIntegrationTests extends AbstractPersonRepositoryIntegration @Autowired ApplicationContext context; @BeforeEach - @Override public void setUp() throws InterruptedException { - super.setUp(); factory = new DefaultListableBeanFactory(); reader = new XmlBeanDefinitionReader(factory); } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepositoryTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepositoryTests.java index 6661b15c0..7f282c8c7 100755 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepositoryTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepositoryTests.java @@ -18,6 +18,7 @@ package org.springframework.data.mongodb.repository.support; import static java.util.Arrays.*; import static org.assertj.core.api.Assertions.*; import static org.springframework.data.domain.ExampleMatcher.*; +import static org.springframework.data.mongodb.test.util.DirtiesStateExtension.*; import java.util.ArrayList; import java.util.HashMap; @@ -29,6 +30,7 @@ import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.dao.IncorrectResultSizeDataAccessException; @@ -48,6 +50,7 @@ import org.springframework.data.mongodb.repository.Person; import org.springframework.data.mongodb.repository.Person.Sex; import org.springframework.data.mongodb.repository.User; import org.springframework.data.mongodb.repository.query.MongoEntityInformation; +import org.springframework.data.mongodb.test.util.DirtiesStateExtension; import org.springframework.data.mongodb.test.util.EnableIfMongoServerVersion; import org.springframework.data.mongodb.test.util.EnableIfReplicaSetAvailable; import org.springframework.data.mongodb.test.util.MongoServerCondition; @@ -65,8 +68,9 @@ import org.springframework.transaction.support.TransactionTemplate; * @author Mark Paluch * @author Jens Schauder */ -@ExtendWith({ MongoTemplateExtension.class, MongoServerCondition.class }) -class SimpleMongoRepositoryTests { +@ExtendWith({ MongoTemplateExtension.class, MongoServerCondition.class, DirtiesStateExtension.class }) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class SimpleMongoRepositoryTests implements StateFunctions { @Template(initialEntitySet = Person.class) // private static MongoTestTemplate template; @@ -75,13 +79,25 @@ class SimpleMongoRepositoryTests { private List all; private MongoEntityInformation personEntityInformation = new CustomizedPersonInformation(); - private SimpleMongoRepository repository = new SimpleMongoRepository<>(personEntityInformation, - template); + private SimpleMongoRepository repository; @BeforeEach void setUp() { + repository = new SimpleMongoRepository<>(personEntityInformation, template); + } + + @Override + public void clear() { + + if (repository == null) { + setUp(); + } repository.deleteAll(); + } + + @Override + public void setupState() { oliver = new Person("Oliver August", "Matthews", 4); dave = new Person("Dave", "Matthews", 42); @@ -105,6 +121,7 @@ class SimpleMongoRepositoryTests { } @Test + @DirtiesState void deleteFromCustomCollectionName() { repository.delete(dave); @@ -113,6 +130,7 @@ class SimpleMongoRepositoryTests { } @Test + @DirtiesState void deleteByIdFromCustomCollectionName() { repository.deleteById(dave.getId()); @@ -121,6 +139,7 @@ class SimpleMongoRepositoryTests { } @Test // DATAMONGO-1054 + @DirtiesState void shouldInsertSingle() { String randomId = UUID.randomUUID().toString(); @@ -132,6 +151,7 @@ class SimpleMongoRepositoryTests { } @Test // DATAMONGO-1054 + @DirtiesState void shouldInsertMultipleFromList() { String randomId = UUID.randomUUID().toString(); @@ -151,6 +171,7 @@ class SimpleMongoRepositoryTests { } @Test // DATAMONGO-1054 + @DirtiesState void shouldInsertMutlipleFromSet() { String randomId = UUID.randomUUID().toString(); @@ -219,6 +240,7 @@ class SimpleMongoRepositoryTests { } @Test // DATAMONGO-1245 + @DirtiesState void findAllByExampleShouldLookUpEntriesCorrectlyWhenUsingNestedObject() { dave.setAddress(new Address("1600 Pennsylvania Ave NW", "20500", "Washington")); @@ -235,6 +257,7 @@ class SimpleMongoRepositoryTests { } @Test // DATAMONGO-1245 + @DirtiesState void findAllByExampleShouldLookUpEntriesCorrectlyWhenUsingPartialNestedObject() { dave.setAddress(new Address("1600 Pennsylvania Ave NW", "20500", "Washington")); @@ -251,6 +274,7 @@ class SimpleMongoRepositoryTests { } @Test // DATAMONGO-1245 + @DirtiesState void findAllByExampleShouldNotFindEntriesWhenUsingPartialNestedObjectInStrictMode() { dave.setAddress(new Address("1600 Pennsylvania Ave NW", "20500", "Washington")); @@ -266,6 +290,7 @@ class SimpleMongoRepositoryTests { } @Test // DATAMONGO-1245 + @DirtiesState void findAllByExampleShouldLookUpEntriesCorrectlyWhenUsingNestedObjectInStrictMode() { dave.setAddress(new Address("1600 Pennsylvania Ave NW", "20500", "Washington")); @@ -293,6 +318,7 @@ class SimpleMongoRepositoryTests { } @Test // DATAMONGO-1245 + @DirtiesState void findAllByExampleShouldResolveDbRefCorrectly() { User user = new User(); @@ -313,6 +339,7 @@ class SimpleMongoRepositoryTests { } @Test // DATAMONGO-1245 + @DirtiesState void findAllByExampleShouldResolveLegacyCoordinatesCorrectly() { Person megan = new Person("megan", "tarash"); @@ -328,6 +355,7 @@ class SimpleMongoRepositoryTests { } @Test // DATAMONGO-1245 + @DirtiesState void findAllByExampleShouldResolveGeoJsonCoordinatesCorrectly() { Person megan = new Person("megan", "tarash"); @@ -343,6 +371,7 @@ class SimpleMongoRepositoryTests { } @Test // DATAMONGO-1245 + @DirtiesState void findAllByExampleShouldProcessInheritanceCorrectly() { PersonExtended reference = new PersonExtended(); @@ -391,6 +420,7 @@ class SimpleMongoRepositoryTests { } @Test // DATAMONGO-1896 + @DirtiesState void saveAllUsesEntityCollection() { Person first = new PersonExtended(); @@ -411,6 +441,7 @@ class SimpleMongoRepositoryTests { @Test // DATAMONGO-2130 @EnableIfReplicaSetAvailable @EnableIfMongoServerVersion(isGreaterThanEqual = "4.0") + @DirtiesState void countShouldBePossibleInTransaction() { MongoTransactionManager txmgr = new MongoTransactionManager(template.getMongoDbFactory()); @@ -435,6 +466,7 @@ class SimpleMongoRepositoryTests { @Test // DATAMONGO-2130 @EnableIfReplicaSetAvailable @EnableIfMongoServerVersion(isGreaterThanEqual = "4.0") + @DirtiesState void existsShouldBePossibleInTransaction() { MongoTransactionManager txmgr = new MongoTransactionManager(template.getMongoDbFactory()); @@ -455,6 +487,7 @@ class SimpleMongoRepositoryTests { } @Test // DATAMONGO-2652 + @DirtiesState void deleteAllByIds() { repository.deleteAllById(asList(dave.getId(), carter.getId())); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/DirtiesStateExtension.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/DirtiesStateExtension.java new file mode 100644 index 000000000..cc95bc34a --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/DirtiesStateExtension.java @@ -0,0 +1,112 @@ +/* + * Copyright 2022 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 org.springframework.data.mongodb.test.util; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; + +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +/** + * Extension to consider tests that {@code @DirtiesState} and {@code @ProvidesState} through annotations. + * + * @author Mark Paluch + */ +public class DirtiesStateExtension implements BeforeEachCallback, AfterEachCallback { + + /** + * Test method that changes the data state by saving or deleting objects. + */ + @Retention(RetentionPolicy.RUNTIME) + public @interface DirtiesState { + + } + + /** + * Test method that sets up its state within the test method itself. + */ + @Retention(RetentionPolicy.RUNTIME) + public @interface ProvidesState { + + } + + /** + * Interface to be implemented by tests that make use of {@link DirtiesStateExtension}. + */ + public interface StateFunctions { + + /** + * Clear the state. + */ + void clear(); + + /** + * Setup the test fixture. + */ + void setupState(); + } + + static final String STATE_KEY = "state"; + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + + Method method = context.getTestMethod().orElse(null); + Object instance = context.getTestInstance().orElse(null); + + if (method == null || instance == null) { + return; + } + + if (method.isAnnotationPresent(ProvidesState.class)) { + ((StateFunctions) instance).clear(); + return; + } + + ExtensionContext.Store mongo = getStore(context); + Boolean state = mongo.get(STATE_KEY, Boolean.class); + + if (state == null) { + + ((StateFunctions) instance).clear(); + ((StateFunctions) instance).setupState(); + mongo.put(STATE_KEY, true); + } + } + + private ExtensionContext.Store getStore(ExtensionContext context) { + return context.getParent().get() + .getStore(ExtensionContext.Namespace.create("mongo-" + context.getRequiredTestClass().getName())); + } + + @Override + public void afterEach(ExtensionContext context) throws Exception { + + Method method = context.getTestMethod().orElse(null); + + if (method == null) { + return; + } + + if (method.isAnnotationPresent(DirtiesState.class) || method.isAnnotationPresent(ProvidesState.class)) { + ExtensionContext.Store mongo = getStore(context); + mongo.remove(STATE_KEY); + } + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTemplateExtension.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTemplateExtension.java index ef3878a81..5c0f67e74 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTemplateExtension.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTemplateExtension.java @@ -25,6 +25,7 @@ import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext.Store; import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.TestInstancePostProcessor; import org.junit.platform.commons.util.AnnotationUtils; import org.junit.platform.commons.util.ExceptionUtils; import org.junit.platform.commons.util.ReflectionUtils; @@ -44,7 +45,7 @@ import org.springframework.util.ClassUtils; * @see MongoTestTemplate * @see ReactiveMongoTestTemplate */ -public class MongoTemplateExtension extends MongoClientExtension { +public class MongoTemplateExtension extends MongoClientExtension implements TestInstancePostProcessor { private static final String DEFAULT_DATABASE = "database"; @@ -56,6 +57,11 @@ public class MongoTemplateExtension extends MongoClientExtension { injectFields(context, null, ReflectionUtils::isStatic); } + @Override + public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception { + injectFields(context, testInstance, it -> true); + } + @Override public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { @@ -142,4 +148,5 @@ public class MongoTemplateExtension extends MongoClientExtension { throw new IllegalStateException("Damn - something went wrong."); } + }