2010-10-26 12:49:25 +02:00
|
|
|
package akka.actor
|
2010-08-24 23:21:28 +02:00
|
|
|
|
2011-06-20 15:11:32 -06:00
|
|
|
import org.scalatest.BeforeAndAfterEach
|
|
|
|
|
import akka.testkit.TestEvent._
|
|
|
|
|
import akka.testkit.EventFilter
|
2010-08-24 23:21:28 +02:00
|
|
|
import org.multiverse.api.latches.StandardLatch
|
2011-07-26 18:33:59 +12:00
|
|
|
import java.util.concurrent.{ ScheduledFuture, ConcurrentLinkedQueue, CountDownLatch, TimeUnit }
|
2011-10-11 16:05:48 +02:00
|
|
|
import akka.testkit.AkkaSpec
|
2010-08-24 23:21:28 +02:00
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
class SchedulerSpec extends AkkaSpec with BeforeAndAfterEach {
|
2011-07-12 12:17:32 +02:00
|
|
|
private val futures = new ConcurrentLinkedQueue[ScheduledFuture[AnyRef]]()
|
|
|
|
|
|
2011-07-26 18:33:59 +12:00
|
|
|
def collectFuture(f: ⇒ ScheduledFuture[AnyRef]): ScheduledFuture[AnyRef] = {
|
2011-07-12 12:17:32 +02:00
|
|
|
val future = f
|
|
|
|
|
futures.add(future)
|
|
|
|
|
future
|
|
|
|
|
}
|
2010-08-24 23:21:28 +02:00
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
override def beforeEach {
|
2011-10-13 13:16:41 +02:00
|
|
|
app.eventHandler.notify(Mute(EventFilter[Exception]("CRASH")))
|
2011-06-20 15:11:32 -06:00
|
|
|
}
|
|
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
override def afterEach {
|
2011-07-26 17:58:37 -06:00
|
|
|
while (futures.peek() ne null) { Option(futures.poll()).foreach(_.cancel(true)) }
|
2010-08-24 23:21:28 +02:00
|
|
|
}
|
|
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
"A Scheduler" must {
|
2010-08-24 23:21:28 +02:00
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
"schedule more than once" in {
|
|
|
|
|
case object Tick
|
|
|
|
|
val countDownLatch = new CountDownLatch(3)
|
2011-10-18 17:56:23 +02:00
|
|
|
val tickActor = actorOf(new Actor {
|
2011-10-11 16:05:48 +02:00
|
|
|
def receive = { case Tick ⇒ countDownLatch.countDown() }
|
|
|
|
|
})
|
|
|
|
|
// run every 50 millisec
|
2011-10-17 18:34:34 +02:00
|
|
|
collectFuture(app.scheduler.schedule(tickActor, Tick, 0, 50, TimeUnit.MILLISECONDS))
|
2010-08-24 23:21:28 +02:00
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
// after max 1 second it should be executed at least the 3 times already
|
|
|
|
|
assert(countDownLatch.await(1, TimeUnit.SECONDS))
|
2010-08-24 23:21:28 +02:00
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
val countDownLatch2 = new CountDownLatch(3)
|
2010-08-24 23:21:28 +02:00
|
|
|
|
2011-10-17 18:34:34 +02:00
|
|
|
collectFuture(app.scheduler.schedule(() ⇒ countDownLatch2.countDown(), 0, 50, TimeUnit.MILLISECONDS))
|
2010-08-24 23:21:28 +02:00
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
// after max 1 second it should be executed at least the 3 times already
|
|
|
|
|
assert(countDownLatch2.await(2, TimeUnit.SECONDS))
|
|
|
|
|
}
|
2010-08-24 23:21:28 +02:00
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
"schedule once" in {
|
|
|
|
|
case object Tick
|
|
|
|
|
val countDownLatch = new CountDownLatch(3)
|
2011-10-18 17:56:23 +02:00
|
|
|
val tickActor = actorOf(new Actor {
|
2011-10-11 16:05:48 +02:00
|
|
|
def receive = { case Tick ⇒ countDownLatch.countDown() }
|
|
|
|
|
})
|
|
|
|
|
// run every 50 millisec
|
2011-10-17 18:34:34 +02:00
|
|
|
collectFuture(app.scheduler.scheduleOnce(tickActor, Tick, 50, TimeUnit.MILLISECONDS))
|
|
|
|
|
collectFuture(app.scheduler.scheduleOnce(() ⇒ countDownLatch.countDown(), 50, TimeUnit.MILLISECONDS))
|
2011-10-11 16:05:48 +02:00
|
|
|
|
|
|
|
|
// after 1 second the wait should fail
|
|
|
|
|
assert(countDownLatch.await(2, TimeUnit.SECONDS) == false)
|
|
|
|
|
// should still be 1 left
|
|
|
|
|
assert(countDownLatch.getCount == 1)
|
2010-08-24 23:21:28 +02:00
|
|
|
}
|
|
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
/**
|
|
|
|
|
* ticket #372
|
2011-10-13 13:41:44 +02:00
|
|
|
* FIXME rewrite the test so that registry is not used
|
2011-10-11 16:05:48 +02:00
|
|
|
*/
|
2011-10-13 13:41:44 +02:00
|
|
|
// "not create actors" in {
|
|
|
|
|
// object Ping
|
|
|
|
|
// val ticks = new CountDownLatch(1000)
|
2011-10-18 17:56:23 +02:00
|
|
|
// val actor = actorOf(new Actor {
|
2011-10-13 13:41:44 +02:00
|
|
|
// def receive = { case Ping ⇒ ticks.countDown }
|
|
|
|
|
// })
|
|
|
|
|
// val numActors = app.registry.local.actors.length
|
|
|
|
|
// (1 to 1000).foreach(_ ⇒ collectFuture(Scheduler.scheduleOnce(actor, Ping, 1, TimeUnit.MILLISECONDS)))
|
|
|
|
|
// assert(ticks.await(10, TimeUnit.SECONDS))
|
|
|
|
|
// assert(app.registry.local.actors.length === numActors)
|
|
|
|
|
// }
|
2010-08-24 23:21:28 +02:00
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
/**
|
|
|
|
|
* ticket #372
|
|
|
|
|
*/
|
|
|
|
|
"be cancellable" in {
|
|
|
|
|
object Ping
|
|
|
|
|
val ticks = new CountDownLatch(1)
|
2010-08-24 23:21:28 +02:00
|
|
|
|
2011-10-18 17:56:23 +02:00
|
|
|
val actor = actorOf(new Actor {
|
2011-10-11 16:05:48 +02:00
|
|
|
def receive = { case Ping ⇒ ticks.countDown() }
|
|
|
|
|
})
|
2010-08-24 23:21:28 +02:00
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
(1 to 10).foreach { i ⇒
|
2011-10-17 18:34:34 +02:00
|
|
|
val future = collectFuture(app.scheduler.scheduleOnce(actor, Ping, 1, TimeUnit.SECONDS))
|
2011-10-11 16:05:48 +02:00
|
|
|
future.cancel(true)
|
2010-08-24 23:21:28 +02:00
|
|
|
}
|
2011-10-11 16:05:48 +02:00
|
|
|
assert(ticks.await(3, TimeUnit.SECONDS) == false) //No counting down should've been made
|
|
|
|
|
}
|
2010-08-24 23:21:28 +02:00
|
|
|
|
2011-10-11 16:05:48 +02:00
|
|
|
/**
|
|
|
|
|
* ticket #307
|
|
|
|
|
*/
|
|
|
|
|
"pick up schedule after actor restart" in {
|
|
|
|
|
object Ping
|
|
|
|
|
object Crash
|
|
|
|
|
|
|
|
|
|
val restartLatch = new StandardLatch
|
|
|
|
|
val pingLatch = new CountDownLatch(6)
|
|
|
|
|
|
2011-10-18 17:56:23 +02:00
|
|
|
val supervisor = actorOf(Props(context ⇒ { case _ ⇒ }).withFaultHandler(AllForOneStrategy(List(classOf[Exception]), 3, 1000)))
|
|
|
|
|
val actor = actorOf(Props(new Actor {
|
2011-10-11 16:05:48 +02:00
|
|
|
def receive = {
|
|
|
|
|
case Ping ⇒ pingLatch.countDown()
|
|
|
|
|
case Crash ⇒ throw new Exception("CRASH")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override def postRestart(reason: Throwable) = restartLatch.open
|
|
|
|
|
}).withSupervisor(supervisor))
|
|
|
|
|
|
2011-10-17 18:34:34 +02:00
|
|
|
collectFuture(app.scheduler.schedule(actor, Ping, 500, 500, TimeUnit.MILLISECONDS))
|
2011-10-11 16:05:48 +02:00
|
|
|
// appx 2 pings before crash
|
2011-10-17 18:34:34 +02:00
|
|
|
collectFuture(app.scheduler.scheduleOnce(actor, Crash, 1000, TimeUnit.MILLISECONDS))
|
2011-10-11 16:05:48 +02:00
|
|
|
|
|
|
|
|
assert(restartLatch.tryAwait(2, TimeUnit.SECONDS))
|
|
|
|
|
// should be enough time for the ping countdown to recover and reach 6 pings
|
|
|
|
|
assert(pingLatch.await(4, TimeUnit.SECONDS))
|
|
|
|
|
}
|
2010-08-24 23:21:28 +02:00
|
|
|
}
|
|
|
|
|
}
|