/* * Copyright (C) 2015-2021 Lightbend Inc. */ package akka.dispatch import scala.concurrent.duration._ import com.typesafe.config.Config import language.postfixOps import akka.actor.{ Actor, ActorSystem, Props } import akka.testkit.{ AkkaSpec, DefaultTimeout } import akka.util.unused object StablePriorityDispatcherSpec { case object Result val config = """ unbounded-stable-prio-dispatcher { mailbox-type = "akka.dispatch.StablePriorityDispatcherSpec$Unbounded" } bounded-stable-prio-dispatcher { mailbox-type = "akka.dispatch.StablePriorityDispatcherSpec$Bounded" } """ class Unbounded(@unused settings: ActorSystem.Settings, @unused config: Config) extends UnboundedStablePriorityMailbox(PriorityGenerator({ case i: Int if i <= 100 => i // Small integers have high priority case _: Int => 101 // Don't care for other integers case Result => Int.MaxValue case _ => throw new RuntimeException() // compiler exhaustiveness check pleaser }: Any => Int)) class Bounded(@unused settings: ActorSystem.Settings, @unused config: Config) extends BoundedStablePriorityMailbox(PriorityGenerator({ case i: Int if i <= 100 => i // Small integers have high priority case _: Int => 101 // Don't care for other integers case Result => Int.MaxValue case _ => throw new RuntimeException() // compiler exhaustiveness check pleaser }: Any => Int), 1000, 10 seconds) } class StablePriorityDispatcherSpec extends AkkaSpec(StablePriorityDispatcherSpec.config) with DefaultTimeout { import StablePriorityDispatcherSpec._ "A StablePriorityDispatcher" must { "Order its messages according to the specified comparator while preserving FIFO for equal priority messages, " + "using an unbounded mailbox" in { val dispatcherKey = "unbounded-stable-prio-dispatcher" testOrdering(dispatcherKey) } "Order its messages according to the specified comparator while preserving FIFO for equal priority messages, " + "using a bounded mailbox" in { val dispatcherKey = "bounded-stable-prio-dispatcher" testOrdering(dispatcherKey) } def testOrdering(dispatcherKey: String): Unit = { val msgs = (1 to 200) toList val shuffled = scala.util.Random.shuffle(msgs) // It's important that the actor under test is not a top level actor // with RepointableActorRef, since messages might be queued in // UnstartedCell and then sent to the StablePriorityQueue and consumed immediately // without the ordering taking place. system.actorOf(Props(new Actor { context.actorOf(Props(new Actor { val acc = scala.collection.mutable.ListBuffer[Int]() shuffled.foreach { m => self ! m } self.tell(Result, testActor) def receive = { case i: Int => acc += i case Result => sender() ! acc.toList } }).withDispatcher(dispatcherKey)) def receive = Actor.emptyBehavior })) // Low messages should come out first, and in priority order. High messages follow - they are equal priority and // should come out in the same order in which they were sent. val lo = (1 to 100) toList val hi = shuffled.filter { _ > 100 } (expectMsgType[List[Int]]: List[Int]) should ===(lo ++ hi) } } }