Tests for reactive API
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright 2023 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.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.mongodb.core.ReplaceOptions.*;
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.bson.BsonInt64;
|
||||
import org.bson.Document;
|
||||
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.reactivestreams.Publisher;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
import org.springframework.data.mongodb.test.util.Client;
|
||||
import org.springframework.data.mongodb.test.util.MongoClientExtension;
|
||||
|
||||
import com.mongodb.client.model.Filters;
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
import com.mongodb.reactivestreams.client.MongoClient;
|
||||
import com.mongodb.reactivestreams.client.MongoCollection;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@ExtendWith(MongoClientExtension.class)
|
||||
public class ReactiveMongoTemplateReplaceTests {
|
||||
|
||||
static final String DB_NAME = "mongo-template-replace-tests";
|
||||
static final String RESTAURANT_COLLECTION = "restaurant";
|
||||
|
||||
static @Client MongoClient client;
|
||||
private ReactiveMongoTemplate template;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
template = new ReactiveMongoTemplate(client, DB_NAME);
|
||||
template.setEntityLifecycleEventsEnabled(false);
|
||||
|
||||
initTestData();
|
||||
}
|
||||
|
||||
@AfterEach()
|
||||
void afterEach() {
|
||||
clearTestData();
|
||||
}
|
||||
|
||||
@Test // GH-4462
|
||||
void replacesExistingDocument() {
|
||||
|
||||
Mono<UpdateResult> result = template.replace(query(where("name").is("Central Perk Cafe")),
|
||||
new Restaurant("Central Pork Cafe", "Manhattan"));
|
||||
|
||||
result.as(StepVerifier::create).consumeNextWith(it -> {
|
||||
assertThat(it.getMatchedCount()).isEqualTo(1);
|
||||
assertThat(it.getModifiedCount()).isEqualTo(1);
|
||||
}).verifyComplete();
|
||||
|
||||
retrieve(collection -> collection.find(Filters.eq("_id", 1)).first()).as(StepVerifier::create)
|
||||
.consumeNextWith(document -> {
|
||||
assertThat(document).containsEntry("r-name", "Central Pork Cafe");
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // GH-4462
|
||||
void replacesFirstOnMoreThanOneMatch() {
|
||||
|
||||
Mono<UpdateResult> result = template.replace(query(where("violations").exists(true)),
|
||||
new Restaurant("Central Pork Cafe", "Manhattan"));
|
||||
|
||||
result.as(StepVerifier::create).consumeNextWith(it -> {
|
||||
assertThat(it.getMatchedCount()).isEqualTo(1);
|
||||
assertThat(it.getModifiedCount()).isEqualTo(1);
|
||||
}).verifyComplete();
|
||||
|
||||
retrieve(collection -> collection.find(Filters.eq("_id", 2)).first()).as(StepVerifier::create)
|
||||
.consumeNextWith(document -> {
|
||||
assertThat(document).containsEntry("r-name", "Central Pork Cafe");
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // GH-4462
|
||||
void replacesExistingDocumentWithRawDoc() {
|
||||
|
||||
Mono<UpdateResult> result = template.replace(query(where("r-name").is("Central Perk Cafe")),
|
||||
Document.parse("{ 'r-name' : 'Central Pork Cafe', 'Borough' : 'Manhattan' }"),
|
||||
template.getCollectionName(Restaurant.class));
|
||||
|
||||
result.as(StepVerifier::create).consumeNextWith(it -> {
|
||||
assertThat(it.getMatchedCount()).isEqualTo(1);
|
||||
assertThat(it.getModifiedCount()).isEqualTo(1);
|
||||
}).verifyComplete();
|
||||
|
||||
retrieve(collection -> collection.find(Filters.eq("_id", 1)).first()).as(StepVerifier::create)
|
||||
.consumeNextWith(document -> {
|
||||
assertThat(document).containsEntry("r-name", "Central Pork Cafe");
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // GH-4462
|
||||
void replacesExistingDocumentWithRawDocMappingQueryAgainstDomainType() {
|
||||
|
||||
Mono<UpdateResult> result = template.replace(query(where("name").is("Central Perk Cafe")), Restaurant.class,
|
||||
Document.parse("{ 'r-name' : 'Central Pork Cafe', 'Borough' : 'Manhattan' }"), ReplaceOptions.none());
|
||||
|
||||
result.as(StepVerifier::create).consumeNextWith(it -> {
|
||||
assertThat(it.getMatchedCount()).isEqualTo(1);
|
||||
assertThat(it.getModifiedCount()).isEqualTo(1);
|
||||
}).verifyComplete();
|
||||
|
||||
retrieve(collection -> collection.find(Filters.eq("_id", 1)).first()).as(StepVerifier::create)
|
||||
.consumeNextWith(document -> {
|
||||
assertThat(document).containsEntry("r-name", "Central Pork Cafe");
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // GH-4462
|
||||
void replacesExistingDocumentWithMatchingId() {
|
||||
|
||||
Mono<UpdateResult> result = template.replace(query(where("name").is("Central Perk Cafe")),
|
||||
new Restaurant(1L, "Central Pork Cafe", "Manhattan", 0));
|
||||
|
||||
result.as(StepVerifier::create).consumeNextWith(it -> {
|
||||
assertThat(it.getMatchedCount()).isEqualTo(1);
|
||||
assertThat(it.getModifiedCount()).isEqualTo(1);
|
||||
}).verifyComplete();
|
||||
|
||||
retrieve(collection -> collection.find(Filters.eq("_id", 1)).first()).as(StepVerifier::create)
|
||||
.consumeNextWith(document -> {
|
||||
assertThat(document).containsEntry("r-name", "Central Pork Cafe");
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // GH-4462
|
||||
void replacesExistingDocumentWithNewIdThrowsDataIntegrityViolationException() {
|
||||
|
||||
template.replace(query(where("name").is("Central Perk Cafe")),
|
||||
new Restaurant(4L, "Central Pork Cafe", "Manhattan", 0))
|
||||
.as(StepVerifier::create)
|
||||
.expectError(DataIntegrityViolationException.class)
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test // GH-4462
|
||||
void doesNothingIfNoMatchFoundAndUpsertSetToFalse/* by default */() {
|
||||
|
||||
Mono<UpdateResult> result = template.replace(query(where("name").is("Pizza Rat's Pizzaria")),
|
||||
new Restaurant(null, "Pizza Rat's Pizzaria", "Manhattan", 8));
|
||||
|
||||
result.as(StepVerifier::create).consumeNextWith(it -> {
|
||||
assertThat(it.getMatchedCount()).isEqualTo(0);
|
||||
assertThat(it.getModifiedCount()).isEqualTo(0);
|
||||
}).verifyComplete();
|
||||
|
||||
retrieve(collection -> collection.find(Filters.eq("r-name", "Pizza Rat's Pizzaria")).first())
|
||||
.as(StepVerifier::create).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // GH-4462
|
||||
void insertsIfNoMatchFoundAndUpsertSetToTrue() {
|
||||
|
||||
Mono<UpdateResult> result = template.replace(query(where("name").is("Pizza Rat's Pizzaria")),
|
||||
new Restaurant(4L, "Pizza Rat's Pizzaria", "Manhattan", 8), replaceOptions().upsert());
|
||||
|
||||
result.as(StepVerifier::create).consumeNextWith(it -> {
|
||||
assertThat(it.getMatchedCount()).isEqualTo(0);
|
||||
assertThat(it.getModifiedCount()).isEqualTo(0);
|
||||
assertThat(it.getUpsertedId()).isEqualTo(new BsonInt64(4L));
|
||||
}).verifyComplete();
|
||||
|
||||
retrieve(collection -> collection.find(Filters.eq("_id", 4)).first()).as(StepVerifier::create)
|
||||
.consumeNextWith(document -> {
|
||||
assertThat(document).containsEntry("r-name", "Pizza Rat's Pizzaria");
|
||||
});
|
||||
}
|
||||
|
||||
void initTestData() {
|
||||
|
||||
List<Document> testData = Stream.of( //
|
||||
"{ '_id' : 1, 'r-name' : 'Central Perk Cafe', 'Borough' : 'Manhattan' }",
|
||||
"{ '_id' : 2, 'r-name' : 'Rock A Feller Bar and Grill', 'Borough' : 'Queens', 'violations' : 2 }",
|
||||
"{ '_id' : 3, 'r-name' : 'Empire State Pub', 'Borough' : 'Brooklyn', 'violations' : 0 }") //
|
||||
.map(Document::parse).collect(Collectors.toList());
|
||||
|
||||
doInCollection(collection -> collection.insertMany(testData));
|
||||
}
|
||||
|
||||
void clearTestData() {
|
||||
doInCollection(collection -> collection.deleteMany(new Document()));
|
||||
}
|
||||
|
||||
void doInCollection(Function<MongoCollection<Document>, Publisher<?>> fkt) {
|
||||
retrieve(collection -> Mono.from(fkt.apply(collection))).then().as(StepVerifier::create).verifyComplete();
|
||||
}
|
||||
|
||||
<T> Mono<T> retrieve(Function<MongoCollection<Document>, Publisher<T>> fkt) {
|
||||
return Mono.from(fkt.apply(client.getDatabase(DB_NAME).getCollection(RESTAURANT_COLLECTION)));
|
||||
}
|
||||
|
||||
@org.springframework.data.mongodb.core.mapping.Document(RESTAURANT_COLLECTION)
|
||||
static class Restaurant {
|
||||
|
||||
Long id;
|
||||
|
||||
@Field("r-name") String name;
|
||||
String borough;
|
||||
Integer violations;
|
||||
|
||||
Restaurant() {}
|
||||
|
||||
Restaurant(String name, String borough) {
|
||||
|
||||
this.name = name;
|
||||
this.borough = borough;
|
||||
}
|
||||
|
||||
Restaurant(Long id, String name, String borough, Integer violations) {
|
||||
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.borough = borough;
|
||||
this.violations = violations;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getRName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setRName(String rName) {
|
||||
this.name = rName;
|
||||
}
|
||||
|
||||
public String getBorough() {
|
||||
return borough;
|
||||
}
|
||||
|
||||
public void setBorough(String borough) {
|
||||
this.borough = borough;
|
||||
}
|
||||
|
||||
public int getViolations() {
|
||||
return violations;
|
||||
}
|
||||
|
||||
public void setViolations(int violations) {
|
||||
this.violations = violations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Restaurant{" + "id=" + id + ", name='" + name + '\'' + ", borough='" + borough + '\'' + ", violations="
|
||||
+ violations + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Restaurant that = (Restaurant) o;
|
||||
return violations == that.violations && Objects.equals(id, that.id) && Objects.equals(name, that.name)
|
||||
&& Objects.equals(borough, that.borough);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name, borough, violations);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user