All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scalatest.concurrent.ConductorMethods.scala Maven / Gradle / Ivy

/*
 * Copyright 2001-2013 Artima, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.scalatest.concurrent

import org.scalatest._
import java.util.concurrent.atomic.AtomicReference
import _root_.java.util.concurrent.Callable
import org.scalatest.OutcomeOf.outcomeOf

/**
 * Trait that provides each test with access to a new Conductor 
 * via methods.
 *
 * 

* Here's an example of the use of this trait to test the ArrayBlockingQueue * concurrency abstraction from java.util.concurrent: *

* *
 * import org.scalatest.FunSuite
 * import org.scalatest.concurrent.ConductorMethods
 * import org.scalatest.matchers.Matchers
 * import java.util.concurrent.ArrayBlockingQueue
 *
 * class ArrayBlockingQueueSuite extends FunSuite with ConductorMethods with Matchers {
 * 
 *   test("calling put on a full queue blocks the producer thread") {
 *
 *     val buf = new ArrayBlockingQueue[Int](1)
 * 
 *     thread("producer") {
 *       buf put 42
 *       buf put 17
 *       beat should be (1)
 *     }
 * 
 *     thread("consumer") {
 *       waitForBeat(1)
 *       buf.take should be (42)
 *       buf.take should be (17)
 *     }
 * 
 *     whenFinished {
 *       buf should be ('empty)
 *     }
 *   }
 *
 *   test("calling take on an empty queue blocks the consumer thread") {
 *
 *     val buf = new ArrayBlockingQueue[Int](1)
 *
 *     thread("producer") {
 *       waitForBeat(1)
 *       buf put 42
 *       buf put 17
 *     }
 *
 *     thread("consumer") {
 *       buf.take should be (42)
 *       buf.take should be (17)
 *       beat should be (1)
 *     }
 *
 *     whenFinished {
 *       buf should be ('empty)
 *     }
 *   }
 * }
 * 
* *

* For an explanation of how these tests work, see the documentation for Conductors. *

* * @author Josh Cough * @author Bill Venners */ trait ConductorMethods extends TestSuiteMixin with Conductors { this: TestSuite => private val conductor = new AtomicReference[Conductor]() /** * Create a new thread that will execute the given function. * If the test is started, then the thread will run the function immediately. * If it is not yet started, the Thread will wait to run the function until * all threads are up and ready to go. * @param f the function to be executed by the thread */ protected def thread(f: => Any): Thread = conductor.get.thread{ f } /** * Create a new thread that will execute the given function. * If the test is started, then the thread will run the function immediately. * If it is not yet started, the Thread will wait to run the function until * all threads are up and ready to go. * @param name the name of the thread * @param f the function to be executed by the thread */ protected def threadNamed(name: String)(f: => Unit): Thread = conductor.get.threadNamed(name){ f } /* * Create a new thread that will execute the given Runnable * @param runnable the Runnable to be executed by the thread */ // def thread[T](runnable: Runnable): Thread = conductor.get.thread(runnable) /* * Create a new thread that will execute the given Runnable * @param name the name of the thread * @param runnable the Runnable to be executed by the thread */ // def thread[T](name: String, runnable: Runnable): Thread = conductor.get.thread(name,runnable) /* * Create a new thread that will execute the given Callable * @param callable the Callable to be executed by the thread */ // def thread[T](callable: Callable[T]): Thread = conductor.get.thread(callable) /* * Create a new thread that will execute the given Callable * @param name the name of the thread * @param callable the Callable to be executed by the thread */ // def thread[T](name: String, callable: Callable[T]): Thread = conductor.get.thread(name,callable) /** * Force the current thread to block until the thread clock reaches the * specified value, at which point the current thread is unblocked. * @param c the tick value to wait for */ protected def waitForBeat(beat:Int): Succeeded.type = conductor.get.waitForBeat(beat) /** * Run the passed function, ensuring the clock does not advance while the function is running * (has not yet returned or thrown an exception). */ protected def withConductorFrozen[T](f: => T): T = conductor.get.withConductorFrozen(f) /** * Check if the clock has been frozen by any threads. (The only way a thread * can freeze the clock is by calling withClockFrozen.) */ protected def isConductorFrozen: Boolean = conductor.get.isConductorFrozen /** * Gets the current value of the clock. Primarily useful in assert statements. * @return the current tick value */ protected def beat: Int = conductor.get.beat /** * Register a function to be executed after the simulation has finished. */ protected def whenFinished(fun: => Assertion): Assertion = conductor.get.whenFinished { fun } /** * Creates and initializes a private instance variable with a new Conductor, * ensuring it is visible to any thread, invokes the passed test function, * and invokes conduct on the Conductor, if it * was not already invoked by the test. * *

* This trait is stackable with other traits that override withFixture(NoArgTest), because * instead of invoking the test function directly, it delegates responsibility for invoking the test * function to super.withFixture(NoArgTest). *

*/ abstract override def withFixture(test: NoArgTest): Outcome = { conductor.compareAndSet(conductor.get, new Conductor) super.withFixture(test) match { case Succeeded if !conductor.get.conductingHasBegun => outcomeOf { conductor.get.conduct() } case other => other } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy