/* # Licensed Materials - Property of IBM # Copyright IBM Corp. 2015 */ package com.ibm.streamsx.topology.test.api; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.TimeUnit; import org.junit.Test; import com.ibm.streamsx.topology.TStream; import com.ibm.streamsx.topology.Topology; import com.ibm.streamsx.topology.context.StreamsContext.Type; import com.ibm.streamsx.topology.function.Function; import com.ibm.streamsx.topology.function.FunctionContainer; import com.ibm.streamsx.topology.function.FunctionContext; import com.ibm.streamsx.topology.function.Initializable; import com.ibm.streamsx.topology.function.Predicate; import com.ibm.streamsx.topology.function.ToIntFunction; import com.ibm.streamsx.topology.streams.BeaconStreams; import com.ibm.streamsx.topology.streams.CollectionStreams; import com.ibm.streamsx.topology.streams.StringStreams; import com.ibm.streamsx.topology.test.AllowAll; import com.ibm.streamsx.topology.test.TestTopology; import com.ibm.streamsx.topology.tester.Condition; import com.ibm.streamsx.topology.tester.Tester; public class StreamTest extends TestTopology { public static void assertStream(Topology f, TStream<?> stream) { TopologyTest.assertFlowElement(f, stream); } @Test public void testBasics() throws Exception { assumeTrue(isMainRun()); final Topology topology = new Topology("BasicStream"); assertEquals("BasicStream", topology.getName()); assertSame(topology, topology.topology()); TStream<String> source = topology.strings("a", "b", "c"); assertStream(topology, source); assertSame(String.class, source.getTupleClass()); assertSame(String.class, source.getTupleType()); assertNotSame(source, source.autonomous()); } @Test public void testStringFilter() throws Exception { final Topology f = newTopology("StringFilter"); TStream<String> source = f.strings("hello", "goodbye", "farewell"); assertStream(f, source); TStream<String> filtered = source.filter(lengthFilter(5)); completeAndValidate(filtered, 10, "goodbye", "farewell"); } @SuppressWarnings("serial") public static Predicate<String> lengthFilter(final int length) { return new Predicate<String>() { @Override public boolean test(String v1) { return v1.length() > length; } }; } @Test public void testTransform() throws Exception { final Topology f = newTopology("TransformStream"); TStream<String> source = f.strings("325", "457", "9325"); assertStream(f, source); TStream<Integer> i1 = source.transform(stringToInt()); TStream<Integer> i2 = i1.transform(add17()); completeAndValidate(i2, 10, "342", "474", "9342"); } @Test public void testTransformWithDrop() throws Exception { final Topology f = newTopology("TransformStream"); TStream<String> source = f.strings("93", "68", "221"); assertStream(f, source); TStream<Integer> i1 = source.transform(stringToIntExcept68()); TStream<Integer> i2 = i1.transform(add17()); completeAndValidate(i2, 10, "110", "238"); } @Test public void testMultiTransform() throws Exception { final Topology topology = newTopology("MultiTransformStream"); TStream<String> source = topology.strings("mary had a little lamb", "its fleece was white as snow"); assertStream(topology, source); TStream<String> words = source.multiTransform(splitWords()); completeAndValidate(words, 10, "mary", "had", "a", "little", "lamb", "its", "fleece", "was", "white", "as", "snow"); } @Test public void testUnionNops() throws Exception { assumeTrue(isMainRun()); final Topology f = newTopology("Union"); TStream<String> s1 = f.strings("A1", "B1", "C1", "D1"); Set<TStream<String>> empty = Collections.emptySet(); assertSame(s1, s1.union(s1)); assertSame(s1, s1.union(empty)); assertSame(s1, s1.union(Collections.singleton(s1))); } @Test public void testUnion() throws Exception { final Topology topology = newTopology("Union"); TStream<String> s1 = topology.strings("A1", "B1", "C1", "D1"); TStream<String> s2 = topology.strings("A2", "B2", "C2", "D2"); List<String> l3 = new ArrayList<>(); l3.add("A3"); l3.add("B3"); TStream<String> s3 = topology.constants(l3); List<String> l4 = new ArrayList<>(); l4.add("A4"); l4.add("B4"); TStream<String> s4 = topology.constants(l4); assertNotSame(s1, s2); TStream<String> su = s1.union(s2); assertNotSame(su, s1); assertNotSame(su, s2); // Merge with two different schema types // but the primary has the correct direct type. su = su.union(s3); assertEquals(String.class, su.getTupleClass()); assertEquals(String.class, su.getTupleType()); // Merge with two different schema types // but the primary has the generic type assertNull(s4.getTupleClass()); su = s4.union(su); assertEquals(String.class, su.getTupleClass()); assertEquals(String.class, su.getTupleType()); // TODO - testing doesn't work against union streams in embedded. su = su.filter(new AllowAll<String>()); Tester tester = topology.getTester(); Condition<Long> suCount = tester.tupleCount(su, 12); Condition<List<String>> suContents = tester.stringContentsUnordered(su, "A1", "B1", "C1", "D1", "A2", "B2", "C2", "D2", "A3", "B3", "A4", "B4"); //assertTrue(complete(tester, suCount, 10, TimeUnit.SECONDS)); complete(tester, suCount, 10, TimeUnit.SECONDS); assertTrue("SU:" + suContents, suContents.valid()); assertTrue("SU:" + suCount, suCount.valid()); } @Test public void testUnionSet() throws Exception { final Topology topology = newTopology("Union"); TStream<String> s1 = topology.strings("A1", "B1", "C1"); TStream<String> s2 = topology.strings("A2", "B2", "C2", "D2"); TStream<String> s3 = topology.strings("A3", "B3", "C3"); Set<TStream<String>> streams = new HashSet<TStream<String>>(); streams.add(s2); streams.add(s3); TStream<String> su = s1.union(streams); // TODO - testing doesn't work against union streams in embedded. su = su.filter(new AllowAll<String>()); Tester tester = topology.getTester(); Condition<Long> suCount = tester.tupleCount(su, 10); Condition<List<String>> suContents = tester.stringContentsUnordered(su, "A1", "B1", "C1", "A2", "B2", "C2", "D2", "A3", "B3", "C3"); assertTrue(complete(tester, suCount, 10, TimeUnit.SECONDS)); // assertTrue("SU:" + suContents, suContents.valid()); assertTrue("SU:" + suCount, suCount.valid()); assertTrue("SUContents:" + suContents, suContents.valid()); } @Test public void testSimpleParallel() throws Exception { final Topology topology = newTopology("EmbeddedParallel"); TStream<Number> s1 = topology.numbers(1, 2, 3, 94, 5, 6).parallel(6) .filter(new AllowAll<Number>()).endParallel(); TStream<String> sp = StringStreams.toString(s1); Tester tester = topology.getTester(); Condition<Long> spCount = tester.tupleCount(sp, 6); Condition<List<String>> spContents = tester.stringContentsUnordered(sp, "1", "2", "3", "94", "5", "6"); complete(tester, spCount, 60, TimeUnit.SECONDS); // assertTrue("SU:" + suContents, suContents.valid()); assertTrue("SP:" + spCount, spCount.valid()); assertTrue("SPContents:" + spContents, spContents.valid()); } @Test public void testSplit() throws Exception { final Topology topology = newTopology("testSplit"); TStream<String> s1 = topology.strings("ch0", "ch1", "ch2", "omit", "another-ch2", "another-ch1", "another-ch0", "another-omit"); List<TStream<String>> splits = s1.split(3, myStringSplitter()); assertEquals("list size", 3, splits.size()); Tester tester = topology.getTester(); List<Condition<List<String>>> contents = new ArrayList<>(); for(int i = 0; i < splits.size(); i++) { TStream<String> ch = splits.get(i); Condition<List<String>> chContents = tester.stringContents(ch, "ch"+i, "another-ch"+i); contents.add(chContents); } TStream<String> all = splits.get(0).union( new HashSet<>(splits.subList(1, splits.size()))); Condition<Long> uCount = tester.tupleCount(all, 6); complete(tester, uCount, 10, TimeUnit.SECONDS); for(int i = 0; i < splits.size(); i++) { assertTrue("chContents["+i+"]:" + contents.get(i), contents.get(i).valid()); } } /** * Partition strings based on the last character of the string. * If the last character is a digit return its value as an int, else return -1. * @return */ @SuppressWarnings("serial") private static ToIntFunction<String> myStringSplitter() { return new ToIntFunction<String>() { @Override public int applyAsInt(String s) { char ch = s.charAt(s.length() - 1); return Character.digit(ch, 10); } }; } @SuppressWarnings("serial") static Function<String, Integer> stringToInt() { return new Function<String, Integer>() { @Override public Integer apply(String v1) { return Integer.valueOf(v1); } }; } @SuppressWarnings("serial") static Function<String, Integer> stringToIntExcept68() { return new Function<String, Integer>() { @Override public Integer apply(String v1) { Integer i = Integer.valueOf(v1); return (i == 68) ? null : i; } }; } @SuppressWarnings("serial") static Function<Integer, Integer> add17() { return new Function<Integer, Integer>() { @Override public Integer apply(Integer v1) { return v1 + 17; } }; } @SuppressWarnings("serial") static Function<String, Iterable<String>> splitWords() { return new Function<String, Iterable<String>>() { @Override public Iterable<String> apply(String v1) { return Arrays.asList(v1.split(" ")); } }; } @Test public void testFunctionContextNonDistributed() throws Exception { assumeTrue(getTesterType() != Type.DISTRIBUTED_TESTER); Topology t = newTopology(); TStream<Map<String, Object>> values = BeaconStreams.single(t).transform(new ExtractFunctionContext()); TStream<String> strings = StringStreams.toString(CollectionStreams.flattenMap(values)); Tester tester = t.getTester(); Condition<Long> spCount = tester.tupleCount(strings, 7); Condition<List<String>> spContents = tester.stringContents(strings, "channel=-1", "domainId=" + System.getProperty("user.name"), "id=0", "instanceId=" + System.getProperty("user.name"), "jobId=0", "maxChannels=0", "relaunchCount=0" ); complete(tester, spCount, 60, TimeUnit.SECONDS); // assertTrue("SU:" + suContents, suContents.valid()); assertTrue("SP:" + spCount, spCount.valid()); assertTrue("SPContents:" + spContents, spContents.valid()); } public static class ExtractFunctionContext implements Function<Long,Map<String,Object>>, Initializable { private static final long serialVersionUID = 1L; private FunctionContext functionContext; @Override public Map<String, Object> apply(Long v) { Map<String,Object> values = new TreeMap<>(); values.put("channel", functionContext.getChannel()); values.put("maxChannels", functionContext.getMaxChannels()); FunctionContainer container = functionContext.getContainer(); values.put("id", container.getId()); values.put("jobId", container.getJobId()); values.put("relaunchCount", container.getRelaunchCount()); values.put("domainId", container.getDomainId()); values.put("instanceId", container.getInstanceId()); return values; } @Override public void initialize(FunctionContext functionContext) throws Exception { this.functionContext = functionContext; } } }