edu.umd.cs.mtc
Class MultithreadedTestCase

java.lang.Object
  extended by junit.framework.Assert
      extended by edu.umd.cs.mtc.MultithreadedTestCase
Direct Known Subclasses:
MultithreadedTest

public abstract class MultithreadedTestCase
extends Assert

This is the base class for each test in the MultithreadedTC framework. To create a multithreaded test case, simply extend this class. Any method with a name that starts with "thread", that has no parameters and a void return type is a thread method. Each thread method will be run in a seperate thread. This class also defines initialize() and finish() methods you can override.

A single run of a multithreaded test case consists of:

  1. Running the initialize() method
  2. Running each thread method in a seperate thread
  3. Running the finish() method when all threads are done.

The method TestFramework.runOnce(MultithreadedTestCase) can be used to run a MultithreadedTestCase once. The method TestFramework.runManyTimes(MultithreadedTestCase, int) can be used to run a multithread test case multiple times (to see if different interleavings produce different behaviors).

There are several additional methods you can use in designing test cases. The MultithreadedTestCase maintains a metronome or clock, and ticks off intervals. You can get the current tick with getTick() and you can wait until a particular tick with waitForTick(int). The metronome isn't a free running clock; it only advances to the next tick when all threads are blocked or waiting. Also, when all threads are blocked, if at least one thread isn't waiting for the metronome to advance, the system declares a deadlock to have occurred and terminates the test case (unless one of the threads is in state TIMED_WAITING).

You can set a command line parameter -Dtunit.trace=true to cause tracing messages to be printed by the metronome frame, or invoke setTrace(boolean) to turn tracing on or off.

You can set command line parameter -Dtunit.runLimit=10 to cause a test case to fail if at least one thread stays in a runnable state for more than 10 seconds without becoming blocked or waiting for a metronome tick. Use different values for shorter or longer time limits.

Since:
1.0
Author:
William Pugh, Nathaniel Ayewah
See Also:
TestFramework

Field Summary
(package private)  int clock
          The metronome used to coordinate between threads.
(package private)  ReentrantReadWriteLock clockLock
          Read locks are acquired when clock is frozen and must be released before the clock can advance in a waitForTick().
(package private) static ThreadLocal<MultithreadedTestCase> currentTestCase
          ThreadLocal containing a reference to the current instance of this class for each thread.
(package private)  boolean failed
          This flag is set to true when a test fails due to deadlock or timeout.
(package private)  Object lock
          The primary lock to synchronize on in this test case before accessing fields in this class.
(package private)  HashMap<String,Thread> methodThreads
          Map a thread name to all test case threads as they are created, primarily so that they can be accessed by each other.
(package private)  IdentityHashMap<Thread,Integer> threads
          Map each thread to the clock tick it is waiting for.
 
Constructor Summary
MultithreadedTestCase()
           
 
Method Summary
 void assertTick(int tick)
          Assert that the clock is in tick tick
