INT-4568: Add reactive MongoDbMH
JIRA: https://jira.spring.io/browse/INT-4568 * Refactor `AbstractMessageHandler` and implement `MongodbReactiveMessageHandler` * Rename `AbstractBaseMessageHandler` to `MessageHandlerSupport` * Clean up code style and resolve possible Sonar smells
This commit is contained in:
@@ -17,12 +17,14 @@
|
||||
package org.springframework.integration.mongodb.outbound;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import org.bson.conversions.Bson;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
@@ -49,29 +51,41 @@ import org.springframework.messaging.Message;
|
||||
*/
|
||||
public class MongoDbStoringMessageHandlerTests extends MongoDbAvailableTests {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void withNullMongoDBFactory() {
|
||||
new MongoDbStoringMessageHandler((MongoDbFactory) null);
|
||||
}
|
||||
private MongoTemplate template;
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void withNullMongoTemplate() {
|
||||
new MongoDbStoringMessageHandler((MongoOperations) null);
|
||||
private MongoDbFactory mongoDbFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mongoDbFactory = prepareMongoFactory("foo");
|
||||
template = new MongoTemplate(mongoDbFactory);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@MongoDbAvailable
|
||||
public void validateMessageHandlingWithDefaultCollection() throws Exception {
|
||||
public void withNullMongoDBFactory() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new MongoDbStoringMessageHandler((MongoDbFactory) null));
|
||||
}
|
||||
|
||||
MongoDbFactory mongoDbFactory = this.prepareMongoFactory();
|
||||
MongoDbStoringMessageHandler handler = new MongoDbStoringMessageHandler(mongoDbFactory);
|
||||
@Test
|
||||
@MongoDbAvailable
|
||||
public void withNullMongoTemplate() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new MongoDbStoringMessageHandler((MongoOperations) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@MongoDbAvailable
|
||||
public void validateMessageHandlingWithDefaultCollection() {
|
||||
|
||||
MongoDbStoringMessageHandler handler = new MongoDbStoringMessageHandler(this.mongoDbFactory);
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
Message<Person> message = MessageBuilder.withPayload(this.createPerson("Bob")).build();
|
||||
handler.handleMessage(message);
|
||||
|
||||
MongoTemplate template = new MongoTemplate(mongoDbFactory);
|
||||
Query query = new BasicQuery("{'name' : 'Bob'}");
|
||||
Person person = template.findOne(query, Person.class, "data");
|
||||
|
||||
@@ -81,17 +95,15 @@ public class MongoDbStoringMessageHandlerTests extends MongoDbAvailableTests {
|
||||
|
||||
@Test
|
||||
@MongoDbAvailable
|
||||
public void validateMessageHandlingWithNamedCollection() throws Exception {
|
||||
public void validateMessageHandlingWithNamedCollection() {
|
||||
|
||||
MongoDbFactory mongoDbFactory = this.prepareMongoFactory();
|
||||
MongoDbStoringMessageHandler handler = new MongoDbStoringMessageHandler(mongoDbFactory);
|
||||
MongoDbStoringMessageHandler handler = new MongoDbStoringMessageHandler(this.mongoDbFactory);
|
||||
handler.setCollectionNameExpression(new LiteralExpression("foo"));
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
Message<Person> message = MessageBuilder.withPayload(this.createPerson("Bob")).build();
|
||||
handler.handleMessage(message);
|
||||
|
||||
MongoTemplate template = new MongoTemplate(mongoDbFactory);
|
||||
Query query = new BasicQuery("{'name' : 'Bob'}");
|
||||
Person person = template.findOne(query, Person.class, "foo");
|
||||
|
||||
@@ -101,10 +113,9 @@ public class MongoDbStoringMessageHandlerTests extends MongoDbAvailableTests {
|
||||
|
||||
@Test
|
||||
@MongoDbAvailable
|
||||
public void validateMessageHandlingWithMongoConverter() throws Exception {
|
||||
public void validateMessageHandlingWithMongoConverter() {
|
||||
|
||||
MongoDbFactory mongoDbFactory = this.prepareMongoFactory();
|
||||
MongoDbStoringMessageHandler handler = new MongoDbStoringMessageHandler(mongoDbFactory);
|
||||
MongoDbStoringMessageHandler handler = new MongoDbStoringMessageHandler(this.mongoDbFactory);
|
||||
handler.setCollectionNameExpression(new LiteralExpression("foo"));
|
||||
MappingMongoConverter converter = new TestMongoConverter(mongoDbFactory, new MongoMappingContext());
|
||||
converter.afterPropertiesSet();
|
||||
@@ -115,7 +126,6 @@ public class MongoDbStoringMessageHandlerTests extends MongoDbAvailableTests {
|
||||
Message<Person> message = MessageBuilder.withPayload(this.createPerson("Bob")).build();
|
||||
handler.handleMessage(message);
|
||||
|
||||
MongoTemplate template = new MongoTemplate(mongoDbFactory);
|
||||
Query query = new BasicQuery("{'name' : 'Bob'}");
|
||||
Person person = template.findOne(query, Person.class, "foo");
|
||||
|
||||
@@ -126,27 +136,26 @@ public class MongoDbStoringMessageHandlerTests extends MongoDbAvailableTests {
|
||||
|
||||
@Test
|
||||
@MongoDbAvailable
|
||||
public void validateMessageHandlingWithMongoTemplate() throws Exception {
|
||||
MongoDbFactory mongoDbFactory = this.prepareMongoFactory();
|
||||
MappingMongoConverter converter = new TestMongoConverter(mongoDbFactory, new MongoMappingContext());
|
||||
public void validateMessageHandlingWithMongoTemplate() {
|
||||
MappingMongoConverter converter = new TestMongoConverter(this.mongoDbFactory, new MongoMappingContext());
|
||||
converter.afterPropertiesSet();
|
||||
converter = spy(converter);
|
||||
MongoTemplate template = new MongoTemplate(mongoDbFactory, converter);
|
||||
MongoTemplate writingTemplate = new MongoTemplate(this.mongoDbFactory, converter);
|
||||
|
||||
|
||||
MongoDbStoringMessageHandler handler = new MongoDbStoringMessageHandler(template);
|
||||
MongoDbStoringMessageHandler handler = new MongoDbStoringMessageHandler(writingTemplate);
|
||||
handler.setCollectionNameExpression(new LiteralExpression("foo"));
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
Message<Person> message = MessageBuilder.withPayload(this.createPerson("Bob")).build();
|
||||
handler.handleMessage(message);
|
||||
|
||||
MongoTemplate readingTemplate = new MongoTemplate(mongoDbFactory);
|
||||
Query query = new BasicQuery("{'name' : 'Bob'}");
|
||||
Person person = readingTemplate.findOne(query, Person.class, "foo");
|
||||
Person person = template.findOne(query, Person.class, "foo");
|
||||
|
||||
assertThat(person.getName()).isEqualTo("Bob");
|
||||
assertThat(person.getAddress().getState()).isEqualTo("PA");
|
||||
verify(converter, times(1)).write(Mockito.any(), Mockito.any(Bson.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2019 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.integration.mongodb.outbound;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.query.BasicQuery;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.integration.mongodb.rules.MongoDbAvailable;
|
||||
import org.springframework.integration.mongodb.rules.MongoDbAvailableTests;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Amol Nayak
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
* @author David Turanski
|
||||
*
|
||||
* @since 5.3
|
||||
*/
|
||||
public class ReactiveMongoDbStoringMessageHandlerTests extends MongoDbAvailableTests {
|
||||
|
||||
private ReactiveMongoTemplate template;
|
||||
|
||||
private ReactiveMongoDatabaseFactory mongoDbFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mongoDbFactory = this.prepareReactiveMongoFactory("foo");
|
||||
template = new ReactiveMongoTemplate(mongoDbFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
@MongoDbAvailable
|
||||
public void withNullMongoDBFactory() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new ReactiveMongoDbStoringMessageHandler((ReactiveMongoDatabaseFactory) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@MongoDbAvailable
|
||||
public void withNullMongoTemplate() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new ReactiveMongoDbStoringMessageHandler((ReactiveMongoOperations) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@MongoDbAvailable
|
||||
public void validateMessageHandlingWithDefaultCollection() {
|
||||
ReactiveMongoDbStoringMessageHandler handler = new ReactiveMongoDbStoringMessageHandler(this.mongoDbFactory);
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
Message<Person> message = MessageBuilder.withPayload(this.createPerson("Bob")).build();
|
||||
waitFor(handler.handleMessage(message));
|
||||
|
||||
Query query = new BasicQuery("{'name' : 'Bob'}");
|
||||
Person person = waitFor(this.template.findOne(query, Person.class, "data"));
|
||||
assertThat(person.getName()).isEqualTo("Bob");
|
||||
assertThat(person.getAddress().getState()).isEqualTo("PA");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@MongoDbAvailable
|
||||
public void validateMessageHandlingWithNamedCollection() {
|
||||
ReactiveMongoDbStoringMessageHandler handler = new ReactiveMongoDbStoringMessageHandler(this.mongoDbFactory);
|
||||
handler.setCollectionNameExpression(new LiteralExpression("foo"));
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
Message<Person> message = MessageBuilder.withPayload(this.createPerson("Bob")).build();
|
||||
waitFor(handler.handleMessage(message));
|
||||
|
||||
Query query = new BasicQuery("{'name' : 'Bob'}");
|
||||
Person person = waitFor(this.template.findOne(query, Person.class, "foo"));
|
||||
|
||||
assertThat(person.getName()).isEqualTo("Bob");
|
||||
assertThat(person.getAddress().getState()).isEqualTo("PA");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@MongoDbAvailable
|
||||
public void errorOnMessageHandlingWithNullValuedExpression() {
|
||||
|
||||
ReactiveMongoDbStoringMessageHandler handler = new ReactiveMongoDbStoringMessageHandler(this.mongoDbFactory);
|
||||
handler.setCollectionNameExpression(new LiteralExpression(null));
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
Message<Person> message = MessageBuilder.withPayload(createPerson("Bob")).build();
|
||||
AtomicBoolean errorOccurred = new AtomicBoolean();
|
||||
handler.handleMessage(message)
|
||||
.doOnError(e -> errorOccurred.set(true))
|
||||
.subscribe(aVoid -> assertThat(errorOccurred.get()).isTrue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@MongoDbAvailable
|
||||
public void validateMessageHandlingWithMongoConverter() {
|
||||
ReactiveMongoDbStoringMessageHandler handler = new ReactiveMongoDbStoringMessageHandler(this.mongoDbFactory);
|
||||
handler.setCollectionNameExpression(new LiteralExpression("foo"));
|
||||
MappingMongoConverter converter =
|
||||
new ReactiveTestMongoConverter(this.mongoDbFactory, new MongoMappingContext());
|
||||
converter.afterPropertiesSet();
|
||||
converter = spy(converter);
|
||||
handler.setMongoConverter(converter);
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
Message<Person> message = MessageBuilder.withPayload(this.createPerson("Bob")).build();
|
||||
waitFor(handler.handleMessage(message));
|
||||
|
||||
Query query = new BasicQuery("{'name' : 'Bob'}");
|
||||
Person person = waitFor(this.template.findOne(query, Person.class, "foo"));
|
||||
|
||||
assertThat(person.getName()).isEqualTo("Bob");
|
||||
assertThat(person.getAddress().getState()).isEqualTo("PA");
|
||||
}
|
||||
|
||||
@Test
|
||||
@MongoDbAvailable
|
||||
public void validateMessageHandlingWithMongoTemplate() {
|
||||
MappingMongoConverter converter =
|
||||
new ReactiveTestMongoConverter(this.mongoDbFactory, new MongoMappingContext());
|
||||
converter.afterPropertiesSet();
|
||||
converter = spy(converter);
|
||||
ReactiveMongoTemplate writingTemplate = new ReactiveMongoTemplate(this.mongoDbFactory, converter);
|
||||
ReactiveMongoDbStoringMessageHandler handler = new ReactiveMongoDbStoringMessageHandler(writingTemplate);
|
||||
handler.setCollectionNameExpression(new LiteralExpression("foo"));
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
Message<Person> message = MessageBuilder.withPayload(this.createPerson("Bob")).build();
|
||||
waitFor(handler.handleMessage(message));
|
||||
|
||||
Query query = new BasicQuery("{'name' : 'Bob'}");
|
||||
Person person = waitFor(this.template.findOne(query, Person.class, "foo"));
|
||||
|
||||
assertThat(person.getName()).isEqualTo("Bob");
|
||||
assertThat(person.getAddress().getState()).isEqualTo("PA");
|
||||
}
|
||||
|
||||
private static <T> T waitFor(Mono<T> mono) {
|
||||
return mono.block(Duration.ofSeconds(3));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.integration.mongodb.rules;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.bson.conversions.Bson;
|
||||
import org.junit.Rule;
|
||||
@@ -23,10 +25,14 @@ import org.junit.Rule;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
|
||||
import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory;
|
||||
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.integration.mongodb.outbound.MessageCollectionCallback;
|
||||
@@ -36,19 +42,21 @@ import com.mongodb.MongoException;
|
||||
import com.mongodb.client.MongoClients;
|
||||
import com.mongodb.client.MongoCollection;
|
||||
|
||||
|
||||
/**
|
||||
* Convenience base class that enables unit test methods to rely upon the {@link MongoDbAvailable} annotation.
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Xavier Padro
|
||||
* @author Artem Bilan
|
||||
* @author David Turanski
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public abstract class MongoDbAvailableTests {
|
||||
|
||||
@Rule
|
||||
public MongoDbAvailableRule redisAvailableRule = new MongoDbAvailableRule();
|
||||
public MongoDbAvailableRule mongoDbAvailableRule = new MongoDbAvailableRule();
|
||||
|
||||
|
||||
protected MongoDbFactory prepareMongoFactory(String... additionalCollectionsToDrop) {
|
||||
@@ -57,6 +65,25 @@ public abstract class MongoDbAvailableTests {
|
||||
return mongoDbFactory;
|
||||
}
|
||||
|
||||
protected ReactiveMongoDatabaseFactory prepareReactiveMongoFactory(String... additionalCollectionsToDrop) {
|
||||
ReactiveMongoDatabaseFactory mongoDbFactory = new SimpleReactiveMongoDatabaseFactory(
|
||||
com.mongodb.reactivestreams.client.MongoClients.create(), "test");
|
||||
cleanupCollections(mongoDbFactory, additionalCollectionsToDrop);
|
||||
return mongoDbFactory;
|
||||
}
|
||||
|
||||
protected void cleanupCollections(ReactiveMongoDatabaseFactory mongoDbFactory,
|
||||
String... additionalCollectionsToDrop) {
|
||||
|
||||
ReactiveMongoTemplate template = new ReactiveMongoTemplate(mongoDbFactory);
|
||||
template.dropCollection("messages").block(Duration.ofSeconds(3));
|
||||
template.dropCollection("configurableStoreMessages").block(Duration.ofSeconds(3));
|
||||
template.dropCollection("data").block(Duration.ofSeconds(3));
|
||||
for (String additionalCollection : additionalCollectionsToDrop) {
|
||||
template.dropCollection(additionalCollection).block(Duration.ofSeconds(3));
|
||||
}
|
||||
}
|
||||
|
||||
protected void cleanupCollections(MongoDbFactory mongoDbFactory, String... additionalCollectionsToDrop) {
|
||||
MongoTemplate template = new MongoTemplate(mongoDbFactory);
|
||||
template.dropCollection("messages");
|
||||
@@ -170,6 +197,27 @@ public abstract class MongoDbAvailableTests {
|
||||
|
||||
}
|
||||
|
||||
public static class ReactiveTestMongoConverter extends MappingMongoConverter {
|
||||
|
||||
public ReactiveTestMongoConverter(
|
||||
ReactiveMongoDatabaseFactory mongoDbFactory,
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
||||
|
||||
super(NoOpDbRefResolver.INSTANCE, mappingContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Object source, Bson target) {
|
||||
super.write(source, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> S read(Class<S> clazz, Bson source) {
|
||||
return super.read(clazz, source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TestCollectionCallback implements MessageCollectionCallback<Long> {
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user