Binding error channel

- bind Spring Integration `errorChannel` as a message producer when the property `spring.cloud.stream.bindings.error.destination` is set
    - The error channel will use this property value as the destination name
  - Add test

This resolves #329

Rename NoopBindable -> BindableAdapter

Return error channel name for getOutputs

Fix review comments

  - Modified integration test to use `Sink` interface
  - Add unit test
This commit is contained in:
Ilayaperumal Gopinathan
2016-02-19 18:00:00 +05:30
committed by Marius Bogoevici
parent d2edea84ee
commit cae56385e0
15 changed files with 248 additions and 17 deletions

View File

@@ -0,0 +1,107 @@
/*
* Copyright 2016 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.cloud.stream.config;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.stream.annotation.Bindings;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.binder.redis.config.RedisMessageChannelBinderConfiguration;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.cloud.stream.test.junit.redis.RedisTestSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.integration.annotation.InboundChannelAdapter;
import org.springframework.integration.annotation.Poller;
import org.springframework.integration.core.MessageSource;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.support.ErrorMessage;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.Assert;
/**
* @author Ilayaperumal Gopinathan
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration({ErrorChannelTests.TestSource.class, ErrorChannelTests.TestErrorSink.class})
public class ErrorChannelTests {
@Rule
public RedisTestSupport redisTestSupport = new RedisTestSupport();
@Autowired
@Bindings(TestErrorSink.class)
private Sink testErrorSink;
@Test
public void testErrorChannelBinding() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
MessageHandler errorMessageHandler = new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
Assert.isTrue(message instanceof ErrorMessage, "Message should be an instance of ErrorMessage");
Assert.isTrue(message.getPayload() instanceof MessagingException, "Message payload should be an instance" +
"of MessagingException");
Assert.isTrue(message.getPayload().toString()
.equals("org.springframework.messaging.MessagingException: test"));
latch.countDown();
}
};
testErrorSink.input().subscribe(errorMessageHandler);
assertTrue(latch.await(10, TimeUnit.SECONDS));
}
@EnableBinding(Source.class)
@EnableAutoConfiguration
@Import(RedisMessageChannelBinderConfiguration.class)
@PropertySource("classpath:/org/springframework/cloud/stream/config/errorchannel/source-channel.properties")
public static class TestSource {
@Bean
@InboundChannelAdapter(value = Source.OUTPUT, poller = @Poller(fixedDelay = "5000", maxMessagesPerPoll = "1"))
public MessageSource<String> timerMessageSource() {
return new MessageSource<String>() {
@Override
public Message<String> receive() {
throw new MessagingException("test");
}
};
}
}
@EnableBinding(Sink.class)
@EnableAutoConfiguration
@Import(RedisMessageChannelBinderConfiguration.class)
@PropertySource("classpath:/org/springframework/cloud/stream/config/errorchannel/errorsink-channel.properties")
public static class TestErrorSink {
}
}

View File

@@ -117,7 +117,7 @@ public class MessageChannelConfigurerTests {
@EnableBinding(Source.class)
@EnableAutoConfiguration
@Import(RedisMessageChannelBinderConfiguration.class)
@PropertySource("classpath:/org/springframework/cloud/stream/config/source-channel-configurers.properties")
@PropertySource("classpath:/org/springframework/cloud/stream/config/channel/source-channel-configurers.properties")
public static class TestSource {
}
@@ -125,7 +125,7 @@ public class MessageChannelConfigurerTests {
@EnableBinding(Sink.class)
@EnableAutoConfiguration
@Import(RedisMessageChannelBinderConfiguration.class)
@PropertySource("classpath:/org/springframework/cloud/stream/config/sink-channel-configurers.properties")
@PropertySource("classpath:/org/springframework/cloud/stream/config/channel/sink-channel-configurers.properties")
public static class TestSink {
}

View File

@@ -0,0 +1 @@
spring.cloud.stream.bindings.input.destination=errorchannel-test

View File

@@ -0,0 +1,2 @@
spring.cloud.stream.bindings.output.destination=source-output
spring.cloud.stream.bindings.error.destination=errorchannel-test