/* * Copyright 2013-2014 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.xd.dirt.stream; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.util.Collections; import java.util.Date; import java.util.Map; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.integration.support.MessageBuilder; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.MessagingException; import org.springframework.messaging.converter.ContentTypeResolver; import org.springframework.util.MimeType; import org.springframework.xd.dirt.integration.bus.StringConvertingContentTypeResolver; import org.springframework.xd.dirt.integration.bus.converter.MessageConverterUtils; import org.springframework.xd.module.core.Module; import org.springframework.xd.tuple.DefaultTuple; import org.springframework.xd.tuple.Tuple; /** * @author David Turanski */ public class TypeConvertingStreamTests extends StreamTestSupport { private ContentTypeResolver contentTypeResolver = new StringConvertingContentTypeResolver(); @BeforeClass public static void setup() { deployStream( "test1", "source --outputType=application/json | sink --inputType=application/x-xd-tuple"); } @Test public void testParametersPresent() { Module source = getDeployedSource("test1"); Module sink = getDeployedSink("test1"); assertEquals("application/json", source.getProperties().get("outputType")); assertEquals("application/x-xd-tuple", sink.getProperties().get("inputType")); } @Test public void testBasicTypeConversion() { MessageTest test = new MessageTest() { @Override public void test(Message<?> message) throws MessagingException { assertTrue(message.getPayload() instanceof Tuple); Tuple t = (Tuple) message.getPayload(); assertEquals("bar", t.getString("s")); assertEquals(9999, t.getInt("i")); assertEquals(MessageConverterUtils.javaObjectMimeType(DefaultTuple.class), contentTypeResolver.resolve(message.getHeaders())); } }; sendPayloadAndVerifyOutput("test1", new Foo("bar", 9999), test); } @Test public void testBasicTypeConversionWithTap() { MessageTest test = new MessageTest() { @Override public void test(Message<?> message) throws MessagingException { assertTrue(message.getPayload() instanceof String); assertEquals("{\"s\":\"bar\",\"i\":9999}", message.getPayload()); // TODO: This not working with the tap // assertEquals(MediaType.APPLICATION_JSON, // message.getHeaders().get(MessageHeaders.CONTENT_TYPE)); } }; sendPayloadAndVerifyTappedOutput("test1", new Foo("bar", 9999), "source", test); } @Test public void testInputTypeAsTJavaTypeConversion() { deployStream( "test2", "source --outputType=application/json | sink --inputType=" + Tuple.class.getName()); MessageTest test = new MessageTest() { @Override public void test(Message<?> message) throws MessagingException { assertTrue(message.getPayload() instanceof Tuple); Tuple t = (Tuple) message.getPayload(); assertEquals("bar", t.getString("s")); assertEquals(9999, t.getInt("i")); assertEquals(MimeType.valueOf("application/x-java-object;type=" + DefaultTuple.class.getName()), contentTypeResolver.resolve(message.getHeaders())); } }; sendPayloadAndVerifyOutput("test2", new Foo("bar", 9999), test); } @Test public void testRawBytes() { deployStream( "rawbytes", "source --outputType=application/x-java-serialized-object | sink"); MessageTest test = new MessageTest() { @Override public void test(Message<?> message) throws MessagingException { assertTrue(message.getPayload() instanceof byte[]); assertEquals(MimeType.valueOf("application/x-java-serialized-object"), contentTypeResolver.resolve(message.getHeaders())); } }; sendPayloadAndVerifyOutput("rawbytes", new Foo("bar", 9999), test); } @Test public void unknownContentTypeWillNotDeploy() { assertFalse(deployStream( "xml", "source --outputType=application/xml | sink")); } @Test public void testObjectToStringConversion() { final Foo foo = new Foo("hello", 123); deployStream( "fooToString", "source --outputType=text/plain | sink"); MessageTest test = new MessageTest() { @Override public void test(Message<?> message) throws MessagingException { assertEquals(foo.toString(), message.getPayload()); assertEquals(MimeType.valueOf("text/plain"), contentTypeResolver.resolve(message.getHeaders())); } }; sendPayloadAndVerifyOutput("fooToString", foo, test); } @Test public void testJsonToMapConversion() { deployStream( "jsonToMap", "source --outputType=application/json | sink --inputType=java.util.Map"); MessageTest test = new MessageTest() { @SuppressWarnings("rawtypes") @Override public void test(Message<?> message) throws MessagingException { Map map = (Map) message.getPayload(); assertEquals("hello", map.get("s")); assertEquals(123, map.get("i")); assertEquals(MimeType.valueOf("application/x-java-object;type=java.util.Map"), contentTypeResolver.resolve(message.getHeaders())); } }; sendPayloadAndVerifyOutput("jsonToMap", new Foo("hello", 123), test); } @Test public void testDefaultTypeConversion() { final Date now = new Date(); /* * Should fall back to Default conversion service */ deployStream( "dateToString", "source --outputType=text/plain | sink"); MessageTest test = new MessageTest() { @Override public void test(Message<?> message) throws MessagingException { assertEquals(now.toString(), message.getPayload()); assertEquals(MimeType.valueOf("text/plain"), contentTypeResolver.resolve(message.getHeaders())); } }; sendPayloadAndVerifyOutput("dateToString", now, test); } // TODO: Test with class value (testtupleprocessor) - fails currently because converted to string 'class // <className>' @Test public void testModuleWithDefaultInputTypeProperties() { deployStream( "defaultInputType", "source --outputType=application/json | testtupleprocessor | sink"); MessageTest test = new MessageTest() { @Override public void test(Message<?> message) throws MessagingException { assertTrue(Tuple.class.isAssignableFrom(message.getPayload().getClass())); assertEquals(MimeType.valueOf("application/x-java-object;type=" + DefaultTuple.class.getName()), contentTypeResolver.resolve(message.getHeaders())); } }; sendPayloadAndVerifyOutput("defaultInputType", new Foo("hello", 123), test); } @Test public void testOverrideInputTypeForModuleWithDefaultInputTypeProperties() { deployStream( "overrideInputType", "source --outputType=application/json | testtupleprocessor --inputType=java.lang.String | sink"); MessageTest test = new MessageTest() { @Override public void test(Message<?> message) throws MessagingException { assertTrue(message.getPayload() instanceof String); } }; sendPayloadAndVerifyOutput("overrideInputType", new Foo("hello", 123), test); } @Test public void testModuleWithDefaultInputTypeDefinedAsClass() { deployStream( "classInputType", "source --outputType=application/json | testtupleprocessor_pojo_config | sink"); MessageTest test = new MessageTest() { @Override public void test(Message<?> message) throws MessagingException { assertTrue(Tuple.class.isAssignableFrom(message.getPayload().getClass())); assertEquals(MimeType.valueOf("application/x-java-object;type=" + DefaultTuple.class.getName()), contentTypeResolver.resolve(message.getHeaders())); } }; sendPayloadAndVerifyOutput("classInputType", new Foo("hello", 123), test); } @Test public void testStringToByteArray() { deployStream( "stringToBytes", "source --outputType=application/octet-stream | sink"); MessageTest test = new MessageTest() { @Override public void test(Message<?> message) throws MessagingException { assertTrue(byte[].class.isAssignableFrom(message.getPayload().getClass())); assertEquals(MimeType.valueOf("text/plain;charset=UTF-8"), contentTypeResolver.resolve(message.getHeaders())); try { assertEquals("hello\u00F6\u00FF", new String((byte[]) message.getPayload(), "UTF-8")); } catch (UnsupportedEncodingException e) { } } }; Message<String> msg = MessageBuilder.withPayload("hello\u00F6\u00FF"). copyHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, "text/plain;charset=UTF-8")).build(); sendMessageAndVerifyOutput("stringToBytes", msg, test); } @SuppressWarnings("serial") static class Foo implements Serializable { private String s; private int i; public Foo(String s, int i) { this.s = s; this.i = i; } public String getS() { return s; } public void setS(String s) { this.s = s; } public int getI() { return i; } public void setI(int i) { this.i = i; } @Override public String toString() { return s + ":" + i; } } }