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

191 lines
6.1 KiB
Scala
Raw Normal View History

/*
* Copyright (C) 2015-2019 Lightbend Inc. <https://www.lightbend.com>
*/
package akka.stream.scaladsl
import akka.actor.Status
2015-12-04 09:37:32 -05:00
import akka.pattern.pipe
import akka.stream.Attributes.inputBuffer
import akka.stream.StreamDetachedException
import akka.stream.testkit._
import akka.stream.testkit.scaladsl.StreamTestKit._
import scala.concurrent.duration._
import scala.concurrent.Await
import scala.concurrent.Promise
import scala.util.control.NoStackTrace
class QueueSinkSpec extends StreamSpec {
implicit val ec = system.dispatcher
val ex = new RuntimeException("ex") with NoStackTrace
val noMsgTimeout = 300.millis
2015-12-04 09:37:32 -05:00
"An QueueSinkSpec" must {
"send the elements as result of future" in assertAllStagesStopped {
val expected = List(Some(1), Some(2), Some(3), None)
2015-12-04 09:37:32 -05:00
val queue = Source(expected.flatten).runWith(Sink.queue())
2019-03-11 10:38:24 +01:00
expected.foreach { v =>
queue.pull().pipeTo(testActor)
expectMsg(v)
}
}
"allow to have only one future waiting for result in each point of time" in assertAllStagesStopped {
val probe = TestPublisher.manualProbe[Int]()
val queue = Source.fromPublisher(probe).runWith(Sink.queue())
val sub = probe.expectSubscription()
val future = queue.pull()
val future2 = queue.pull()
an[IllegalStateException] shouldBe thrownBy { Await.result(future2, remainingOrDefault) }
sub.sendNext(1)
future.pipeTo(testActor)
expectMsg(Some(1))
sub.sendComplete()
2015-12-04 09:37:32 -05:00
queue.pull()
}
"wait for next element from upstream" in assertAllStagesStopped {
val probe = TestPublisher.manualProbe[Int]()
val queue = Source.fromPublisher(probe).runWith(Sink.queue())
val sub = probe.expectSubscription()
queue.pull().pipeTo(testActor)
expectNoMessage(noMsgTimeout)
sub.sendNext(1)
expectMsg(Some(1))
sub.sendComplete()
2015-12-04 09:37:32 -05:00
queue.pull()
}
"fail future on stream failure" in assertAllStagesStopped {
val probe = TestPublisher.manualProbe[Int]()
val queue = Source.fromPublisher(probe).runWith(Sink.queue())
val sub = probe.expectSubscription()
queue.pull().pipeTo(testActor)
expectNoMessage(noMsgTimeout)
sub.sendError(ex)
expectMsg(Status.Failure(ex))
}
"fail future when stream failed" in assertAllStagesStopped {
val probe = TestPublisher.manualProbe[Int]()
val queue = Source.fromPublisher(probe).runWith(Sink.queue())
val sub = probe.expectSubscription()
2015-12-04 09:37:32 -05:00
sub.sendError(ex)
the[Exception] thrownBy { Await.result(queue.pull(), remainingOrDefault) } should be(ex)
}
"fail future immediately if stream already canceled" in assertAllStagesStopped {
val queue = Source.empty[Int].runWith(Sink.queue())
// race here because no way to observe that queue sink saw termination
awaitAssert({
queue.pull().failed.futureValue shouldBe a[StreamDetachedException]
})
}
"timeout future when stream cannot provide data" in assertAllStagesStopped {
val probe = TestPublisher.manualProbe[Int]()
val queue = Source.fromPublisher(probe).runWith(Sink.queue())
val sub = probe.expectSubscription()
queue.pull().pipeTo(testActor)
expectNoMessage(noMsgTimeout)
sub.sendNext(1)
expectMsg(Some(1))
sub.sendComplete()
2015-12-04 09:37:32 -05:00
queue.pull()
}
2016-01-16 12:17:19 -05:00
"fail pull future when stream is completed" in assertAllStagesStopped {
val probe = TestPublisher.manualProbe[Int]()
val queue = Source.fromPublisher(probe).runWith(Sink.queue())
val sub = probe.expectSubscription()
queue.pull().pipeTo(testActor)
sub.sendNext(1)
expectMsg(Some(1))
sub.sendComplete()
Await.result(queue.pull(), noMsgTimeout) should be(None)
queue.pull().failed.futureValue shouldBe an[StreamDetachedException]
2016-01-16 12:17:19 -05:00
}
"keep on sending even after the buffer has been full" in assertAllStagesStopped {
val bufferSize = 16
val streamElementCount = bufferSize + 4
2019-03-11 10:38:24 +01:00
val sink = Sink.queue[Int]().withAttributes(inputBuffer(bufferSize, bufferSize))
2018-02-19 07:31:13 +00:00
val bufferFullProbe = Promise[akka.Done.type]
val queue = Source(1 to streamElementCount)
.alsoTo(Flow[Int].drop(bufferSize - 1).to(Sink.foreach(_ => bufferFullProbe.trySuccess(akka.Done))))
2018-02-19 07:31:13 +00:00
.toMat(sink)(Keep.right)
.run()
2018-02-19 07:31:13 +00:00
bufferFullProbe.future.futureValue should ===(akka.Done)
for (i <- 1 to streamElementCount) {
2019-03-11 10:38:24 +01:00
queue.pull().pipeTo(testActor)
expectMsg(Some(i))
}
2019-03-11 10:38:24 +01:00
queue.pull().pipeTo(testActor)
expectMsg(None)
}
2016-01-14 15:22:25 +01:00
"cancel upstream on cancel" in assertAllStagesStopped {
val queue = Source.repeat(1).runWith(Sink.queue())
queue.pull()
queue.cancel()
}
"be able to cancel upstream right away" in assertAllStagesStopped {
val queue = Source.repeat(1).runWith(Sink.queue())
queue.cancel()
}
"work with one element buffer" in assertAllStagesStopped {
val sink = Sink.queue[Int]().withAttributes(inputBuffer(1, 1))
val probe = TestPublisher.manualProbe[Int]()
val queue = Source.fromPublisher(probe).runWith(sink)
val sub = probe.expectSubscription()
queue.pull().pipeTo(testActor)
sub.sendNext(1) // should pull next element
expectMsg(Some(1))
queue.pull().pipeTo(testActor)
expectNoMessage(200.millis) // element requested but buffer empty
sub.sendNext(2)
expectMsg(Some(2))
sub.sendComplete()
Await.result(queue.pull(), noMsgTimeout) should be(None)
}
"fail to materialize with zero sized input buffer" in {
an[IllegalArgumentException] shouldBe thrownBy {
Source.single(()).runWith(Sink.queue().withAttributes(inputBuffer(0, 0)))
}
}
"materialize to a queue which is seamlessly translatable between scala and java DSL" in assertAllStagesStopped {
val expected = List(Some(1), Some(2), Some(3), None)
val javadslQueue = Source(expected.flatten).runWith(Sink.queue()).asJava
val scaladslQueue = akka.stream.javadsl.SinkQueueWithCancel.asScala(javadslQueue)
2019-05-21 13:35:11 +02:00
expected.foreach { v =>
scaladslQueue.pull().pipeTo(testActor)
expectMsg(v)
}
}
}
}