pekko/akka-stream-tests/src/test/scala/akka/stream/scaladsl/FlowMapAsyncUnorderedSpec.scala

190 lines
6.2 KiB
Scala
Raw Normal View History

2014-09-11 11:29:50 +03:00
/**
* Copyright (C) 2014 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.stream.scaladsl
2014-09-11 11:29:50 +03:00
import scala.concurrent.Await
import scala.concurrent.Future
2014-09-11 11:29:50 +03:00
import scala.concurrent.duration._
import scala.util.control.NoStackTrace
import akka.stream.ActorFlowMaterializer
2014-09-11 11:29:50 +03:00
import akka.stream.testkit.AkkaSpec
import akka.stream.testkit.StreamTestKit
import akka.testkit.TestLatch
import akka.testkit.TestProbe
import akka.stream.ActorOperationAttributes.supervisionStrategy
import akka.stream.Supervision.resumingDecider
import akka.stream.testkit.StreamTestKit.OnNext
import akka.stream.testkit.StreamTestKit.OnComplete
import akka.stream.impl.ReactiveStreamsCompliance
2014-09-11 11:29:50 +03:00
class FlowMapAsyncUnorderedSpec extends AkkaSpec {
2014-09-11 11:29:50 +03:00
implicit val materializer = ActorFlowMaterializer()
2014-09-11 11:29:50 +03:00
"A Flow with mapAsyncUnordered" must {
2014-09-11 11:29:50 +03:00
"produce future elements in the order they are ready" in {
2014-09-11 11:29:50 +03:00
val c = StreamTestKit.SubscriberProbe[Int]()
implicit val ec = system.dispatcher
val latch = (1 to 4).map(_ -> TestLatch(1)).toMap
2015-04-09 22:28:16 +02:00
val p = Source(1 to 4).mapAsyncUnordered(4, n Future {
Await.ready(latch(n), 5.seconds)
2014-09-11 11:29:50 +03:00
n
}).to(Sink(c)).run()
2014-09-11 11:29:50 +03:00
val sub = c.expectSubscription()
sub.request(5)
latch(2).countDown()
c.expectNext(2)
latch(4).countDown()
c.expectNext(4)
latch(3).countDown()
c.expectNext(3)
latch(1).countDown()
c.expectNext(1)
2014-09-11 11:29:50 +03:00
c.expectComplete()
}
"not run more futures than requested elements" in {
val probe = TestProbe()
val c = StreamTestKit.SubscriberProbe[Int]()
implicit val ec = system.dispatcher
2015-04-09 22:28:16 +02:00
val p = Source(1 to 20).mapAsyncUnordered(4, n Future {
2014-09-11 11:29:50 +03:00
probe.ref ! n
n
}).to(Sink(c)).run()
2014-09-11 11:29:50 +03:00
val sub = c.expectSubscription()
2015-04-09 22:28:16 +02:00
// first four run immediately
probe.expectMsgAllOf(1, 2, 3, 4)
c.expectNoMsg(200.millis)
probe.expectNoMsg(Duration.Zero)
2014-09-11 11:29:50 +03:00
sub.request(1)
2015-04-09 22:28:16 +02:00
var got = Set(c.expectNext())
probe.expectMsg(5)
2014-09-11 11:29:50 +03:00
probe.expectNoMsg(500.millis)
2015-04-09 22:28:16 +02:00
sub.request(25)
probe.expectMsgAllOf(6 to 20: _*)
c.probe.within(3.seconds) {
for (_ 2 to 20) got += c.expectNext()
}
2014-09-11 11:29:50 +03:00
2015-04-09 22:28:16 +02:00
got should be((1 to 20).toSet)
c.expectComplete()
2014-09-11 11:29:50 +03:00
}
"signal future failure" in {
val latch = TestLatch(1)
val c = StreamTestKit.SubscriberProbe[Int]()
implicit val ec = system.dispatcher
2015-04-09 22:28:16 +02:00
val p = Source(1 to 5).mapAsyncUnordered(4, n Future {
2014-09-11 11:29:50 +03:00
if (n == 3) throw new RuntimeException("err1") with NoStackTrace
else {
Await.ready(latch, 10.seconds)
n
}
}).to(Sink(c)).run()
2014-09-11 11:29:50 +03:00
val sub = c.expectSubscription()
sub.request(10)
c.expectError.getMessage should be("err1")
latch.countDown()
}
"signal error from mapAsyncUnordered" in {
2014-09-11 11:29:50 +03:00
val latch = TestLatch(1)
val c = StreamTestKit.SubscriberProbe[Int]()
implicit val ec = system.dispatcher
2015-04-09 22:28:16 +02:00
val p = Source(1 to 5).mapAsyncUnordered(4, n
2014-09-11 11:29:50 +03:00
if (n == 3) throw new RuntimeException("err2") with NoStackTrace
else {
Future {
Await.ready(latch, 10.seconds)
n
}
}).
to(Sink(c)).run()
2014-09-11 11:29:50 +03:00
val sub = c.expectSubscription()
sub.request(10)
c.expectError.getMessage should be("err2")
latch.countDown()
}
"resume after future failure" in {
val c = StreamTestKit.SubscriberProbe[Int]()
implicit val ec = system.dispatcher
val p = Source(1 to 5)
.mapAsyncUnordered(4, n Future {
if (n == 3) throw new RuntimeException("err3") with NoStackTrace
else n
})
.withAttributes(supervisionStrategy(resumingDecider))
.to(Sink(c)).run()
val sub = c.expectSubscription()
sub.request(10)
val expected = (OnComplete :: List(1, 2, 4, 5).map(OnNext.apply)).toSet
c.probe.receiveWhile(2.seconds, messages = 5) { case x x }.toSet should be(expected)
}
"finish after future failure" in {
import system.dispatcher
Await.result(Source(1 to 3).mapAsyncUnordered(1, n Future {
if (n == 3) throw new RuntimeException("err3b") with NoStackTrace
else n
}).withAttributes(supervisionStrategy(resumingDecider))
.grouped(10)
.runWith(Sink.head), 1.second) should be(Seq(1, 2))
}
"resume when mapAsyncUnordered throws" in {
val c = StreamTestKit.SubscriberProbe[Int]()
implicit val ec = system.dispatcher
val p = Source(1 to 5)
.mapAsyncUnordered(4, n
if (n == 3) throw new RuntimeException("err4") with NoStackTrace
else Future(n))
.withAttributes(supervisionStrategy(resumingDecider))
.to(Sink(c)).run()
val sub = c.expectSubscription()
sub.request(10)
val expected = (OnComplete :: List(1, 2, 4, 5).map(OnNext.apply)).toSet
2015-04-09 22:28:16 +02:00
c.probe.receiveWhile(3.seconds, messages = 5) { case x x }.toSet should be(expected)
}
"signal NPE when future is completed with null" in {
val c = StreamTestKit.SubscriberProbe[String]()
2015-04-09 22:28:16 +02:00
val p = Source(List("a", "b")).mapAsyncUnordered(4, elem Future.successful(null)).to(Sink(c)).run()
val sub = c.expectSubscription()
sub.request(10)
c.expectError.getMessage should be(ReactiveStreamsCompliance.ElementMustNotBeNullMsg)
}
"resume when future is completed with null" in {
val c = StreamTestKit.SubscriberProbe[String]()
val p = Source(List("a", "b", "c"))
.mapAsyncUnordered(4, elem if (elem == "b") Future.successful(null) else Future.successful(elem))
.withAttributes(supervisionStrategy(resumingDecider))
.to(Sink(c)).run()
val sub = c.expectSubscription()
sub.request(10)
for (elem List("a", "c")) c.expectNext(elem)
c.expectComplete()
}
"should handle cancel properly" in {
val pub = StreamTestKit.PublisherProbe[Int]()
val sub = StreamTestKit.SubscriberProbe[Int]()
2015-04-09 22:28:16 +02:00
Source(pub).mapAsyncUnordered(4, Future.successful).runWith(Sink(sub))
val upstream = pub.expectSubscription()
upstream.expectRequest()
sub.expectSubscription().cancel()
upstream.expectCancellation()
}
2014-09-11 11:29:50 +03:00
}
}