2014-10-10 10:39:29 +02:00
|
|
|
/**
|
|
|
|
|
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
|
|
|
|
*/
|
2014-10-27 14:35:41 +01:00
|
|
|
package akka.stream.scaladsl
|
2014-10-10 10:39:29 +02:00
|
|
|
|
2015-01-27 18:29:20 +01:00
|
|
|
import akka.stream.ActorFlowMaterializer
|
|
|
|
|
import akka.stream.ActorFlowMaterializerSettings
|
2014-10-27 14:35:41 +01:00
|
|
|
import akka.stream.testkit.AkkaSpec
|
2014-10-10 10:39:29 +02:00
|
|
|
import akka.stream.testkit.StreamTestKit.SubscriberProbe
|
2014-10-27 14:35:41 +01:00
|
|
|
import akka.stream.testkit.StreamTestKit
|
2015-01-28 14:19:50 +01:00
|
|
|
import org.reactivestreams.Subscriber
|
|
|
|
|
import akka.stream._
|
2014-10-10 10:39:29 +02:00
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
object GraphFlowSpec {
|
2014-10-17 14:05:50 +02:00
|
|
|
val source1 = Source(0 to 3)
|
2014-10-10 10:39:29 +02:00
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val partialGraph = FlowGraph.partial() { implicit b ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
2014-10-17 14:05:50 +02:00
|
|
|
val source2 = Source(4 to 9)
|
|
|
|
|
val source3 = Source.empty[Int]
|
|
|
|
|
val source4 = Source.empty[String]
|
2014-10-10 10:39:29 +02:00
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val inMerge = b.add(Merge[Int](2))
|
|
|
|
|
val outMerge = b.add(Merge[String](2))
|
|
|
|
|
val m2 = b.add(Merge[Int](2))
|
|
|
|
|
|
|
|
|
|
inMerge.out.map(_ * 2) ~> m2.in(0)
|
|
|
|
|
m2.out.map(_ / 2).map(i ⇒ (i + 1).toString) ~> outMerge.in(0)
|
|
|
|
|
|
|
|
|
|
source2 ~> inMerge.in(0)
|
|
|
|
|
source3 ~> m2.in(1)
|
|
|
|
|
source4 ~> outMerge.in(1)
|
|
|
|
|
FlowShape(inMerge.in(1), outMerge.out)
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val stdRequests = 10
|
|
|
|
|
val stdResult = Set(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
class GraphFlowSpec extends AkkaSpec {
|
2014-10-10 10:39:29 +02:00
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
import GraphFlowSpec._
|
2014-10-10 10:39:29 +02:00
|
|
|
|
2015-01-27 18:29:20 +01:00
|
|
|
val settings = ActorFlowMaterializerSettings(system)
|
2014-10-10 10:39:29 +02:00
|
|
|
.withInputBuffer(initialSize = 2, maxSize = 16)
|
|
|
|
|
|
2015-01-27 18:29:20 +01:00
|
|
|
implicit val materializer = ActorFlowMaterializer(settings)
|
2014-10-10 10:39:29 +02:00
|
|
|
|
|
|
|
|
def validateProbe(probe: SubscriberProbe[Int], requests: Int, result: Set[Int]): Unit = {
|
|
|
|
|
val subscription = probe.expectSubscription()
|
|
|
|
|
|
|
|
|
|
val collected = (1 to requests).map { _ ⇒
|
|
|
|
|
subscription.request(1)
|
|
|
|
|
probe.expectNext()
|
|
|
|
|
}.toSet
|
|
|
|
|
|
|
|
|
|
collected should be(result)
|
|
|
|
|
probe.expectComplete()
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"FlowGraphs" when {
|
|
|
|
|
"turned into flows" should {
|
2014-10-17 14:05:50 +02:00
|
|
|
"work with a Source and Sink" in {
|
2014-10-10 10:39:29 +02:00
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
|
|
|
|
|
val flow = Flow(partialGraph) { implicit b ⇒
|
2015-01-28 14:19:50 +01:00
|
|
|
partial ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
|
|
|
|
|
(partial.inlet, partial.outlet.map(_.toInt).outlet)
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-31 10:43:42 +02:00
|
|
|
source1.via(flow).to(Sink(probe)).run()
|
2014-10-10 10:39:29 +02:00
|
|
|
|
|
|
|
|
validateProbe(probe, stdRequests, stdResult)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"be transformable with a Pipe" in {
|
|
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val flow = Flow(partialGraph) { implicit b ⇒
|
|
|
|
|
partial ⇒
|
|
|
|
|
(partial.inlet, partial.outlet)
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-31 10:43:42 +02:00
|
|
|
source1.via(flow).map(_.toInt).to(Sink(probe)).run()
|
2014-10-10 10:39:29 +02:00
|
|
|
|
|
|
|
|
validateProbe(probe, stdRequests, stdResult)
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
"work with another GraphFlow" in {
|
2014-10-10 10:39:29 +02:00
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
|
|
|
|
|
val flow1 = Flow(partialGraph) { implicit b ⇒
|
2015-01-28 14:19:50 +01:00
|
|
|
partial ⇒
|
|
|
|
|
(partial.inlet, partial.outlet)
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val flow2 = Flow(Flow[String].map(_.toInt)) { implicit b ⇒
|
|
|
|
|
importFlow ⇒
|
|
|
|
|
(importFlow.inlet, importFlow.outlet)
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-31 10:43:42 +02:00
|
|
|
source1.via(flow1).via(flow2).to(Sink(probe)).run()
|
2014-10-10 10:39:29 +02:00
|
|
|
|
|
|
|
|
validateProbe(probe, stdRequests, stdResult)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"be reusable multiple times" in {
|
|
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val flow = Flow(Flow[Int].map(_ * 2)) { implicit b ⇒
|
|
|
|
|
importFlow ⇒
|
|
|
|
|
(importFlow.inlet, importFlow.outlet)
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
2014-10-10 10:39:29 +02:00
|
|
|
Source(1 to 5) ~> flow ~> flow ~> Sink(probe)
|
|
|
|
|
}.run()
|
|
|
|
|
|
|
|
|
|
validateProbe(probe, 5, Set(4, 8, 12, 16, 20))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"turned into sources" should {
|
2014-10-17 14:05:50 +02:00
|
|
|
"work with a Sink" in {
|
2014-10-10 10:39:29 +02:00
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
|
|
|
|
|
val source = Source(partialGraph) { implicit b ⇒
|
2015-01-28 14:19:50 +01:00
|
|
|
partial ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
source1 ~> partial.inlet
|
|
|
|
|
partial.outlet.map(_.toInt).outlet
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-31 10:43:42 +02:00
|
|
|
source.to(Sink(probe)).run()
|
2014-10-10 10:39:29 +02:00
|
|
|
|
|
|
|
|
validateProbe(probe, stdRequests, stdResult)
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-06 10:08:38 +02:00
|
|
|
"work with a Sink when having KeyedSource inside" in {
|
|
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val source = Source.apply(Source.subscriber[Int]()) { implicit b ⇒
|
|
|
|
|
subSource ⇒
|
|
|
|
|
subSource.outlet
|
2014-11-06 10:08:38 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val mm: Subscriber[Int] = source.to(Sink(probe)).run()
|
|
|
|
|
source1.to(Sink(mm)).run()
|
2014-11-06 10:08:38 +02:00
|
|
|
|
|
|
|
|
validateProbe(probe, 4, (0 to 3).toSet)
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-10 10:39:29 +02:00
|
|
|
"be transformable with a Pipe" in {
|
|
|
|
|
|
|
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val source = Source(partialGraph) { implicit b ⇒
|
|
|
|
|
partial ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
source1 ~> partial.inlet
|
|
|
|
|
partial.outlet
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-31 10:43:42 +02:00
|
|
|
source.map(_.toInt).to(Sink(probe)).run()
|
2014-10-10 10:39:29 +02:00
|
|
|
|
|
|
|
|
validateProbe(probe, stdRequests, stdResult)
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
"work with an GraphFlow" in {
|
2014-10-10 10:39:29 +02:00
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
|
|
|
|
|
val source = Source(partialGraph) { implicit b ⇒
|
2015-01-28 14:19:50 +01:00
|
|
|
partial ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
source1 ~> partial.inlet
|
|
|
|
|
partial.outlet
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val flow = Flow(Flow[String].map(_.toInt)) { implicit b ⇒
|
|
|
|
|
importFlow ⇒
|
|
|
|
|
(importFlow.inlet, importFlow.outlet)
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-31 10:43:42 +02:00
|
|
|
source.via(flow).to(Sink(probe)).run()
|
2014-10-10 10:39:29 +02:00
|
|
|
|
|
|
|
|
validateProbe(probe, stdRequests, stdResult)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"be reusable multiple times" in {
|
|
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val source = Source(Source(1 to 5)) { implicit b ⇒
|
|
|
|
|
s ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
s.outlet.map(_ * 2).outlet
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed(source, source)(Keep.both) { implicit b ⇒
|
|
|
|
|
(s1, s2) ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
val merge = b.add(Merge[Int](2))
|
|
|
|
|
s1.outlet ~> merge.in(0)
|
|
|
|
|
merge.out ~> Sink(probe)
|
|
|
|
|
s2.outlet.map(_ * 10) ~> merge.in(1)
|
2014-10-10 10:39:29 +02:00
|
|
|
}.run()
|
|
|
|
|
|
|
|
|
|
validateProbe(probe, 10, Set(2, 4, 6, 8, 10, 20, 40, 60, 80, 100))
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-11-06 12:38:04 +02:00
|
|
|
|
2014-10-10 10:39:29 +02:00
|
|
|
"turned into sinks" should {
|
2014-10-17 14:05:50 +02:00
|
|
|
"work with a Source" in {
|
2014-10-10 10:39:29 +02:00
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
|
|
|
|
|
val sink = Sink(partialGraph) { implicit b ⇒
|
2015-01-28 14:19:50 +01:00
|
|
|
partial ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
partial.outlet.map(_.toInt) ~> Sink(probe)
|
|
|
|
|
partial.inlet
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-31 10:43:42 +02:00
|
|
|
source1.to(sink).run()
|
2014-10-10 10:39:29 +02:00
|
|
|
|
|
|
|
|
validateProbe(probe, stdRequests, stdResult)
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-06 10:08:38 +02:00
|
|
|
"work with a Source when having KeyedSink inside" in {
|
|
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
val pubSink = Sink.publisher[Int]
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val sink = Sink(pubSink) { implicit b ⇒
|
|
|
|
|
p ⇒
|
|
|
|
|
p.inlet
|
2014-11-06 10:08:38 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val mm = source1.runWith(sink)
|
|
|
|
|
Source(mm).to(Sink(probe)).run()
|
2014-11-06 10:08:38 +02:00
|
|
|
|
|
|
|
|
validateProbe(probe, 4, (0 to 3).toSet)
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-10 10:39:29 +02:00
|
|
|
"be transformable with a Pipe" in {
|
|
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val sink = Sink(partialGraph, Flow[String].map(_.toInt))(Keep.both) { implicit b ⇒
|
|
|
|
|
(partial, flow) ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
flow.outlet ~> partial.inlet
|
|
|
|
|
partial.outlet.map(_.toInt) ~> Sink(probe)
|
|
|
|
|
flow.inlet
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-31 10:43:42 +02:00
|
|
|
val iSink = Flow[Int].map(_.toString).to(sink)
|
|
|
|
|
source1.to(iSink).run()
|
2014-10-10 10:39:29 +02:00
|
|
|
|
|
|
|
|
validateProbe(probe, stdRequests, stdResult)
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
"work with a GraphFlow" in {
|
2014-10-10 10:39:29 +02:00
|
|
|
|
|
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
|
|
|
|
|
val flow = Flow(partialGraph) { implicit b ⇒
|
2015-01-28 14:19:50 +01:00
|
|
|
partial ⇒
|
|
|
|
|
(partial.inlet, partial.outlet)
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val sink = Sink(Flow[String].map(_.toInt)) { implicit b ⇒
|
|
|
|
|
flow ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
flow.outlet ~> Sink(probe)
|
|
|
|
|
flow.inlet
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-31 10:43:42 +02:00
|
|
|
source1.via(flow).to(sink).run()
|
2014-10-10 10:39:29 +02:00
|
|
|
|
|
|
|
|
validateProbe(probe, stdRequests, stdResult)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"used together" should {
|
|
|
|
|
"materialize properly" in {
|
|
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
2014-10-17 14:05:50 +02:00
|
|
|
val inSource = Source.subscriber[Int]
|
|
|
|
|
val outSink = Sink.publisher[Int]
|
2014-10-10 10:39:29 +02:00
|
|
|
|
|
|
|
|
val flow = Flow(partialGraph) { implicit b ⇒
|
2015-01-28 14:19:50 +01:00
|
|
|
partial ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
(partial.inlet, partial.outlet.map(_.toInt).outlet)
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val source = Source(Flow[Int].map(_.toString), inSource)(Keep.right) { implicit b ⇒
|
|
|
|
|
(flow, src) ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
src.outlet ~> flow.inlet
|
|
|
|
|
flow.outlet
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val sink = Sink(Flow[String].map(_.toInt), outSink)(Keep.right) { implicit b ⇒
|
|
|
|
|
(flow, snk) ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
flow.outlet ~> snk.inlet
|
|
|
|
|
flow.inlet
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val (m1, m2, m3) = FlowGraph.closed(source, flow, sink)(Tuple3.apply) { implicit b ⇒
|
|
|
|
|
(src, f, snk) ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
src.outlet.map(_.toInt) ~> f.inlet
|
|
|
|
|
f.outlet.map(_.toString) ~> snk.inlet
|
2014-10-10 10:39:29 +02:00
|
|
|
}.run()
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val subscriber = m1
|
|
|
|
|
val publisher = m3
|
|
|
|
|
source1.runWith(Sink.publisher()).subscribe(subscriber)
|
2014-10-10 10:39:29 +02:00
|
|
|
publisher.subscribe(probe)
|
|
|
|
|
|
|
|
|
|
validateProbe(probe, stdRequests, stdResult)
|
|
|
|
|
}
|
2014-11-06 12:38:04 +02:00
|
|
|
|
|
|
|
|
"allow connecting source to sink directly" in {
|
|
|
|
|
val probe = StreamTestKit.SubscriberProbe[Int]()
|
|
|
|
|
val inSource = Source.subscriber[Int]
|
|
|
|
|
val outSink = Sink.publisher[Int]
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val source = Source(inSource) { implicit b ⇒
|
|
|
|
|
src ⇒
|
|
|
|
|
src.outlet
|
2014-11-06 12:38:04 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val sink = Sink(outSink) { implicit b ⇒
|
|
|
|
|
snk ⇒
|
|
|
|
|
snk.inlet
|
2014-11-06 12:38:04 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val (m1, m2) = FlowGraph.closed(source, sink)(Keep.both) { implicit b ⇒
|
|
|
|
|
(src, snk) ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
src.outlet ~> snk.inlet
|
2014-11-06 12:38:04 +02:00
|
|
|
}.run()
|
|
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
val subscriber = m1
|
|
|
|
|
val publisher = m2
|
2014-11-06 12:38:04 +02:00
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
source1.runWith(Sink.publisher()).subscribe(subscriber)
|
2014-11-06 12:38:04 +02:00
|
|
|
publisher.subscribe(probe)
|
|
|
|
|
|
|
|
|
|
validateProbe(probe, 4, (0 to 3).toSet)
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-10 10:39:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|