/** * Copyright (C) 2014 Typesafe Inc. */ package akka.stream.javadsl; import akka.japi.Pair; import akka.pattern.Patterns; import akka.japi.tuple.Tuple4; import akka.stream.*; import akka.stream.javadsl.GraphDSL.Builder; import akka.stream.stage.*; import akka.japi.function.*; import akka.stream.testkit.AkkaSpec; import akka.testkit.JavaTestKit; import akka.testkit.TestProbe; import org.junit.ClassRule; import org.junit.Test; import org.reactivestreams.Publisher; import scala.concurrent.Await; import scala.concurrent.Future; import scala.concurrent.duration.Duration; import scala.runtime.BoxedUnit; import java.util.*; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; public class FlowGraphTest extends StreamTest { public FlowGraphTest() { super(actorSystemResource); } @ClassRule public static AkkaJUnitActorSystemResource actorSystemResource = new AkkaJUnitActorSystemResource("FlowGraphTest", AkkaSpec.testConf()); @SuppressWarnings("serial") public Creator> op() { return new akka.japi.function.Creator>() { @Override public PushPullStage create() throws Exception { return new PushPullStage() { @Override public SyncDirective onPush(T element, Context ctx) { return ctx.push(element); } @Override public SyncDirective onPull(Context ctx) { return ctx.pull(); } }; } }; } @Test public void mustBeAbleToUseMerge() throws Exception { final Flow f1 = Flow.of(String.class).transform(FlowGraphTest.this. op()).named("f1"); final Flow f2 = Flow.of(String.class).transform(FlowGraphTest.this. op()).named("f2"); @SuppressWarnings("unused") final Flow f3 = Flow.of(String.class).transform(FlowGraphTest.this. op()).named("f3"); final Source in1 = Source.from(Arrays.asList("a", "b", "c")); final Source in2 = Source.from(Arrays.asList("d", "e", "f")); final Sink> publisher = Sink.asPublisher(false); final Source source = Source.fromGraph( GraphDSL.create(new Function, SourceShape>() { @Override public SourceShape apply(Builder b) throws Exception { final UniformFanInShape merge = b.add(Merge.create(2)); b.from(b.add(in1)).via(b.add(f1)).toInlet(merge.in(0)); b.from(b.add(in2)).via(b.add(f2)).toInlet(merge.in(1)); return new SourceShape(merge.out()); } })); // collecting final Publisher pub = source.runWith(publisher, materializer); final Future> all = Source.fromPublisher(pub).grouped(100).runWith(Sink.>head(), materializer); final List result = Await.result(all, Duration.apply(200, TimeUnit.MILLISECONDS)); assertEquals(new HashSet(Arrays.asList("a", "b", "c", "d", "e", "f")), new HashSet(result)); } @Test public void mustBeAbleToUseZip() { final JavaTestKit probe = new JavaTestKit(system); final Iterable input1 = Arrays.asList("A", "B", "C"); final Iterable input2 = Arrays.asList(1, 2, 3); RunnableGraph.fromGraph( GraphDSL.create( new Function,ClosedShape>() { @Override public ClosedShape apply(final Builder b) throws Exception { final Source in1 = Source.from(input1); final Source in2 = Source.from(input2); final FanInShape2> zip = b.add(Zip.create()); final Sink, BoxedUnit> out = createSink(probe); b.from(b.add(in1)).toInlet(zip.in0()); b.from(b.add(in2)).toInlet(zip.in1()); b.from(zip.out()).to(b.add(out)); return ClosedShape.getInstance(); } })).run(materializer); List output = Arrays.asList(probe.receiveN(3)); @SuppressWarnings("unchecked") List> expected = Arrays.asList(new Pair("A", 1), new Pair( "B", 2), new Pair("C", 3)); assertEquals(expected, output); } @Test public void mustBeAbleToUseUnzip() { final JavaTestKit probe1 = new JavaTestKit(system); final JavaTestKit probe2 = new JavaTestKit(system); @SuppressWarnings("unchecked") final List> input = Arrays.asList(new Pair("A", 1), new Pair("B", 2), new Pair("C", 3)); final Iterable expected1 = Arrays.asList("A", "B", "C"); final Iterable expected2 = Arrays.asList(1, 2, 3); RunnableGraph.fromGraph(GraphDSL.create( new Function, ClosedShape>() { @Override public ClosedShape apply(final Builder b) throws Exception { final SourceShape> in = b.add(Source.from(input)); final FanOutShape2, String, Integer> unzip = b.add(Unzip.create()); final SinkShape out1 = b.add(FlowGraphTest.createSink(probe1)); final SinkShape out2 = b.add(FlowGraphTest.createSink(probe2)); b.from(in).toInlet(unzip.in()); b.from(unzip.out0()).to(out1); b.from(unzip.out1()).to(out2); return ClosedShape.getInstance(); } })).run(materializer); List output1 = Arrays.asList(probe1.receiveN(3)); List output2 = Arrays.asList(probe2.receiveN(3)); assertEquals(expected1, output1); assertEquals(expected2, output2); } private static Sink createSink(final JavaTestKit probe){ return Sink.actorRef(probe.getRef(), "onComplete"); } @Test public void mustBeAbleToUseUnzipWith() throws Exception { final JavaTestKit probe1 = new JavaTestKit(system); final JavaTestKit probe2 = new JavaTestKit(system); RunnableGraph.fromGraph(GraphDSL.create( new Function, ClosedShape>() { @Override public ClosedShape apply(final Builder b) throws Exception { final Source in = Source.single(1); final FanOutShape2 unzip = b.add(UnzipWith.create( new Function>() { @Override public Pair apply(Integer l) throws Exception { return new Pair(l + "!", l); } }) ); final SinkShape out1 = b.add(FlowGraphTest.createSink(probe1)); final SinkShape out2 = b.add(FlowGraphTest.createSink(probe2)); b.from(b.add(in)).toInlet(unzip.in()); b.from(unzip.out0()).to(out1); b.from(unzip.out1()).to(out2); return ClosedShape.getInstance(); } } )).run(materializer); Duration d = Duration.create(300, TimeUnit.MILLISECONDS); Object output1 = probe1.receiveOne(d); Object output2 = probe2.receiveOne(d); assertEquals("1!", output1); assertEquals(1, output2); } @Test public void mustBeAbleToUseUnzip4With() throws Exception { final JavaTestKit probe1 = new JavaTestKit(system); final JavaTestKit probe2 = new JavaTestKit(system); final JavaTestKit probe3 = new JavaTestKit(system); final JavaTestKit probe4 = new JavaTestKit(system); RunnableGraph.fromGraph(GraphDSL.create( new Function, ClosedShape>() { @Override public ClosedShape apply(final Builder b) throws Exception { final Source in = Source.single(1); final FanOutShape4 unzip = b.add(UnzipWith.create4( new Function>() { @Override public Tuple4 apply(Integer l) throws Exception { return new Tuple4(l.toString(), l, l + "+" + l, l + l); } }) ); final SinkShape out1 = b.add(FlowGraphTest.createSink(probe1)); final SinkShape out2 = b.add(FlowGraphTest.createSink(probe2)); final SinkShape out3 = b.add(FlowGraphTest.createSink(probe3)); final SinkShape out4 = b.add(FlowGraphTest.createSink(probe4)); b.from(b.add(in)).toInlet(unzip.in()); b.from(unzip.out0()).to(out1); b.from(unzip.out1()).to(out2); b.from(unzip.out2()).to(out3); b.from(unzip.out3()).to(out4); return ClosedShape.getInstance(); } })).run(materializer); Duration d = Duration.create(300, TimeUnit.MILLISECONDS); Object output1 = probe1.receiveOne(d); Object output2 = probe2.receiveOne(d); Object output3 = probe3.receiveOne(d); Object output4 = probe4.receiveOne(d); assertEquals("1", output1); assertEquals(1, output2); assertEquals("1+1", output3); assertEquals(2, output4); } @Test public void mustBeAbleToUseZipWith() throws Exception { final Source in1 = Source.single(1); final Source in2 = Source.single(10); final Graph, BoxedUnit> sumZip = ZipWith.create( new Function2() { @Override public Integer apply(Integer l, Integer r) throws Exception { return l + r; } }); final Future future = RunnableGraph.fromGraph(GraphDSL.create(Sink.head(), new Function2>, SinkShape, ClosedShape>() { @Override public ClosedShape apply(Builder> b, SinkShape out) throws Exception { final FanInShape2 zip = b.add(sumZip); b.from(b.add(in1)).toInlet(zip.in0()); b.from(b.add(in2)).toInlet(zip.in1()); b.from(zip.out()).to(out); return ClosedShape.getInstance(); } })).run(materializer); final Integer result = Await.result(future, Duration.create(300, TimeUnit.MILLISECONDS)); assertEquals(11, (int) result); } @Test public void mustBeAbleToUseZip4With() throws Exception { final Source in1 = Source.single(1); final Source in2 = Source.single(10); final Source in3 = Source.single(100); final Source in4 = Source.single(1000); final Graph, BoxedUnit> sumZip = ZipWith.create4( new Function4() { @Override public Integer apply(Integer i1, Integer i2, Integer i3, Integer i4) throws Exception { return i1 + i2 + i3 + i4; } }); final Future future = RunnableGraph.fromGraph( GraphDSL.create(Sink.head(), new Function2>, SinkShape, ClosedShape>() { @Override public ClosedShape apply(Builder> b, SinkShape out) throws Exception { final FanInShape4 zip = b.add(sumZip); b.from(b.add(in1)).toInlet(zip.in0()); b.from(b.add(in2)).toInlet(zip.in1()); b.from(b.add(in3)).toInlet(zip.in2()); b.from(b.add(in4)).toInlet(zip.in3()); b.from(zip.out()).to(out); return ClosedShape.getInstance(); } })).run(materializer); final Integer result = Await.result(future, Duration.create(300, TimeUnit.MILLISECONDS)); assertEquals(1111, (int) result); } @Test public void mustBeAbleToUseMatValue() throws Exception { @SuppressWarnings("unused") final Source in1 = Source.single(1); final TestProbe probe = TestProbe.apply(system); final Future future = RunnableGraph.fromGraph( GraphDSL.create(Sink. head(), new Function2>, SinkShape, ClosedShape>() { @Override public ClosedShape apply(Builder> b, SinkShape out) throws Exception { b.from(b.add(Source.single(1))).to(out); b.from(b.materializedValue()).to(b.add(Sink.foreach(new Procedure>(){ public void apply(Future mat) throws Exception { Patterns.pipe(mat, system.dispatcher()).to(probe.ref()); } }))); return ClosedShape.getInstance(); } })).run(materializer); final Integer result = Await.result(future, Duration.create(300, TimeUnit.MILLISECONDS)); assertEquals(1, (int) result); probe.expectMsg(1); } }