|
Akka/Scala example source code file (CoronerSpec.scala)
The CoronerSpec.scala Akka example source code
/**
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.testkit
import java.io._
import java.lang.management.ManagementFactory
import java.util.concurrent.Semaphore
import java.util.concurrent.locks.ReentrantLock
import org.scalatest.WordSpec
import org.scalatest.Matchers
import scala.concurrent.duration._
import scala.concurrent.Await
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class CoronerSpec extends WordSpec with Matchers {
private def captureOutput[A](f: PrintStream ⇒ A): (A, String) = {
val bytes = new ByteArrayOutputStream()
val out = new PrintStream(bytes, true, "UTF-8")
val result = f(out)
(result, new String(bytes.toByteArray(), "UTF-8"))
}
"A Coroner" must {
"generate a report if enough time passes" in {
val (_, report) = captureOutput(out ⇒ {
val coroner = Coroner.watch(100.milliseconds, "XXXX", out)
Await.ready(coroner, 5.seconds)
coroner.cancel()
})
report should include("Coroner's Report")
report should include("XXXX")
}
"not generate a report if cancelled early" in {
val (_, report) = captureOutput(out ⇒ {
val coroner = Coroner.watch(60.seconds, "XXXX", out)
coroner.cancel()
Await.ready(coroner, 1.seconds)
})
report should be("")
}
"display thread counts if enabled" in {
val (_, report) = captureOutput(out ⇒ {
val coroner = Coroner.watch(60.seconds, "XXXX", out, displayThreadCounts = true)
coroner.cancel()
Await.ready(coroner, 1.second)
})
report should include("Coroner Thread Count starts at ")
report should include("Coroner Thread Count started at ")
report should include("XXXX")
report should not include ("Coroner's Report")
}
"display deadlock information in its report" in {
// Create two threads that each recursively synchronize on a list of
// objects. Give each thread the same objects, but in reversed order.
// Control execution of the threads so that they each hold an object
// that the other wants to synchronize on. BOOM! Deadlock. Generate a
// report, then clean up and check the report contents.
final case class LockingThread(name: String, thread: Thread, ready: Semaphore, proceed: Semaphore)
def lockingThread(name: String, initialLocks: List[ReentrantLock]): LockingThread = {
val ready = new Semaphore(0)
val proceed = new Semaphore(0)
val t = new Thread(new Runnable {
def run = try recursiveLock(initialLocks) catch { case _: InterruptedException ⇒ () }
def recursiveLock(locks: List[ReentrantLock]) {
locks match {
case Nil ⇒ ()
case lock :: rest ⇒ {
ready.release()
proceed.acquire()
lock.lockInterruptibly() // Allows us to break deadlock and free threads
try {
recursiveLock(rest)
} finally {
lock.unlock()
}
}
}
}
}, name)
t.start()
LockingThread(name, t, ready, proceed)
}
val x = new ReentrantLock()
val y = new ReentrantLock()
val a = lockingThread("deadlock-thread-a", List(x, y))
val b = lockingThread("deadlock-thread-b", List(y, x))
// Walk threads into deadlock
a.ready.acquire()
b.ready.acquire()
a.proceed.release()
b.proceed.release()
a.ready.acquire()
b.ready.acquire()
a.proceed.release()
b.proceed.release()
val (_, report) = captureOutput(Coroner.printReport("Deadlock test", _))
a.thread.interrupt()
b.thread.interrupt()
report should include("Coroner's Report")
// Split test based on JVM capabilities. Not all JVMs can detect
// deadlock between ReentrantLocks. However, we need to use
// ReentrantLocks because normal, monitor-based locks cannot be
// un-deadlocked once this test is finished.
val threadMx = ManagementFactory.getThreadMXBean()
if (threadMx.isSynchronizerUsageSupported()) {
val sectionHeading = "Deadlocks found for monitors and ownable synchronizers"
report should include(sectionHeading)
val deadlockSection = report.split(sectionHeading)(1)
deadlockSection should include("deadlock-thread-a")
deadlockSection should include("deadlock-thread-b")
} else {
val sectionHeading = "Deadlocks found for monitors, but NOT ownable synchronizers"
report should include(sectionHeading)
val deadlockSection = report.split(sectionHeading)(1)
deadlockSection should include("None")
deadlockSection should not include ("deadlock-thread-a")
deadlockSection should not include ("deadlock-thread-b")
}
}
}
}
Other Akka source code examplesHere is a short list of links related to this Akka CoronerSpec.scala source code file: |
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.