!str #18692 javadsl.FlowGraph.Builder.add()
* also make factories more consistent by only offering FlowGraph.create() * also remove secondary (edge-based) FlowGraph.Builder DSL * also improve naming for conversions from Graph to Source/Flow/BidiFlow/Sink
This commit is contained in:
parent
0f99a42df9
commit
f29d7affbd
120 changed files with 1535 additions and 1897 deletions
|
|
@ -4,8 +4,7 @@
|
|||
package akka.stream.scaladsl
|
||||
|
||||
import akka.stream.Attributes._
|
||||
import akka.stream.ActorMaterializer
|
||||
import akka.stream.OverflowStrategy
|
||||
import akka.stream.{ ClosedShape, ActorMaterializer, OverflowStrategy }
|
||||
import akka.stream.testkit._
|
||||
import akka.stream.stage._
|
||||
|
||||
|
|
@ -41,47 +40,52 @@ class FlowGraphCompileSpec extends AkkaSpec {
|
|||
val out2 = Sink.head[String]
|
||||
|
||||
"A Graph" should {
|
||||
import FlowGraph.Implicits._
|
||||
"build simple merge" in {
|
||||
FlowGraph.closed() { b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
val merge = b.add(Merge[String](2))
|
||||
b.addEdge(b.add(in1), f1, merge.in(0))
|
||||
b.addEdge(b.add(in2), f2, merge.in(1))
|
||||
b.addEdge(merge.out, f3, b.add(out1))
|
||||
}.run()
|
||||
in1 ~> f1 ~> merge.in(0)
|
||||
in2 ~> f2 ~> merge.in(1)
|
||||
merge.out ~> f3 ~> out1
|
||||
ClosedShape
|
||||
}).run()
|
||||
}
|
||||
|
||||
"build simple broadcast" in {
|
||||
FlowGraph.closed() { b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
val bcast = b.add(Broadcast[String](2))
|
||||
b.addEdge(b.add(in1), f1, bcast.in)
|
||||
b.addEdge(bcast.out(0), f2, b.add(out1))
|
||||
b.addEdge(bcast.out(1), f3, b.add(out2))
|
||||
}.run()
|
||||
in1 ~> f1 ~> bcast.in
|
||||
bcast.out(0) ~> f2 ~> out1
|
||||
bcast.out(1) ~> f3 ~> out2
|
||||
ClosedShape
|
||||
}).run()
|
||||
}
|
||||
|
||||
"build simple balance" in {
|
||||
FlowGraph.closed() { b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
val balance = b.add(Balance[String](2))
|
||||
b.addEdge(b.add(in1), f1, balance.in)
|
||||
b.addEdge(balance.out(0), f2, b.add(out1))
|
||||
b.addEdge(balance.out(1), f3, b.add(out2))
|
||||
}
|
||||
in1 ~> f1 ~> balance.in
|
||||
balance.out(0) ~> f2 ~> out1
|
||||
balance.out(1) ~> f3 ~> out2
|
||||
ClosedShape
|
||||
})
|
||||
}
|
||||
|
||||
"build simple merge - broadcast" in {
|
||||
FlowGraph.closed() { b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
val merge = b.add(Merge[String](2))
|
||||
val bcast = b.add(Broadcast[String](2))
|
||||
b.addEdge(b.add(in1), f1, merge.in(0))
|
||||
b.addEdge(b.add(in2), f2, merge.in(1))
|
||||
b.addEdge(merge.out, f3, bcast.in)
|
||||
b.addEdge(bcast.out(0), f4, b.add(out1))
|
||||
b.addEdge(bcast.out(1), f5, b.add(out2))
|
||||
}.run()
|
||||
in1 ~> f1 ~> merge.in(0)
|
||||
in2 ~> f2 ~> merge.in(1)
|
||||
merge ~> f3 ~> bcast
|
||||
bcast.out(0) ~> f4 ~> out1
|
||||
bcast.out(1) ~> f5 ~> out2
|
||||
ClosedShape
|
||||
}).run()
|
||||
}
|
||||
|
||||
"build simple merge - broadcast with implicits" in {
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
import FlowGraph.Implicits._
|
||||
val merge = b.add(Merge[String](2))
|
||||
val bcast = b.add(Broadcast[String](2))
|
||||
|
|
@ -90,7 +94,8 @@ class FlowGraphCompileSpec extends AkkaSpec {
|
|||
bcast.out(0) ~> f3 ~> b.add(out1)
|
||||
b.add(in2) ~> f4 ~> merge.in(1)
|
||||
bcast.out(1) ~> f5 ~> b.add(out2)
|
||||
}.run()
|
||||
ClosedShape
|
||||
}).run()
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -105,24 +110,25 @@ class FlowGraphCompileSpec extends AkkaSpec {
|
|||
"detect cycle in " in {
|
||||
pending // FIXME needs cycle detection capability
|
||||
intercept[IllegalArgumentException] {
|
||||
FlowGraph.closed() { b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
val merge = b.add(Merge[String](2))
|
||||
val bcast1 = b.add(Broadcast[String](2))
|
||||
val bcast2 = b.add(Broadcast[String](2))
|
||||
val feedbackLoopBuffer = Flow[String].buffer(10, OverflowStrategy.dropBuffer)
|
||||
b.addEdge(b.add(in1), f1, merge.in(0))
|
||||
b.addEdge(merge.out, f2, bcast1.in)
|
||||
b.addEdge(bcast1.out(0), f3, b.add(out1))
|
||||
b.addEdge(bcast1.out(1), feedbackLoopBuffer, bcast2.in)
|
||||
b.addEdge(bcast2.out(0), f5, merge.in(1)) // cycle
|
||||
b.addEdge(bcast2.out(1), f6, b.add(out2))
|
||||
}
|
||||
in1 ~> f1 ~> merge.in(0)
|
||||
merge ~> f2 ~> bcast1
|
||||
bcast1.out(0) ~> f3 ~> out1
|
||||
bcast1.out(1) ~> feedbackLoopBuffer ~> bcast2
|
||||
bcast2.out(0) ~> f5 ~> merge.in(1) // cycle
|
||||
bcast2.out(1) ~> f6 ~> out2
|
||||
ClosedShape
|
||||
})
|
||||
}.getMessage.toLowerCase should include("cycle")
|
||||
|
||||
}
|
||||
|
||||
"express complex topologies in a readable way" in {
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
val merge = b.add(Merge[String](2))
|
||||
val bcast1 = b.add(Broadcast[String](2))
|
||||
val bcast2 = b.add(Broadcast[String](2))
|
||||
|
|
@ -131,22 +137,24 @@ class FlowGraphCompileSpec extends AkkaSpec {
|
|||
b.add(in1) ~> f1 ~> merge ~> f2 ~> bcast1 ~> f3 ~> b.add(out1)
|
||||
bcast1 ~> feedbackLoopBuffer ~> bcast2 ~> f5 ~> merge
|
||||
bcast2 ~> f6 ~> b.add(out2)
|
||||
}.run()
|
||||
ClosedShape
|
||||
}).run()
|
||||
}
|
||||
|
||||
"build broadcast - merge" in {
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
val bcast = b.add(Broadcast[String](2))
|
||||
val merge = b.add(Merge[String](2))
|
||||
import FlowGraph.Implicits._
|
||||
in1 ~> f1 ~> bcast ~> f2 ~> merge ~> f3 ~> out1
|
||||
bcast ~> f4 ~> merge
|
||||
}.run()
|
||||
ClosedShape
|
||||
}).run()
|
||||
}
|
||||
|
||||
"build wikipedia Topological_sorting" in {
|
||||
// see https://en.wikipedia.org/wiki/Topological_sorting#mediaviewer/File:Directed_acyclic_graph.png
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
val b3 = b.add(Broadcast[String](2))
|
||||
val b7 = b.add(Broadcast[String](2))
|
||||
val b11 = b.add(Broadcast[String](3))
|
||||
|
|
@ -170,22 +178,24 @@ class FlowGraphCompileSpec extends AkkaSpec {
|
|||
in5 ~> f("k") ~> m11
|
||||
in3 ~> f("l") ~> b3 ~> f("m") ~> m8
|
||||
b3 ~> f("n") ~> m10
|
||||
}.run()
|
||||
ClosedShape
|
||||
}).run()
|
||||
}
|
||||
|
||||
"make it optional to specify flows" in {
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
val merge = b.add(Merge[String](2))
|
||||
val bcast = b.add(Broadcast[String](2))
|
||||
import FlowGraph.Implicits._
|
||||
in1 ~> merge ~> bcast ~> out1
|
||||
in2 ~> merge
|
||||
bcast ~> out2
|
||||
}.run()
|
||||
ClosedShape
|
||||
}).run()
|
||||
}
|
||||
|
||||
"build unzip - zip" in {
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
val zip = b.add(Zip[Int, String]())
|
||||
val unzip = b.add(Unzip[Int, String]())
|
||||
val out = Sink.publisher[(Int, String)]
|
||||
|
|
@ -194,12 +204,13 @@ class FlowGraphCompileSpec extends AkkaSpec {
|
|||
unzip.out0 ~> Flow[Int].map(_ * 2) ~> zip.in0
|
||||
unzip.out1 ~> zip.in1
|
||||
zip.out ~> out
|
||||
}.run()
|
||||
ClosedShape
|
||||
}).run()
|
||||
}
|
||||
|
||||
"distinguish between input and output ports" in {
|
||||
intercept[IllegalArgumentException] {
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
val zip = b.add(Zip[Int, String]())
|
||||
val unzip = b.add(Unzip[Int, String]())
|
||||
val wrongOut = Sink.publisher[(Int, Int)]
|
||||
|
|
@ -210,22 +221,24 @@ class FlowGraphCompileSpec extends AkkaSpec {
|
|||
"zip.left ~> zip.right" shouldNot compile
|
||||
"Flow(List(1, 2, 3)) ~> zip.left ~> wrongOut" shouldNot compile
|
||||
"""Flow(List(1 -> "a", 2 -> "b", 3 -> "c")) ~> unzip.in ~> whatever""" shouldNot compile
|
||||
}
|
||||
}.getMessage should include("unconnected")
|
||||
ClosedShape
|
||||
})
|
||||
}.getMessage should include("must correspond to")
|
||||
}
|
||||
|
||||
"build with variance" in {
|
||||
val out = Sink(TestSubscriber.manualProbe[Fruit]())
|
||||
FlowGraph.closed() { b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
import FlowGraph.Implicits._
|
||||
val merge = b.add(Merge[Fruit](2))
|
||||
b.addEdge(b add Source[Fruit](apples), Flow[Fruit], merge.in(0))
|
||||
b.addEdge(b add Source[Apple](apples), Flow[Apple], merge.in(1))
|
||||
b.addEdge(merge.out, Flow[Fruit].map(identity), b add out)
|
||||
}
|
||||
Source[Fruit](apples) ~> Flow[Fruit] ~> merge.in(0)
|
||||
Source[Apple](apples) ~> Flow[Apple] ~> merge.in(1)
|
||||
merge.out ~> Flow[Fruit].map(identity) ~> Sink(TestSubscriber.manualProbe[Fruit]())
|
||||
ClosedShape
|
||||
})
|
||||
}
|
||||
|
||||
"build with variance when indices are not specified" in {
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
import FlowGraph.Implicits._
|
||||
val fruitMerge = b.add(Merge[Fruit](2))
|
||||
Source[Fruit](apples) ~> fruitMerge
|
||||
|
|
@ -253,11 +266,12 @@ class FlowGraphCompileSpec extends AkkaSpec {
|
|||
Source[Apple](apples) ~> appleBcast
|
||||
appleBcast ~> Sink.head[Fruit]
|
||||
appleBcast ~> Sink.head[Apple]
|
||||
}
|
||||
ClosedShape
|
||||
})
|
||||
}
|
||||
|
||||
"build with implicits and variance" in {
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
def appleSource = b.add(Source(TestPublisher.manualProbe[Apple]()))
|
||||
def fruitSource = b.add(Source(TestPublisher.manualProbe[Fruit]()))
|
||||
val outA = b add Sink(TestSubscriber.manualProbe[Fruit]())
|
||||
|
|
@ -289,40 +303,40 @@ class FlowGraphCompileSpec extends AkkaSpec {
|
|||
"merge.out ~> b.add(Broadcast[Apple](2))" shouldNot compile
|
||||
"merge.out ~> Flow[Fruit].map(identity) ~> b.add(Broadcast[Apple](2))" shouldNot compile
|
||||
"fruitSource ~> merge ~> b.add(Broadcast[Apple](2))" shouldNot compile
|
||||
}
|
||||
ClosedShape
|
||||
})
|
||||
}
|
||||
|
||||
"build with plain flow without junctions" in {
|
||||
FlowGraph.closed() { b ⇒
|
||||
b.addEdge(b.add(in1), f1, b.add(out1))
|
||||
}.run()
|
||||
FlowGraph.closed() { b ⇒
|
||||
b.addEdge(b.add(in1), f1, b.add(f2.to(out1)))
|
||||
}.run()
|
||||
FlowGraph.closed() { b ⇒
|
||||
b.addEdge(b.add(in1 via f1), f2, b.add(out1))
|
||||
}.run()
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
import FlowGraph.Implicits._
|
||||
b.add(in1) ~> f1 ~> b.add(out1)
|
||||
}.run()
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
import FlowGraph.Implicits._
|
||||
b.add(in1) ~> b.add(out1)
|
||||
}.run()
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
import FlowGraph.Implicits._
|
||||
b.add(in1) ~> b.add(f1 to out1)
|
||||
}.run()
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
import FlowGraph.Implicits._
|
||||
b.add(in1 via f1) ~> b.add(out1)
|
||||
}.run()
|
||||
FlowGraph.closed() { implicit b ⇒
|
||||
import FlowGraph.Implicits._
|
||||
b.add(in1 via f1) ~> b.add(f2 to out1)
|
||||
}.run()
|
||||
import FlowGraph.Implicits._
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
in1 ~> f1 ~> out1
|
||||
ClosedShape
|
||||
}).run()
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
in1 ~> f1 ~> f2.to(out1)
|
||||
ClosedShape
|
||||
}).run()
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
(in1 via f1) ~> f2 ~> out1
|
||||
ClosedShape
|
||||
}).run()
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
in1 ~> out1
|
||||
ClosedShape
|
||||
}).run()
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
in1 ~> (f1 to out1)
|
||||
ClosedShape
|
||||
}).run()
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
(in1 via f1) ~> out1
|
||||
ClosedShape
|
||||
}).run()
|
||||
RunnableGraph.fromGraph(FlowGraph.create() { implicit b ⇒
|
||||
(in1 via f1) ~> (f2 to out1)
|
||||
ClosedShape
|
||||
}).run()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue