/* * Copyright 2016-2017 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 * * http://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.core; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Query.*; import lombok.Data; import reactor.core.Disposable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import org.bson.Document; import org.bson.types.ObjectId; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.data.annotation.Id; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.geo.Metrics; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mongodb.core.MongoTemplateTests.PersonWithConvertedId; import org.springframework.data.mongodb.core.MongoTemplateTests.VersionedPerson; import org.springframework.data.mongodb.core.index.GeoSpatialIndexType; import org.springframework.data.mongodb.core.index.GeospatialIndex; import org.springframework.data.mongodb.core.index.Index; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.NearQuery; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.mongodb.WriteConcern; /** * Integration test for {@link MongoTemplate}. * * @author Mark Paluch * @author Christoph Strobl */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:reactive-infrastructure.xml") public class ReactiveMongoTemplateTests { @Rule public ExpectedException thrown = ExpectedException.none(); @Autowired SimpleReactiveMongoDatabaseFactory factory; @Autowired ReactiveMongoTemplate template; @Before public void setUp() { StepVerifier .create(template.dropCollection("people") // .mergeWith(template.dropCollection("collection")) // .mergeWith(template.dropCollection(Person.class)) // .mergeWith(template.dropCollection(Venue.class)) // .mergeWith(template.dropCollection(PersonWithAList.class)) // .mergeWith(template.dropCollection(PersonWithIdPropertyOfTypeObjectId.class)) // .mergeWith(template.dropCollection(PersonWithVersionPropertyOfTypeInteger.class)) // .mergeWith(template.dropCollection(Sample.class))) // .verifyComplete(); } @After public void cleanUp() {} @Test // DATAMONGO-1444 public void insertSetsId() { PersonWithAList person = new PersonWithAList(); assert person.getId() == null; StepVerifier.create(template.insert(person)).expectNextCount(1).verifyComplete(); assertThat(person.getId(), is(notNullValue())); } @Test // DATAMONGO-1444 public void insertAllSetsId() { PersonWithAList person = new PersonWithAList(); StepVerifier.create(template.insertAll(Collections.singleton(person))).expectNextCount(1).verifyComplete(); assertThat(person.getId(), is(notNullValue())); } @Test // DATAMONGO-1444 public void insertCollectionSetsId() { PersonWithAList person = new PersonWithAList(); StepVerifier.create(template.insert(Collections.singleton(person), PersonWithAList.class)).expectNextCount(1) .verifyComplete(); assertThat(person.getId(), is(notNullValue())); } @Test // DATAMONGO-1444 public void saveSetsId() { PersonWithAList person = new PersonWithAList(); assert person.getId() == null; StepVerifier.create(template.save(person)).expectNextCount(1).verifyComplete(); assertThat(person.getId(), is(notNullValue())); } @Test // DATAMONGO-1444 public void insertsSimpleEntityCorrectly() { Person person = new Person("Mark"); person.setAge(35); StepVerifier.create(template.insert(person)).expectNextCount(1).verifyComplete(); StepVerifier.create(template.find(new Query(where("_id").is(person.getId())), Person.class)) // .expectNext(person) // .verifyComplete(); } @Test // DATAMONGO-1444 public void simpleInsertDoesNotAllowArrays() { thrown.expect(IllegalArgumentException.class); Person person = new Person("Mark"); person.setAge(35); template.insert(new Person[] { person }); } @Test // DATAMONGO-1444 public void simpleInsertDoesNotAllowCollections() { thrown.expect(IllegalArgumentException.class); Person person = new Person("Mark"); person.setAge(35); template.insert(Collections.singletonList(person)); } @Test // DATAMONGO-1444 public void insertsSimpleEntityWithSuppliedCollectionNameCorrectly() { Person person = new Person("Homer"); person.setAge(35); StepVerifier.create(template.insert(person, "people")).expectNextCount(1).verifyComplete(); StepVerifier.create(template.find(new Query(where("_id").is(person.getId())), Person.class, "people")) // .expectNext(person) // .verifyComplete(); } @Test // DATAMONGO-1444 public void insertBatchCorrectly() { List<Person> people = Arrays.asList(new Person("Dick", 22), new Person("Harry", 23), new Person("Tom", 21)); StepVerifier.create(template.insertAll(people)).expectNextCount(3).verifyComplete(); StepVerifier.create(template.find(new Query().with(Sort.by("firstname")), Person.class)) // .expectNextSequence(people) // .verifyComplete(); } @Test // DATAMONGO-1444 public void insertBatchWithSuppliedCollectionNameCorrectly() { List<Person> people = Arrays.asList(new Person("Dick", 22), new Person("Harry", 23), new Person("Tom", 21)); StepVerifier.create(template.insert(people, "people")).expectNextCount(3).verifyComplete(); StepVerifier.create(template.find(new Query().with(Sort.by("firstname")), Person.class, "people")) // .expectNextSequence(people) // .verifyComplete(); } @Test // DATAMONGO-1444 public void insertBatchWithSuppliedEntityTypeCorrectly() { List<Person> people = Arrays.asList(new Person("Dick", 22), new Person("Harry", 23), new Person("Tom", 21)); StepVerifier.create(template.insert(people, Person.class)).expectNextCount(3).verifyComplete(); StepVerifier.create(template.find(new Query().with(Sort.by("firstname")), Person.class)) // .expectNextSequence(people) // .verifyComplete(); } @Test // DATAMONGO-1444 public void testAddingToList() { PersonWithAList person = createPersonWithAList("Sven", 22); StepVerifier.create(template.insert(person)).expectNextCount(1).verifyComplete(); Query query = new Query(where("id").is(person.getId())); StepVerifier.create(template.findOne(query, PersonWithAList.class)).consumeNextWith(actual -> { assertThat(actual.getWishList().size(), is(0)); }).verifyComplete(); person.addToWishList("please work!"); StepVerifier.create(template.save(person)).expectNextCount(1).verifyComplete(); StepVerifier.create(template.findOne(query, PersonWithAList.class)).consumeNextWith(actual -> { assertThat(actual.getWishList().size(), is(1)); }).verifyComplete(); Friend friend = new Friend(); person.setFirstName("Erik"); person.setAge(21); person.addFriend(friend); StepVerifier.create(template.save(person)).expectNextCount(1).verifyComplete(); StepVerifier.create(template.findOne(query, PersonWithAList.class)).consumeNextWith(actual -> { assertThat(actual.getWishList().size(), is(1)); assertThat(actual.getFriends().size(), is(1)); }).verifyComplete(); } @Test // DATAMONGO-1444 public void testFindOneWithSort() { PersonWithAList sven = createPersonWithAList("Sven", 22); PersonWithAList erik = createPersonWithAList("Erik", 21); PersonWithAList mark = createPersonWithAList("Mark", 40); StepVerifier.create(template.insertAll(Arrays.asList(sven, erik, mark))).expectNextCount(3).verifyComplete(); // test query with a sort Query query = new Query(where("age").gt(10)); query.with(Sort.by(Direction.DESC, "age")); StepVerifier.create(template.findOne(query, PersonWithAList.class)).consumeNextWith(actual -> { assertThat(actual.getFirstName(), is("Mark")); }).verifyComplete(); } @Test // DATAMONGO-1444 public void bogusUpdateDoesNotTriggerException() { ReactiveMongoTemplate mongoTemplate = new ReactiveMongoTemplate(factory); mongoTemplate.setWriteResultChecking(WriteResultChecking.EXCEPTION); Person oliver = new Person("Oliver2", 25); StepVerifier.create(template.insert(oliver)).expectNextCount(1).verifyComplete(); Query q = new Query(where("BOGUS").gt(22)); Update u = new Update().set("firstName", "Sven"); StepVerifier.create(mongoTemplate.updateFirst(q, u, Person.class)).expectNextCount(1).verifyComplete(); } @Test // DATAMONGO-1444 public void updateFirstByEntityTypeShouldUpdateObject() { Person person = new Person("Oliver2", 25); StepVerifier.create(template.insert(person) // .then(template.updateFirst(new Query(where("age").is(25)), new Update().set("firstName", "Sven"), Person.class)) // .flatMapMany(p -> template.find(new Query(where("age").is(25)), Person.class))).consumeNextWith(actual -> { assertThat(actual.getFirstName(), is(equalTo("Sven"))); }).verifyComplete(); } @Test // DATAMONGO-1444 public void updateFirstByCollectionNameShouldUpdateObjects() { Person person = new Person("Oliver2", 25); StepVerifier .create(template.insert(person, "people") // .then(template.updateFirst(new Query(where("age").is(25)), new Update().set("firstName", "Sven"), "people")) // .flatMapMany(p -> template.find(new Query(where("age").is(25)), Person.class, "people"))) .consumeNextWith(actual -> { assertThat(actual.getFirstName(), is(equalTo("Sven"))); }).verifyComplete(); } @Test // DATAMONGO-1444 public void updateMultiByEntityTypeShouldUpdateObjects() { Query query = new Query( new Criteria().orOperator(where("firstName").is("Walter Jr"), Criteria.where("firstName").is("Walter"))); StepVerifier .create(template .insertAll(Mono .just(Arrays.asList(new Person("Walter", 50), new Person("Skyler", 43), new Person("Walter Jr", 16)))) // .flatMap(a -> template.updateMulti(query, new Update().set("firstName", "Walt"), Person.class)) // .thenMany(template.find(new Query(where("firstName").is("Walt")), Person.class))) // .expectNextCount(2) // .verifyComplete(); } @Test // DATAMONGO-1444 public void updateMultiByCollectionNameShouldUpdateObject() { Query query = new Query( new Criteria().orOperator(where("firstName").is("Walter Jr"), Criteria.where("firstName").is("Walter"))); List<Person> people = Arrays.asList(new Person("Walter", 50), // new Person("Skyler", 43), // new Person("Walter Jr", 16)); Flux<Person> personFlux = template.insertAll(Mono.just(people), "people") // .collectList() // .flatMap(a -> template.updateMulti(query, new Update().set("firstName", "Walt"), Person.class, "people")) // .flatMapMany(p -> template.find(new Query(where("firstName").is("Walt")), Person.class, "people")); StepVerifier.create(personFlux) // .expectNextCount(2) // .verifyComplete(); } @Test // DATAMONGO-1444 public void throwsExceptionForDuplicateIds() { ReactiveMongoTemplate template = new ReactiveMongoTemplate(factory); template.setWriteResultChecking(WriteResultChecking.EXCEPTION); Person person = new Person(new ObjectId(), "Amol"); person.setAge(28); StepVerifier.create(template.insert(person)).expectNextCount(1).verifyComplete(); StepVerifier.create(template.insert(person)).expectError(DataIntegrityViolationException.class).verify(); } @Test // DATAMONGO-1444 public void throwsExceptionForUpdateWithInvalidPushOperator() { ReactiveMongoTemplate template = new ReactiveMongoTemplate(factory); template.setWriteResultChecking(WriteResultChecking.EXCEPTION); ObjectId id = new ObjectId(); Person person = new Person(id, "Amol"); person.setAge(28); StepVerifier.create(template.insert(person)).expectNextCount(1).verifyComplete(); Query query = new Query(where("firstName").is("Amol")); Update upd = new Update().push("age", 29); StepVerifier.create(template.updateFirst(query, upd, Person.class)) // .expectError(DataIntegrityViolationException.class) // .verify(); } @Test // DATAMONGO-1444 public void rejectsDuplicateIdInInsertAll() { ReactiveMongoTemplate template = new ReactiveMongoTemplate(factory); template.setWriteResultChecking(WriteResultChecking.EXCEPTION); ObjectId id = new ObjectId(); Person person = new Person(id, "Amol"); person.setAge(28); StepVerifier.create(template.insertAll(Arrays.asList(person, person))) // .expectError(DataIntegrityViolationException.class) // .verify(); } @Test // DATAMONGO-1444 public void testFindAndUpdate() { StepVerifier .create( template.insertAll(Arrays.asList(new Person("Tom", 21), new Person("Dick", 22), new Person("Harry", 23)))) // .expectNextCount(3) // .verifyComplete(); Query query = new Query(Criteria.where("firstName").is("Harry")); Update update = new Update().inc("age", 1); Person p = template.findAndModify(query, update, Person.class).block(); // return old assertThat(p.getFirstName(), is("Harry")); assertThat(p.getAge(), is(23)); p = template.findOne(query, Person.class).block(); assertThat(p.getAge(), is(24)); p = template.findAndModify(query, update, Person.class, "person").block(); assertThat(p.getAge(), is(24)); p = template.findOne(query, Person.class).block(); assertThat(p.getAge(), is(25)); p = template.findAndModify(query, update, new FindAndModifyOptions().returnNew(true), Person.class).block(); assertThat(p.getAge(), is(26)); p = template.findAndModify(query, update, null, Person.class, "person").block(); assertThat(p.getAge(), is(26)); p = template.findOne(query, Person.class).block(); assertThat(p.getAge(), is(27)); Query query2 = new Query(Criteria.where("firstName").is("Mary")); p = template.findAndModify(query2, update, new FindAndModifyOptions().returnNew(true).upsert(true), Person.class) .block(); assertThat(p.getFirstName(), is("Mary")); assertThat(p.getAge(), is(1)); } @Test // DATAMONGO-1444 public void testFindAllAndRemoveFullyReturnsAndRemovesDocuments() { Sample spring = new Sample("100", "spring"); Sample data = new Sample("200", "data"); Sample mongodb = new Sample("300", "mongodb"); StepVerifier.create(template.insert(Arrays.asList(spring, data, mongodb), Sample.class)) // .expectNextCount(3) // .verifyComplete(); Query qry = query(where("field").in("spring", "mongodb")); StepVerifier.create(template.findAllAndRemove(qry, Sample.class)).expectNextCount(2).verifyComplete(); StepVerifier.create(template.findOne(new Query(), Sample.class)).expectNext(data).verifyComplete(); } @Test // DATAMONGO-1444 public void optimisticLockingHandling() { // Init version PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger(); person.age = 29; person.firstName = "Patryk"; StepVerifier.create(template.save(person)).expectNextCount(1).verifyComplete(); StepVerifier.create(template.findAll(PersonWithVersionPropertyOfTypeInteger.class)).consumeNextWith(actual -> { assertThat(actual.version, is(0)); }).verifyComplete(); StepVerifier.create(template.findAll(PersonWithVersionPropertyOfTypeInteger.class).flatMap(p -> { // Version change person.firstName = "Patryk2"; return template.save(person); })).expectNextCount(1).verifyComplete(); assertThat(person.version, is(1)); StepVerifier.create(template.findAll(PersonWithVersionPropertyOfTypeInteger.class)).consumeNextWith(actual -> { assertThat(actual.version, is(1)); }).verifyComplete(); // Optimistic lock exception person.version = 0; person.firstName = "Patryk3"; StepVerifier.create(template.save(person)).expectError(OptimisticLockingFailureException.class).verify(); } @Test // DATAMONGO-1444 public void doesNotFailOnVersionInitForUnversionedEntity() { Document dbObject = new Document(); dbObject.put("firstName", "Oliver"); StepVerifier .create(template.insert(dbObject, // template.determineCollectionName(PersonWithVersionPropertyOfTypeInteger.class))) // .expectNextCount(1) // .verifyComplete(); } @Test // DATAMONGO-1444 public void removesObjectFromExplicitCollection() { String collectionName = "explicit"; StepVerifier.create(template.remove(new Query(), collectionName)).expectNextCount(1).verifyComplete(); PersonWithConvertedId person = new PersonWithConvertedId(); person.name = "Dave"; StepVerifier.create(template.save(person, collectionName)).expectNextCount(1).verifyComplete(); StepVerifier.create(template.findAll(PersonWithConvertedId.class, collectionName)).expectNextCount(1) .verifyComplete(); StepVerifier.create(template.remove(person, collectionName)).expectNextCount(1).verifyComplete(); StepVerifier.create(template.findAll(PersonWithConvertedId.class, collectionName)).verifyComplete(); } @Test // DATAMONGO-1444 public void savesMapCorrectly() { Map<String, String> map = new HashMap<>(); map.put("key", "value"); StepVerifier.create(template.save(map, "maps")).expectNextCount(1).verifyComplete(); } @Test // DATAMONGO-1444 public void savesMongoPrimitiveObjectCorrectly() { StepVerifier.create(template.save(new Object(), "collection")) // .expectError(IllegalArgumentException.class) // .verify(); } @Test // DATAMONGO-1444 public void savesPlainDbObjectCorrectly() { Document dbObject = new Document("foo", "bar"); StepVerifier.create(template.save(dbObject, "collection")).expectNextCount(1).verifyComplete(); assertThat(dbObject.containsKey("_id"), is(true)); } @Test(expected = IllegalArgumentException.class) // DATAMONGO-1444 public void rejectsPlainObjectWithOutExplicitCollection() { Document dbObject = new Document("foo", "bar"); StepVerifier.create(template.save(dbObject, "collection")).expectNextCount(1).verifyComplete(); StepVerifier.create(template.findById(dbObject.get("_id"), Document.class)) // .expectError(IllegalArgumentException.class) // .verify(); } @Test // DATAMONGO-1444 public void readsPlainDbObjectById() { Document dbObject = new Document("foo", "bar"); StepVerifier.create(template.save(dbObject, "collection")).expectNextCount(1).verifyComplete(); StepVerifier.create(template.findById(dbObject.get("_id"), Document.class, "collection")) // .consumeNextWith(actual -> { assertThat(actual.get("foo"), is(dbObject.get("foo"))); assertThat(actual.get("_id"), is(dbObject.get("_id"))); }).verifyComplete(); } @Test // DATAMONGO-1444 public void geoNear() { List<Venue> venues = Arrays.asList(new Venue("Penn Station", -73.99408, 40.75057), // new Venue("10gen Office", -73.99171, 40.738868), // new Venue("Flatiron Building", -73.988135, 40.741404), // new Venue("Maplewood, NJ", -74.2713, 40.73137)); StepVerifier.create(template.insertAll(venues)).expectNextCount(4).verifyComplete(); IndexOperationsAdapter.blocking(template.indexOps(Venue.class)) .ensureIndex(new GeospatialIndex("location").typed(GeoSpatialIndexType.GEO_2D)); NearQuery geoFar = NearQuery.near(-73, 40, Metrics.KILOMETERS).num(10).maxDistance(150, Metrics.KILOMETERS); StepVerifier.create(template.geoNear(geoFar, Venue.class)) // .expectNextCount(4) // .verifyComplete(); NearQuery geoNear = NearQuery.near(-73, 40, Metrics.KILOMETERS).num(10).maxDistance(120, Metrics.KILOMETERS); StepVerifier.create(template.geoNear(geoNear, Venue.class)) // .expectNextCount(3) // .verifyComplete(); } @Test // DATAMONGO-1444 public void writesPlainString() { StepVerifier.create(template.save("{ 'foo' : 'bar' }", "collection")) // .expectNextCount(1) // .verifyComplete(); } @Test // DATAMONGO-1444 public void rejectsNonJsonStringForSave() { StepVerifier.create(template.save("Foobar!", "collection")) // .expectError(MappingException.class) // .verify(); } @Test // DATAMONGO-1444 public void initializesVersionOnInsert() { PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger(); person.firstName = "Dave"; StepVerifier.create(template.insert(person)).expectNextCount(1).verifyComplete(); assertThat(person.version, is(0)); } @Test // DATAMONGO-1444 public void initializesVersionOnBatchInsert() { PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger(); person.firstName = "Dave"; StepVerifier.create(template.insertAll(Collections.singleton(person))).expectNextCount(1).verifyComplete(); assertThat(person.version, is(0)); } @Test // DATAMONGO-1444 public void queryCanBeNull() { StepVerifier.create(template.findAll(PersonWithIdPropertyOfTypeObjectId.class)).verifyComplete(); StepVerifier.create(template.find(null, PersonWithIdPropertyOfTypeObjectId.class)).verifyComplete(); } @Test // DATAMONGO-1444 public void versionsObjectIntoDedicatedCollection() { PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger(); person.firstName = "Dave"; StepVerifier.create(template.save(person, "personX")).expectNextCount(1).verifyComplete(); assertThat(person.version, is(0)); StepVerifier.create(template.save(person, "personX")).expectNextCount(1).verifyComplete(); assertThat(person.version, is(1)); } @Test // DATAMONGO-1444 public void correctlySetsLongVersionProperty() { PersonWithVersionPropertyOfTypeLong person = new PersonWithVersionPropertyOfTypeLong(); person.firstName = "Dave"; StepVerifier.create(template.save(person, "personX")).expectNextCount(1).verifyComplete(); assertThat(person.version, is(0L)); } @Test // DATAMONGO-1444 public void throwsExceptionForIndexViolationIfConfigured() { ReactiveMongoTemplate template = new ReactiveMongoTemplate(factory); template.setWriteResultChecking(WriteResultChecking.EXCEPTION); StepVerifier .create(template.indexOps(Person.class) // .ensureIndex(new Index().on("firstName", Direction.DESC).unique())) // .expectNextCount(1) // .verifyComplete(); Person person = new Person(new ObjectId(), "Amol"); person.setAge(28); StepVerifier.create(template.save(person)).expectNextCount(1).verifyComplete(); person = new Person(new ObjectId(), "Amol"); person.setAge(28); StepVerifier.create(template.save(person)).expectError(DataIntegrityViolationException.class).verify(); } @Test // DATAMONGO-1444 public void preventsDuplicateInsert() { template.setWriteConcern(WriteConcern.MAJORITY); PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger(); person.firstName = "Dave"; StepVerifier.create(template.save(person)).expectNextCount(1).verifyComplete(); assertThat(person.version, is(0)); person.version = null; StepVerifier.create(template.save(person)).expectError(DuplicateKeyException.class).verify(); } @Test // DATAMONGO-1444 public void countAndFindWithoutTypeInformation() { Person person = new Person(); StepVerifier.create(template.save(person)).expectNextCount(1).verifyComplete(); Query query = query(where("_id").is(person.getId())); String collectionName = template.getCollectionName(Person.class); StepVerifier.create(template.find(query, HashMap.class, collectionName)).expectNextCount(1).verifyComplete(); StepVerifier.create(template.count(query, collectionName)).expectNext(1L).verifyComplete(); } @Test // DATAMONGO-1444 public void nullsPropertiesForVersionObjectUpdates() { VersionedPerson person = new VersionedPerson(); person.firstname = "Dave"; person.lastname = "Matthews"; StepVerifier.create(template.save(person)).expectNextCount(1).verifyComplete(); assertThat(person.id, is(notNullValue())); person.lastname = null; StepVerifier.create(template.save(person)).expectNextCount(1).verifyComplete(); StepVerifier.create(template.findOne(query(where("id").is(person.id)), VersionedPerson.class)) // .consumeNextWith(actual -> { assertThat(actual.lastname, is(nullValue())); }) // .verifyComplete(); } @Test // DATAMONGO-1444 public void nullsValuesForUpdatesOfUnversionedEntity() { Person person = new Person("Dave"); StepVerifier.create(template.save(person)).expectNextCount(1).verifyComplete(); person.setFirstName(null); StepVerifier.create(template.save(person)).expectNextCount(1).verifyComplete(); StepVerifier.create(template.findOne(query(where("id").is(person.getId())), Person.class)) // .consumeNextWith(actual -> { assertThat(actual.getFirstName(), is(nullValue())); }) // .verifyComplete(); } @Test // DATAMONGO-1444 public void savesJsonStringCorrectly() { Document dbObject = new Document().append("first", "first").append("second", "second"); StepVerifier.create(template.save(dbObject, "collection")).expectNextCount(1).verifyComplete(); StepVerifier.create(template.findAll(Document.class, "collection")) // .consumeNextWith(actual -> { assertThat(actual.containsKey("first"), is(true)); }) // .verifyComplete(); } @Test // DATAMONGO-1444 public void executesExistsCorrectly() { Sample sample = new Sample(); StepVerifier.create(template.save(sample)).expectNextCount(1).verifyComplete(); Query query = query(where("id").is(sample.id)); StepVerifier.create(template.exists(query, Sample.class)).expectNext(true).verifyComplete(); StepVerifier.create(template.exists(query(where("_id").is(sample.id)), template.getCollectionName(Sample.class))) .expectNext(true).verifyComplete(); StepVerifier.create(template.exists(query, Sample.class, template.getCollectionName(Sample.class))).expectNext(true) .verifyComplete(); } @Test // DATAMONGO-1444 public void tailStreamsData() throws InterruptedException { StepVerifier.create(template.dropCollection("capped") .then(template.createCollection("capped", // new CollectionOptions(1000, 10, true))) .then(template.insert(new Document("random", Math.random()).append("key", "value"), // "capped"))) .expectNextCount(1).verifyComplete(); BlockingQueue<Document> documents = new LinkedBlockingQueue<>(1000); Flux<Document> capped = template.tail(null, Document.class, "capped"); Disposable disposable = capped.doOnNext(documents::add).subscribe(); assertThat(documents.poll(5, TimeUnit.SECONDS), is(notNullValue())); assertThat(documents.isEmpty(), is(true)); disposable.dispose(); } @Test // DATAMONGO-1444 public void tailStreamsDataUntilCancellation() throws InterruptedException { StepVerifier.create(template.dropCollection("capped") .then(template.createCollection("capped", // new CollectionOptions(1000, 10, true))) .then(template.insert(new Document("random", Math.random()).append("key", "value"), // "capped"))) .expectNextCount(1).verifyComplete(); BlockingQueue<Document> documents = new LinkedBlockingQueue<>(1000); Flux<Document> capped = template.tail(null, Document.class, "capped"); Disposable disposable = capped.doOnNext(documents::add).subscribe(); assertThat(documents.poll(5, TimeUnit.SECONDS), is(notNullValue())); assertThat(documents.isEmpty(), is(true)); StepVerifier.create(template.insert(new Document("random", Math.random()).append("key", "value"), "capped")) // .expectNextCount(1) // .verifyComplete(); assertThat(documents.poll(5, TimeUnit.SECONDS), is(notNullValue())); disposable.dispose(); StepVerifier.create(template.insert(new Document("random", Math.random()).append("key", "value"), "capped")) // .expectNextCount(1) // .verifyComplete(); assertThat(documents.poll(1, TimeUnit.SECONDS), is(nullValue())); } private PersonWithAList createPersonWithAList(String firstname, int age) { PersonWithAList p = new PersonWithAList(); p.setFirstName(firstname); p.setAge(age); return p; } @Data static class Sample { @Id String id; String field; public Sample() {} public Sample(String id, String field) { this.id = id; this.field = field; } } }