/*
* Copyright 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.integration.test.mock;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.springframework.integration.test.matcher.HeaderMatcher.hasHeader;
import static org.springframework.integration.test.matcher.PayloadAndHeaderMatcher.sameExceptIgnorableHeaders;
import static org.springframework.integration.test.matcher.PayloadMatcher.hasPayload;
import static org.springframework.integration.test.mock.MockIntegration.mockMessageHandler;
import java.util.List;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.Poller;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.expression.ValueExpression;
import org.springframework.integration.handler.ExpressionEvaluatingMessageHandler;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.test.context.MockIntegrationContext;
import org.springframework.integration.test.context.SpringIntegrationTest;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author Artem Bilan
*
* @since 5.0
*/
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = MockMessageHandlerTests.Config.class)
@SpringIntegrationTest
public class MockMessageHandlerTests {
@Autowired
private ApplicationContext context;
@Autowired
private MockIntegrationContext mockIntegrationContext;
@Autowired
private MessageChannel mockHandlerChannel;
@Autowired
private MessageChannel pojoServiceChannel;
@Autowired
private MessageChannel rawChannel;
@Autowired
private QueueChannel results;
@Autowired
private ArgumentCaptor<Message<?>> messageArgumentCaptor;
@After
public void tearDown() {
this.mockIntegrationContext.resetBeans();
results.purge(null);
}
@Test
public void testMockMessageHandler() {
QueueChannel replies = new QueueChannel();
Message<String> message = MessageBuilder.withPayload("foo")
.setHeader("bar", "BAR")
.setHeader("baz", "BAZ")
.setReplyChannel(replies)
.build();
this.mockHandlerChannel.send(message);
this.mockHandlerChannel.send(message);
this.mockHandlerChannel.send(message);
Message<String> message1 = MessageBuilder.fromMessage(message)
.removeHeaders("bar", "baz")
.build();
this.mockHandlerChannel.send(message1);
for (int i = 0; i < 4; i++) {
Message<?> receive = replies.receive(10000);
assertNotNull(receive);
assertEquals("foo", receive.getPayload());
}
List<Message<?>> messages = this.messageArgumentCaptor.getAllValues();
assertEquals(4, messages.size());
assertThat(messages.get(0), hasHeader("bar", "BAR"));
assertThat(messages.get(1),
sameExceptIgnorableHeaders(MessageBuilder.withPayload("foo")
.setHeader("baz", "BAZ")
.build(),
"bar", MessageHeaders.REPLY_CHANNEL));
assertThat(messages.get(2), hasPayload("foo"));
assertThat(messages.get(3), hasPayload("foo"));
}
@Test
public void testMockMessageHandlerPojoService() {
this.pojoServiceChannel.send(new GenericMessage<>("bar"));
Message<?> receive = this.results.receive(10000);
assertNotNull(receive);
assertEquals("barbar", receive.getPayload());
MessageHandler mockMessageHandler =
mockMessageHandler()
.handleNextAndReply(m -> m.getPayload().toString().toUpperCase());
this.mockIntegrationContext.instead("mockMessageHandlerTests.Config.myService.serviceActivator",
mockMessageHandler);
this.pojoServiceChannel.send(new GenericMessage<>("foo"));
receive = this.results.receive(10000);
assertNotNull(receive);
assertEquals("FOO", receive.getPayload());
try {
this.pojoServiceChannel.send(new GenericMessage<>("bar"));
fail("AssertionError expected");
}
catch (Error e) {
assertThat(e, instanceOf(AssertionError.class));
}
}
@Test
@SuppressWarnings("unchecked")
public void testMockRawHandler() {
ArgumentCaptor<Message<?>> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
MessageHandler mockMessageHandler =
spy(mockMessageHandler(messageArgumentCaptor))
.handleNext(m -> { });
String endpointId = "rawHandlerConsumer";
this.mockIntegrationContext.instead(endpointId, mockMessageHandler);
Object endpoint = this.context.getBean(endpointId);
assertSame(mockMessageHandler, TestUtils.getPropertyValue(endpoint, "handler", MessageHandler.class));
GenericMessage<String> message = new GenericMessage<>("foo");
this.rawChannel.send(message);
verify(mockMessageHandler)
.handleMessage(message);
assertSame(message, messageArgumentCaptor.getValue());
this.mockIntegrationContext.resetBeans(endpointId);
mockMessageHandler =
mockMessageHandler()
.handleNextAndReply(m -> m);
try {
this.mockIntegrationContext.instead(endpointId, mockMessageHandler);
fail("IllegalStateException expected");
}
catch (Exception e) {
assertThat(e, instanceOf(IllegalStateException.class));
assertThat(e.getMessage(), containsString("with replies can't replace simple MessageHandler"));
}
}
@Configuration
@EnableIntegration
public static class Config {
@Bean
public PollableChannel results() {
return new QueueChannel();
}
@Bean
@SuppressWarnings("unchecked")
public ArgumentCaptor<Message<?>> messageArgumentCaptor() {
return ArgumentCaptor.forClass(Message.class);
}
@Bean
public PollableChannel mockHandlerChannel() {
return new QueueChannel();
}
@Bean
@ServiceActivator(inputChannel = "mockHandlerChannel",
poller = @Poller(fixedDelay = "100"))
public MessageHandler mockHandler() {
return mockMessageHandler(messageArgumentCaptor())
.handleNextAndReply(m -> m)
.handleNextAndReply(m -> m)
.handleNextAndReply(m -> "foo");
}
@ServiceActivator(inputChannel = "pojoServiceChannel", outputChannel = "results")
public String myService(String payload) {
return payload + payload;
}
@Bean
public SubscribableChannel rawChannel() {
return new DirectChannel();
}
@Bean
public EventDrivenConsumer rawHandlerConsumer() {
return new EventDrivenConsumer(rawChannel(),
new ExpressionEvaluatingMessageHandler(new ValueExpression<>("test")));
}
}
}