static void awaitOn(Condition c)
          This method is a replacement for Condition.await().
 void finish()
          This method is invoked in a test after after all test threads have finished.
 void freezeClock()
          When the clock is frozen, it will not advance even when all threads are blocked.
 Thread getThread(int index)
          Get a thread corresponding to the method whose name is formed using the prefix "thread" followed by an integer (represented by index.
 Thread getThreadByName(String methodName)
          Get a thread given the method name that it corresponds to.
 int getTick()
          Gets the current value of the thread metronome.
 boolean getTrace()
           
(package private)  void goodbye()
          This method is called just before a testcase thread completes.
(package private)  void hello()
          This method is called right after a new testcase thread is created by the TestFramework.
 void initialize()
          This method is invoked in a test run before any test threads have started.
 boolean isClockFrozen()
          Check if the clock has been frozen by any threads.
 void mayYield()
          Calling this method from one of the test threads may cause the thread to yield.
 void mayYield(double probability)
          Calling this method from one of the test threads may cause the thread to yield.
 Thread putThread(String methodName, Thread t)
          Associates a thread with given method name.
 void setTrace(boolean trace)
           
static void skipNextWait()
          When this method is called from a thread, the next call to waitOn(Object) or awaitOn(Condition) will return immediately without blocking.
 void unfreezeClock()
          Unfreeze a clock that has been frozen by freezeClock().
 void waitForTick(Enum e)
          An Enum-based version of waitForTick.
 void waitForTick(int c)
          Force this thread to block until the thread metronome reaches the specified value, at which point the thread is unblocked.
static void waitOn(Object o)
          This method is a replacement for Object.wait().
 
Methods inherited from class junit.framework.Assert
assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertEquals, assertFalse, assertFalse, assertNotNull, assertNotNull, assertNotSame, assertNotSame, assertNull, assertNull, assertSame, assertSame, assertTrue, assertTrue, fail, fail
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

clock

int clock
The metronome used to coordinate between threads. This clock is advanced by the clock thread started by TestFramework. The clock will not advance if it is frozen.

See Also:
waitForTick(int), freezeClock(), unfreezeClock()

lock

Object lock
The primary lock to synchronize on in this test case before accessing fields in this class.


failed

boolean failed
This flag is set to true when a test fails due to deadlock or timeout.

See Also:
TestFramework

threads

IdentityHashMap<Thread,Integer> threads
Map each thread to the clock tick it is waiting for.


currentTestCase

static ThreadLocal<MultithreadedTestCase> currentTestCase
ThreadLocal containing a reference to the current instance of this class for each thread. When a thread completes or dies, its reference to this class is removed.


methodThreads

HashMap<String,Thread> methodThreads
Map a thread name to all test case threads as they are created, primarily so that they can be accessed by each other.

See Also:
getThreadByName(String), getThread(int)

clockLock

final ReentrantReadWriteLock clockLock
Read locks are acquired when clock is frozen and must be released before the clock can advance in a waitForTick().

Constructor Detail

MultithreadedTestCase

public MultithreadedTestCase()
Method Detail

initialize

public void initialize()
This method is invoked in a test run before any test threads have started.


finish

public void finish()
This method is invoked in a test after after all test threads have finished.


setTrace

public void setTrace(boolean trace)
Parameters:
trace - the trace to set

getTrace

public boolean getTrace()
Returns:
the trace

hello

void hello()
This method is called right after a new testcase thread is created by the TestFramework. It provides initial values for currentTestCase and threads.


goodbye

void goodbye()
This method is called just before a testcase thread completes. It cleans out currentTestCase and threads.


getThreadByName

public Thread getThreadByName(String methodName)
Get a thread given the method name that it corresponds to. E.g. to get the thread running the contents of the method thread1(), call getThreadByName("thread1")

NOTE: initialize() is called before threads are created, so this method returns null if called from initialize() (but not from finish()).

Parameters:
methodName - the name of the method corresponding to the thread requested
Returns:
the thread corresponding to methodName
See Also:
getThread(int)

getThread

public Thread getThread(int index)
Get a thread corresponding to the method whose name is formed using the prefix "thread" followed by an integer (represented by index. e.g. getThread(1) returns the thread that thread1() is running in.

NOTE: initialize() is called before threads are created, so this method returns null if called from initialize() (but not from finish()).

Parameters:
index - an integer following "thread" in the name of the method
Returns:
the Thread corresponding to this method
See Also:
getThreadByName(String)

putThread

public Thread putThread(String methodName,
                        Thread t)
Associates a thread with given method name. If the method name is already associated with a Thread, the old thread is returned, otherwise null is returned


waitForTick

public void waitForTick(int c)
Force this thread to block until the thread metronome reaches the specified value, at which point the thread is unblocked.

Parameters:
c - the tick value to wait for

waitForTick

public void waitForTick(Enum e)
An Enum-based version of waitForTick. It simply looks up the ordinal and adds 1 to determine the clock tick to wait for.

Parameters:
e - An Enum representing the tick to wait for. The first enumeration constant represents tick 1, the second is tick 2, etc.
See Also:
waitForTick(int)

getTick

public int getTick()
Gets the current value of the thread metronome. Primarily useful in assert statements.

Returns:
the current tick value
See Also:
assertTick(int)

assertTick

public void assertTick(int tick)
Assert that the clock is in tick tick

Parameters:
tick - a number >= 0

freezeClock

public void freezeClock()
When the clock is frozen, it will not advance even when all threads are blocked. Use this to block the current thread with a time limit, but prevent the clock from advancing due to a waitForTick(int) in another thread. This statements that occur when clock is frozen should be followed by unfreezeClock() in the same thread.


unfreezeClock

public void unfreezeClock()
Unfreeze a clock that has been frozen by freezeClock(). Both methods must be called from the same thread.


isClockFrozen

public boolean isClockFrozen()
Check if the clock has been frozen by any threads.


skipNextWait

public static void skipNextWait()
When this method is called from a thread, the next call to waitOn(Object) or awaitOn(Condition) will return immediately without blocking. Use this to make tests more robust.


waitOn

public static void waitOn(Object o)
This method is a replacement for Object.wait(). It suppresses the InterruptedException that you would otherwise have to deal with, and allows automated skipping of the next wait. The method skipNextWait() will force that thread to immediately return from the next call to this method. Designing your tests so that they work even if Object.wait() occasionally returns immediately will make your code much more robust in face of several potential threading issues.

Parameters:
o - the object to wait on

awaitOn

public static void awaitOn(Condition c)
This method is a replacement for Condition.await(). It suppresses the InterruptedException that you would otherwise have to deal with, and allows automated skipping of the next wait. The method skipNextWait() will force that thread to immediately return from the next call to this method. Designing your tests so that they work even if Condition.await() occasionally returns immediately will make your code much more robust in face of several potential threading issues.

Parameters:
c - the condition to await on

mayYield

public void mayYield()
Calling this method from one of the test threads may cause the thread to yield. Use this between statements to generate more interleavings.


mayYield

public void mayYield(double probability)
Calling this method from one of the test threads may cause the thread to yield. Use this between statements to generate more interleavings.

Parameters:
probability - (a number between 0 and 1) the likelihood that Thread.yield() is called