INTEXT-8: Add SNS Outbound Channel Adapter
JIRA: https://jira.spring.io/browse/INTEXT-8 Address PR comments
This commit is contained in:
@@ -61,7 +61,7 @@ public class SnsInboundChannelAdapterParserTests {
|
||||
|
||||
|
||||
@Test
|
||||
public void testSqsMessageDrivenChannelAdapterParser() {
|
||||
public void testSnsInboundChannelAdapterParser() {
|
||||
assertSame(this.amazonSns, TestUtils.getPropertyValue(this.snsInboundChannelAdapter,
|
||||
"notificationStatusResolver.amazonSns"));
|
||||
assertTrue(TestUtils.getPropertyValue(this.snsInboundChannelAdapter, "handleNotificationStatus", Boolean.class));
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int-aws="http://www.springframework.org/schema/integration/aws"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration/aws http://www.springframework.org/schema/integration/aws/spring-integration-aws.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
<bean id="amazonSns" class="org.mockito.Mockito" factory-method="mock">
|
||||
<constructor-arg value="com.amazonaws.services.sns.AmazonSNS"/>
|
||||
</bean>
|
||||
|
||||
<int-aws:sns-outbound-channel-adapter id="defaultAdapter" sns="amazonSns">
|
||||
<int-aws:request-handler-advice-chain>
|
||||
<bean class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice"/>
|
||||
</int-aws:request-handler-advice-chain>
|
||||
</int-aws:sns-outbound-channel-adapter>
|
||||
|
||||
<int:channel id="notificationChannel"/>
|
||||
|
||||
<int-aws:sns-outbound-gateway
|
||||
id="snsGateway"
|
||||
sns="amazonSns"
|
||||
request-channel="notificationChannel"
|
||||
reply-channel="errorChannel"
|
||||
topic-arn="foo"
|
||||
subject="bar"
|
||||
body-expression="payload.toUpperCase()"
|
||||
auto-startup="false"
|
||||
phase="201"/>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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.integration.aws.config.xml;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.integration.endpoint.AbstractEndpoint;
|
||||
import org.springframework.integration.handler.advice.RequestHandlerRetryAdvice;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.amazonaws.services.sns.AmazonSNS;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class SnsOutboundChannelAdapterParserTests {
|
||||
|
||||
@Autowired
|
||||
private AmazonSNS amazonSns;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("defaultAdapter")
|
||||
private MessageChannel defaultAdapterChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("errorChannel")
|
||||
private MessageChannel errorChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("defaultAdapter.adapter")
|
||||
private AbstractEndpoint defaultAdapter;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("defaultAdapter.handler")
|
||||
private MessageHandler defaultAdapterHandler;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("notificationChannel")
|
||||
private MessageChannel notificationChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("snsGateway")
|
||||
private AbstractEndpoint snsGateway;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("snsGateway.handler")
|
||||
private MessageHandler snsGatewayHandler;
|
||||
|
||||
@Test
|
||||
public void testSnsOutboundChannelAdapterDefaultParser() throws Exception {
|
||||
Object handler = TestUtils.getPropertyValue(this.defaultAdapter, "handler");
|
||||
assertFalse(AopUtils.isAopProxy(handler));
|
||||
|
||||
assertSame(this.defaultAdapterHandler, handler);
|
||||
|
||||
assertThat(TestUtils.getPropertyValue(handler, "adviceChain", List.class).get(0),
|
||||
instanceOf(RequestHandlerRetryAdvice.class));
|
||||
|
||||
assertSame(this.defaultAdapterChannel, TestUtils.getPropertyValue(this.defaultAdapter, "inputChannel"));
|
||||
|
||||
assertSame(this.amazonSns, TestUtils.getPropertyValue(this.defaultAdapterHandler, "amazonSns"));
|
||||
assertNotNull(TestUtils.getPropertyValue(this.defaultAdapterHandler, "evaluationContext"));
|
||||
assertNull(TestUtils.getPropertyValue(this.defaultAdapterHandler, "topicArnExpression"));
|
||||
assertNull(TestUtils.getPropertyValue(this.defaultAdapterHandler, "subjectExpression"));
|
||||
assertNull(TestUtils.getPropertyValue(this.defaultAdapterHandler, "bodyExpression"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSnsOutboundChannelAdapterParser() {
|
||||
assertSame(this.notificationChannel, TestUtils.getPropertyValue(this.snsGateway, "inputChannel"));
|
||||
assertSame(this.snsGatewayHandler, TestUtils.getPropertyValue(this.snsGateway, "handler"));
|
||||
assertFalse(TestUtils.getPropertyValue(this.snsGateway, "autoStartup", Boolean.class));
|
||||
assertEquals(new Integer(201), TestUtils.getPropertyValue(this.snsGateway, "phase", Integer.class));
|
||||
assertTrue(TestUtils.getPropertyValue(this.snsGatewayHandler, "produceReply", Boolean.class));
|
||||
assertSame(this.errorChannel, TestUtils.getPropertyValue(this.snsGatewayHandler, "outputChannel"));
|
||||
|
||||
assertSame(this.amazonSns, TestUtils.getPropertyValue(this.snsGatewayHandler, "amazonSns"));
|
||||
assertNotNull(TestUtils.getPropertyValue(this.snsGatewayHandler, "evaluationContext"));
|
||||
assertEquals("foo",
|
||||
TestUtils.getPropertyValue(this.snsGatewayHandler, "topicArnExpression", Expression.class)
|
||||
.getExpressionString());
|
||||
assertEquals("bar",
|
||||
TestUtils.getPropertyValue(this.snsGatewayHandler, "subjectExpression", Expression.class)
|
||||
.getExpressionString());
|
||||
assertEquals("payload.toUpperCase()",
|
||||
TestUtils.getPropertyValue(this.snsGatewayHandler, "bodyExpression", Expression.class)
|
||||
.getExpressionString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.integration.aws.outbound;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.aws.support.SnsBodyBuilder;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public class SnsMessageBuilderTests {
|
||||
|
||||
@Test
|
||||
public void testSnsMessageBuilder() {
|
||||
try {
|
||||
SnsBodyBuilder.withDefault("");
|
||||
fail("IllegalArgumentException expected");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertThat(e, instanceOf(IllegalArgumentException.class));
|
||||
assertThat(e.getMessage(), containsString("defaultMessage must not be empty."));
|
||||
}
|
||||
|
||||
String message = SnsBodyBuilder.withDefault("foo").build();
|
||||
assertEquals("{\"default\":\"foo\"}", message);
|
||||
|
||||
try {
|
||||
SnsBodyBuilder.withDefault("foo")
|
||||
.forProtocols("{\"foo\" : \"bar\"}")
|
||||
.build();
|
||||
fail("IllegalArgumentException expected");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertThat(e, instanceOf(IllegalArgumentException.class));
|
||||
assertThat(e.getMessage(), containsString("protocols must not be empty."));
|
||||
}
|
||||
try {
|
||||
SnsBodyBuilder.withDefault("foo")
|
||||
.forProtocols("{\"foo\" : \"bar\"}", "")
|
||||
.build();
|
||||
fail("IllegalArgumentException expected");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertThat(e, instanceOf(IllegalArgumentException.class));
|
||||
assertThat(e.getMessage(), containsString("protocols must not contain empty elements."));
|
||||
}
|
||||
|
||||
message = SnsBodyBuilder.withDefault("foo")
|
||||
.forProtocols("{\"foo\" : \"bar\"}", "sms")
|
||||
.build();
|
||||
|
||||
assertEquals("{\"default\":\"foo\",\"sms\":\"{\\\"foo\\\" : \\\"bar\\\"}\"}", message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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.integration.aws.outbound;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.integration.aws.support.AwsHeaders;
|
||||
import org.springframework.integration.aws.support.SnsBodyBuilder;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.config.EnableIntegration;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.amazonaws.services.sns.AmazonSNS;
|
||||
import com.amazonaws.services.sns.model.PublishRequest;
|
||||
import com.amazonaws.services.sns.model.PublishResult;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class SnsMessageHandlerTests {
|
||||
|
||||
private static SpelExpressionParser PARSER = new SpelExpressionParser();
|
||||
|
||||
@Autowired
|
||||
private MessageChannel sendToSnsChannel;
|
||||
|
||||
@Autowired
|
||||
private AmazonSNS amazonSNS;
|
||||
|
||||
@Test
|
||||
public void testSnsMessageHandler() {
|
||||
SnsBodyBuilder payload = SnsBodyBuilder.withDefault("foo")
|
||||
.forProtocols("{\"foo\" : \"bar\"}", "sms");
|
||||
|
||||
QueueChannel replyChannel = new QueueChannel();
|
||||
|
||||
Message<?> message = MessageBuilder.withPayload(payload)
|
||||
.setHeader("topic", "topic")
|
||||
.setHeader("subject", "subject")
|
||||
.setReplyChannel(replyChannel)
|
||||
.build();
|
||||
|
||||
this.sendToSnsChannel.send(message);
|
||||
|
||||
Message<?> reply = replyChannel.receive(1000);
|
||||
assertNotNull(reply);
|
||||
|
||||
ArgumentCaptor<PublishRequest> captor = ArgumentCaptor.forClass(PublishRequest.class);
|
||||
verify(this.amazonSNS).publish(captor.capture());
|
||||
|
||||
PublishRequest publishRequest = captor.getValue();
|
||||
|
||||
assertEquals("json", publishRequest.getMessageStructure());
|
||||
assertEquals("topic", publishRequest.getTopicArn());
|
||||
assertEquals("subject", publishRequest.getSubject());
|
||||
assertEquals("{\"default\":\"foo\",\"sms\":\"{\\\"foo\\\" : \\\"bar\\\"}\"}", publishRequest.getMessage());
|
||||
|
||||
assertEquals("111", reply.getHeaders().get(AwsHeaders.SNS_PUBLISHED_MESSAGE_ID));
|
||||
assertEquals("topic", reply.getHeaders().get(AwsHeaders.TOPIC));
|
||||
assertSame(publishRequest, reply.getPayload());
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableIntegration
|
||||
public static class ContextConfiguration {
|
||||
|
||||
@Bean
|
||||
public AmazonSNS amazonSNS() {
|
||||
AmazonSNS mock = mock(AmazonSNS.class);
|
||||
|
||||
doAnswer(new Answer<PublishResult>() {
|
||||
|
||||
@Override
|
||||
public PublishResult answer(InvocationOnMock invocation) throws Throwable {
|
||||
return new PublishResult().withMessageId("111");
|
||||
}
|
||||
}).when(mock).publish(any(PublishRequest.class));
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "sendToSnsChannel")
|
||||
public MessageHandler snsMessageHandler() {
|
||||
SnsMessageHandler snsMessageHandler = new SnsMessageHandler(amazonSNS(), true);
|
||||
snsMessageHandler.setTopicArnExpression(PARSER.parseExpression("headers.topic"));
|
||||
snsMessageHandler.setSubjectExpression(PARSER.parseExpression("headers.subject"));
|
||||
snsMessageHandler.setBodyExpression(PARSER.parseExpression("payload"));
|
||||
return snsMessageHandler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user