2014-10-08 18:16:57 +02:00
|
|
|
/**
|
2017-01-04 17:37:10 +01:00
|
|
|
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
2014-10-08 18:16:57 +02:00
|
|
|
*/
|
|
|
|
|
package akka.stream.impl.fusing
|
|
|
|
|
|
2016-01-21 16:52:44 +01:00
|
|
|
import akka.stream.impl.ConstantFun
|
2015-05-08 12:47:49 +02:00
|
|
|
import akka.stream.stage._
|
2016-07-28 16:43:08 +08:00
|
|
|
import akka.stream.testkit.StreamSpec
|
2015-09-02 16:46:37 +02:00
|
|
|
import akka.testkit.EventFilter
|
2016-04-14 00:37:15 +08:00
|
|
|
import akka.stream._
|
2016-07-20 13:26:27 +02:00
|
|
|
import akka.stream.impl.fusing.GraphStages.SimpleLinearGraphStage
|
2014-10-08 18:16:57 +02:00
|
|
|
|
2016-07-28 16:43:08 +08:00
|
|
|
class InterpreterSpec extends StreamSpec with GraphInterpreterSpecKit {
|
2015-02-04 09:26:32 +01:00
|
|
|
import Supervision.stoppingDecider
|
2014-10-08 18:16:57 +02:00
|
|
|
|
2015-10-31 14:46:10 +01:00
|
|
|
/*
|
2016-02-28 23:14:29 +02:00
|
|
|
* These tests were written for the previous version of the interpreter, the so called OneBoundedInterpreter.
|
2015-10-31 14:46:10 +01:00
|
|
|
* These stages are now properly emulated by the GraphInterpreter and many of the edge cases were relevant to
|
|
|
|
|
* the execution model of the old one. Still, these tests are very valuable, so please do not remove.
|
|
|
|
|
*/
|
|
|
|
|
|
2016-02-28 23:14:29 +02:00
|
|
|
val takeOne = Take(1)
|
|
|
|
|
val takeTwo = Take(2)
|
|
|
|
|
|
2014-10-08 18:16:57 +02:00
|
|
|
"Interpreter" must {
|
|
|
|
|
|
2016-07-20 13:26:27 +02:00
|
|
|
"implement map correctly" in new OneBoundedSetup[Int](Map((x: Int) ⇒ x + 1)) {
|
2014-10-08 18:16:57 +02:00
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(OnNext(1)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(OnNext(2)))
|
|
|
|
|
|
|
|
|
|
upstream.onComplete()
|
|
|
|
|
lastEvents() should be(Set(OnComplete))
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-20 13:26:27 +02:00
|
|
|
"implement chain of maps correctly" in new OneBoundedSetup[Int](
|
|
|
|
|
Map((x: Int) ⇒ x + 1),
|
|
|
|
|
Map((x: Int) ⇒ x * 2),
|
|
|
|
|
Map((x: Int) ⇒ x + 1)) {
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(OnNext(3)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(OnNext(5)))
|
|
|
|
|
|
|
|
|
|
downstream.cancel()
|
|
|
|
|
lastEvents() should be(Set(Cancel))
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-20 13:26:27 +02:00
|
|
|
"work with only boundary ops" in new OneBoundedSetup[Int]() {
|
2014-10-08 18:16:57 +02:00
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(OnNext(0)))
|
|
|
|
|
|
|
|
|
|
upstream.onComplete()
|
|
|
|
|
lastEvents() should be(Set(OnComplete))
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-14 11:04:08 +02:00
|
|
|
"implement one-to-many many-to-one chain correctly" in new OneBoundedSetup[Int](
|
2016-04-14 00:37:15 +08:00
|
|
|
Doubler(),
|
2016-04-14 11:04:08 +02:00
|
|
|
Filter((x: Int) ⇒ x != 0)) {
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(OnNext(1)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(1)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onComplete()
|
|
|
|
|
lastEvents() should be(Set(OnComplete))
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-14 11:04:08 +02:00
|
|
|
"implement many-to-one one-to-many chain correctly" in new OneBoundedSetup[Int](
|
|
|
|
|
Filter((x: Int) ⇒ x != 0),
|
2016-04-14 00:37:15 +08:00
|
|
|
Doubler()) {
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(OnNext(1)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(1)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
downstream.cancel()
|
|
|
|
|
lastEvents() should be(Set(Cancel))
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-28 23:14:29 +02:00
|
|
|
"implement take" in new OneBoundedSetup[Int](takeTwo) {
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(OnNext(0)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(OnNext(1), Cancel, OnComplete))
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-28 23:14:29 +02:00
|
|
|
"implement take inside a chain" in new OneBoundedSetup[Int](
|
2016-04-14 11:04:08 +02:00
|
|
|
Filter((x: Int) ⇒ x != 0),
|
2016-02-28 23:14:29 +02:00
|
|
|
takeTwo,
|
2016-07-20 13:26:27 +02:00
|
|
|
Map((x: Int) ⇒ x + 1)) {
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(OnNext(2)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(2)
|
|
|
|
|
lastEvents() should be(Set(Cancel, OnComplete, OnNext(3)))
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-08 14:22:18 +02:00
|
|
|
"implement fold" in new OneBoundedSetup[Int](Fold(0, (agg: Int, x: Int) ⇒ agg + x)) {
|
2014-10-08 18:16:57 +02:00
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(2)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onComplete()
|
|
|
|
|
lastEvents() should be(Set(OnNext(3), OnComplete))
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-08 14:22:18 +02:00
|
|
|
"implement fold with proper cancel" in new OneBoundedSetup[Int](Fold(0, (agg: Int, x: Int) ⇒ agg + x)) {
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(2)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
downstream.cancel()
|
|
|
|
|
lastEvents() should be(Set(Cancel))
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-08 14:22:18 +02:00
|
|
|
"work if fold completes while not in a push position" in new OneBoundedSetup[Int](Fold(0, (agg: Int, x: Int) ⇒ agg + x)) {
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
upstream.onComplete()
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnComplete, OnNext(0)))
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-08 14:22:18 +02:00
|
|
|
"implement grouped" in new OneBoundedSetup[Int](Grouped(3)) {
|
2014-10-08 18:16:57 +02:00
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(2)
|
|
|
|
|
lastEvents() should be(Set(OnNext(Vector(0, 1, 2))))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(3)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onComplete()
|
|
|
|
|
lastEvents() should be(Set(OnNext(Vector(3)), OnComplete))
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-21 16:52:44 +01:00
|
|
|
"implement batch (conflate)" in new OneBoundedSetup[Int](Batch(
|
|
|
|
|
1L,
|
|
|
|
|
ConstantFun.zeroLong,
|
2014-10-08 18:16:57 +02:00
|
|
|
(in: Int) ⇒ in,
|
2016-01-21 16:52:44 +01:00
|
|
|
(agg: Int, x: Int) ⇒ agg + x)) {
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(OnNext(0), RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(2)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(3)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
upstream.onNext(4)
|
|
|
|
|
lastEvents() should be(Set(OnNext(4), RequestOne))
|
|
|
|
|
|
|
|
|
|
downstream.cancel()
|
|
|
|
|
lastEvents() should be(Set(Cancel))
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-18 11:29:14 +01:00
|
|
|
"implement expand" in new OneBoundedSetup[Int](new Expand(Iterator.continually(_: Int))) {
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne, OnNext(0)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(0)))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne, OnNext(1)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(1)))
|
|
|
|
|
|
|
|
|
|
upstream.onComplete()
|
|
|
|
|
lastEvents() should be(Set(OnComplete))
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-21 16:52:44 +01:00
|
|
|
"work with batch-batch (conflate-conflate)" in new OneBoundedSetup[Int](
|
|
|
|
|
Batch(
|
|
|
|
|
1L,
|
|
|
|
|
ConstantFun.zeroLong,
|
2014-10-08 18:16:57 +02:00
|
|
|
(in: Int) ⇒ in,
|
2016-01-21 16:52:44 +01:00
|
|
|
(agg: Int, x: Int) ⇒ agg + x),
|
|
|
|
|
Batch(
|
|
|
|
|
1L,
|
|
|
|
|
ConstantFun.zeroLong,
|
2014-10-08 18:16:57 +02:00
|
|
|
(in: Int) ⇒ in,
|
2016-01-21 16:52:44 +01:00
|
|
|
(agg: Int, x: Int) ⇒ agg + x)) {
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(OnNext(0), RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(2)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(3)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
upstream.onNext(4)
|
|
|
|
|
lastEvents() should be(Set(OnNext(4), RequestOne))
|
|
|
|
|
|
|
|
|
|
downstream.cancel()
|
|
|
|
|
lastEvents() should be(Set(Cancel))
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-18 11:29:14 +01:00
|
|
|
"work with expand-expand" in new OneBoundedSetup[Int](
|
|
|
|
|
new Expand(Iterator.from),
|
|
|
|
|
new Expand(Iterator.from)) {
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(0)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
2014-11-25 12:26:24 +01:00
|
|
|
lastEvents() should be(Set(OnNext(1)))
|
2014-10-08 18:16:57 +02:00
|
|
|
|
2014-11-25 12:26:24 +01:00
|
|
|
upstream.onNext(10)
|
2014-10-08 18:16:57 +02:00
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
2014-11-25 12:26:24 +01:00
|
|
|
lastEvents() should be(Set(RequestOne, OnNext(2))) // One element is still in the pipeline
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
downstream.requestOne()
|
2014-11-25 12:26:24 +01:00
|
|
|
lastEvents() should be(Set(OnNext(10)))
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
downstream.requestOne()
|
2014-11-25 12:26:24 +01:00
|
|
|
lastEvents() should be(Set(OnNext(11)))
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
upstream.onComplete()
|
2014-11-25 12:26:24 +01:00
|
|
|
downstream.requestOne()
|
|
|
|
|
// This is correct! If you don't believe, run the interpreter with Debug on
|
|
|
|
|
lastEvents() should be(Set(OnComplete, OnNext(12)))
|
2014-10-08 18:16:57 +02:00
|
|
|
}
|
|
|
|
|
|
2016-01-21 16:52:44 +01:00
|
|
|
"implement batch-expand (conflate-expand)" in new OneBoundedSetup[Int](
|
|
|
|
|
Batch(
|
|
|
|
|
1L,
|
|
|
|
|
ConstantFun.zeroLong,
|
2014-10-08 18:16:57 +02:00
|
|
|
(in: Int) ⇒ in,
|
2016-01-21 16:52:44 +01:00
|
|
|
(agg: Int, x: Int) ⇒ agg + x),
|
2016-01-18 11:29:14 +01:00
|
|
|
new Expand(Iterator.continually(_: Int))) {
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(0)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(0)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(1)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(1)))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(2)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(2)))
|
|
|
|
|
|
|
|
|
|
downstream.cancel()
|
|
|
|
|
lastEvents() should be(Set(Cancel))
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-21 16:52:44 +01:00
|
|
|
"implement doubler-conflate (doubler-batch)" in new OneBoundedSetup[Int](
|
2016-04-14 00:37:15 +08:00
|
|
|
Doubler(),
|
2016-01-21 16:52:44 +01:00
|
|
|
Batch(
|
|
|
|
|
1L,
|
|
|
|
|
ConstantFun.zeroLong,
|
2014-10-08 18:16:57 +02:00
|
|
|
(in: Int) ⇒ in,
|
2016-01-21 16:52:44 +01:00
|
|
|
(agg: Int, x: Int) ⇒ agg + x)) {
|
2014-10-08 18:16:57 +02:00
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(2)
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(6)))
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-31 14:46:10 +01:00
|
|
|
// Note, the new interpreter has no jumpback table, still did not want to remove the test
|
2016-04-14 00:37:15 +08:00
|
|
|
"work with jumpback table and completed elements" in new OneBoundedSetup[Int](
|
2016-07-20 13:26:27 +02:00
|
|
|
Map((x: Int) ⇒ x),
|
|
|
|
|
Map((x: Int) ⇒ x),
|
2015-01-26 10:31:57 +01:00
|
|
|
KeepGoing(),
|
2016-07-20 13:26:27 +02:00
|
|
|
Map((x: Int) ⇒ x),
|
|
|
|
|
Map((x: Int) ⇒ x)) {
|
2015-01-26 10:31:57 +01:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(OnNext(1)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
|
|
|
|
upstream.onNext(2)
|
|
|
|
|
lastEvents() should be(Set(OnNext(2)))
|
|
|
|
|
|
|
|
|
|
upstream.onComplete()
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(2)))
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(OnNext(2)))
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-20 13:26:27 +02:00
|
|
|
"work with pushAndFinish if upstream completes with pushAndFinish" in new OneBoundedSetup[Int](new PushFinishStage) {
|
2015-05-04 16:05:36 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
2015-10-31 14:46:10 +01:00
|
|
|
upstream.onNextAndComplete(0)
|
|
|
|
|
lastEvents() should be(Set(OnNext(0), OnComplete))
|
2015-05-04 16:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-20 13:26:27 +02:00
|
|
|
"work with pushAndFinish if indirect upstream completes with pushAndFinish" in new OneBoundedSetup[Int](
|
|
|
|
|
Map((x: Any) ⇒ x),
|
2015-05-04 16:05:36 +02:00
|
|
|
new PushFinishStage,
|
2016-07-20 13:26:27 +02:00
|
|
|
Map((x: Any) ⇒ x)) {
|
2015-05-04 16:05:36 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
2015-10-31 14:46:10 +01:00
|
|
|
upstream.onNextAndComplete(1)
|
|
|
|
|
lastEvents() should be(Set(OnNext(1), OnComplete))
|
2015-05-04 16:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-08 14:22:18 +02:00
|
|
|
"work with pushAndFinish if upstream completes with pushAndFinish and downstream immediately pulls" in new OneBoundedSetup[Int](
|
2016-07-20 13:26:27 +02:00
|
|
|
new PushFinishStage,
|
2016-07-08 14:22:18 +02:00
|
|
|
Fold(0, (x: Int, y: Int) ⇒ x + y)) {
|
2015-05-04 16:05:36 +02:00
|
|
|
|
|
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
2015-10-31 14:46:10 +01:00
|
|
|
upstream.onNextAndComplete(1)
|
|
|
|
|
lastEvents() should be(Set(OnNext(1), OnComplete))
|
2015-05-04 16:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-20 13:26:27 +02:00
|
|
|
"report error if pull is called while op is terminating" in new OneBoundedSetup[Int](
|
|
|
|
|
new SimpleLinearGraphStage[Any] {
|
|
|
|
|
override def createLogic(inheritedAttributes: Attributes): GraphStageLogic =
|
|
|
|
|
new GraphStageLogic(shape) with InHandler with OutHandler {
|
|
|
|
|
override def onPush(): Unit = pull(in)
|
|
|
|
|
override def onPull(): Unit = pull(in)
|
|
|
|
|
override def onUpstreamFinish(): Unit = if (!hasBeenPulled(in)) pull(in)
|
|
|
|
|
|
|
|
|
|
setHandlers(in, out, this)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
) {
|
2015-05-08 12:47:49 +02:00
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
2016-02-12 08:28:16 +01:00
|
|
|
EventFilter[IllegalArgumentException](pattern = ".*Cannot pull closed port.*", occurrences = 1).intercept {
|
|
|
|
|
upstream.onComplete()
|
|
|
|
|
}
|
2015-05-08 12:47:49 +02:00
|
|
|
val ev = lastEvents()
|
|
|
|
|
ev.nonEmpty should be(true)
|
|
|
|
|
ev.forall {
|
2015-10-31 14:46:10 +01:00
|
|
|
case OnError(_: IllegalArgumentException) ⇒ true
|
|
|
|
|
case _ ⇒ false
|
2015-05-08 12:47:49 +02:00
|
|
|
} should be(true)
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-28 23:14:29 +02:00
|
|
|
"implement take-take" in new OneBoundedSetup[Int](
|
|
|
|
|
takeOne,
|
|
|
|
|
takeOne) {
|
2015-05-04 16:05:36 +02:00
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
2015-10-31 14:46:10 +01:00
|
|
|
upstream.onNext(1)
|
|
|
|
|
lastEvents() should be(Set(OnNext(1), OnComplete, Cancel))
|
2015-05-04 16:05:36 +02:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-28 23:14:29 +02:00
|
|
|
"implement take-take with pushAndFinish from upstream" in new OneBoundedSetup[Int](
|
|
|
|
|
takeOne,
|
|
|
|
|
takeOne) {
|
2015-05-04 16:05:36 +02:00
|
|
|
lastEvents() should be(Set.empty)
|
|
|
|
|
|
|
|
|
|
downstream.requestOne()
|
|
|
|
|
lastEvents() should be(Set(RequestOne))
|
|
|
|
|
|
2015-10-31 14:46:10 +01:00
|
|
|
upstream.onNextAndComplete(1)
|
|
|
|
|
lastEvents() should be(Set(OnNext(1), OnComplete))
|
2015-09-02 16:46:37 +02:00
|
|
|
}
|
2014-10-08 18:16:57 +02:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-18 17:13:15 +08:00
|
|
|
private[akka] final case class Doubler[T]() extends SimpleLinearGraphStage[T] {
|
2016-04-14 00:37:15 +08:00
|
|
|
|
|
|
|
|
override def createLogic(inheritedAttributes: Attributes): GraphStageLogic =
|
|
|
|
|
new GraphStageLogic(shape) with InHandler with OutHandler {
|
|
|
|
|
var latest: T = _
|
|
|
|
|
var oneMore = false
|
|
|
|
|
|
|
|
|
|
override def onPush(): Unit = {
|
|
|
|
|
latest = grab(in)
|
|
|
|
|
oneMore = true
|
|
|
|
|
push(out, latest)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Called when the output port has received a pull, and therefore ready to emit an element, i.e. [[GraphStageLogic.push()]]
|
|
|
|
|
* is now allowed to be called on this port.
|
|
|
|
|
*/
|
|
|
|
|
override def onPull(): Unit = {
|
|
|
|
|
if (oneMore) {
|
|
|
|
|
push(out, latest)
|
|
|
|
|
oneMore = false
|
|
|
|
|
} else {
|
|
|
|
|
pull(in)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setHandlers(in, out, this)
|
|
|
|
|
}
|
2015-10-31 14:46:10 +01:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-18 17:13:15 +08:00
|
|
|
private[akka] final case class KeepGoing[T]() extends SimpleLinearGraphStage[T] {
|
2015-10-31 14:46:10 +01:00
|
|
|
|
2016-04-14 00:37:15 +08:00
|
|
|
override def createLogic(inheritedAttributes: Attributes): GraphStageLogic =
|
|
|
|
|
new GraphStageLogic(shape) with InHandler with OutHandler {
|
|
|
|
|
var lastElem: T = _
|
2015-10-31 14:46:10 +01:00
|
|
|
|
2016-04-14 00:37:15 +08:00
|
|
|
override def onPush(): Unit = {
|
|
|
|
|
lastElem = grab(in)
|
|
|
|
|
push(out, lastElem)
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-08 14:22:18 +02:00
|
|
|
// note that the default value of lastElem will be always pushed if the upstream closed at the very begining without a pulling
|
2016-04-14 00:37:15 +08:00
|
|
|
override def onPull(): Unit = {
|
|
|
|
|
if (isClosed(in)) {
|
|
|
|
|
push(out, lastElem)
|
|
|
|
|
} else {
|
|
|
|
|
pull(in)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override def onUpstreamFinish(): Unit = {}
|
|
|
|
|
|
|
|
|
|
setHandlers(in, out, this)
|
|
|
|
|
}
|
2015-10-31 14:46:10 +01:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-20 13:26:27 +02:00
|
|
|
private[akka] class PushFinishStage(onPostStop: () ⇒ Unit = () ⇒ ()) extends SimpleLinearGraphStage[Any] {
|
|
|
|
|
override def createLogic(inheritedAttributes: Attributes): GraphStageLogic =
|
|
|
|
|
new GraphStageLogic(shape) with InHandler with OutHandler {
|
|
|
|
|
override def onPush(): Unit = {
|
|
|
|
|
push(out, grab(in))
|
|
|
|
|
completeStage()
|
|
|
|
|
}
|
|
|
|
|
override def onPull(): Unit = pull(in)
|
|
|
|
|
override def onUpstreamFinish(): Unit = failStage(akka.stream.testkit.Utils.TE("Cannot happen"))
|
|
|
|
|
override def postStop(): Unit = onPostStop()
|
2015-10-31 14:46:10 +01:00
|
|
|
|
2016-07-20 13:26:27 +02:00
|
|
|
setHandlers(in, out, this)
|
|
|
|
|
}
|
2015-10-31 14:46:10 +01:00
|
|
|
}
|
|
|
|
|
|
2014-10-08 18:16:57 +02:00
|
|
|
}
|