Added: activemq/activemq-apollo/trunk/apollo-util/src/test/scala/org/scalatest/ParallelBeforeAndAfterAll.scala URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-util/src/test/scala/org/scalatest/ParallelBeforeAndAfterAll.scala?rev=1366431&view=auto ============================================================================== --- activemq/activemq-apollo/trunk/apollo-util/src/test/scala/org/scalatest/ParallelBeforeAndAfterAll.scala (added) +++ activemq/activemq-apollo/trunk/apollo-util/src/test/scala/org/scalatest/ParallelBeforeAndAfterAll.scala Fri Jul 27 16:04:01 2012 @@ -0,0 +1,253 @@ +/* + * Copyright 2001-2009 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 + +import tools.ConcurrentDistributor + +/** + * Trait that can be mixed into suites that need methods invoked before and after executing the + * suite. This trait allows code to be executed before and/or after all the tests and nested suites of a + * suite are run. This trait overrides <code>run</code> (the main <code>run</code> method that + * takes seven parameters, an optional test name, reporter, stopper, filter, configMap, optional distributor, + * and tracker) and calls the + * <code>beforeAll</code> method, then calls <code>super.run</code>. After the <code>super.run</code> + * invocation completes, whether it returns normally or completes abruptly with an exception, + * this trait's <code>run</code> method will invoke <code>afterAll</code>. + * + * <p> + * Trait <code>BeforeAndAfterAll</code> defines two overloaded variants each of <code>beforeAll</code> + * and <code>afterAll</code>, one that takes a <code>configMap</code> and another that takes no + * arguments. This traits implemention of the variant that takes the <code>configMap</code> + * simply invokes the variant that takes no parameters, which does nothing. Thus you can override + * whichever variant you want. If you need something from the <code>configMap</code> before + * all tests and nested suites are run, override <code>beforeAll(Map[String, Any])</code>. Otherwise, + * override <code>beforeAll()</code>. + * </p> + * + * <p> + * For example, the following <code>MasterSuite</code> mixes in <code>BeforeAndAfterAll</code> and + * in <code>beforeAll</code>, creates and writes to a temp file, taking the name of the temp file + * from the <code>configMap</code>. This same <code>configMap</code> is then passed to the <code>run</code> + * methods of the nested suites, <code>OneSuite</code>, <code>TwoSuite</code>, <code>RedSuite</code>, + * and <code>BlueSuite</code>, so those suites can access the filename and, therefore, the file's + * contents. After all of the nested suites have executed, <code>afterAll</code> is invoked, which + * again grabs the file name from the <code>configMap</code> and deletes the file: + * </p> + * + * <pre class="stHighlight"> + * import org.scalatest.SuperSuite + * import org.scalatest.BeforeAndAfterAll + * import java.io.FileReader + * import java.io.FileWriter + * import java.io.File + * + * class MasterSuite extends Suite with BeforeAndAfterAll { + * + * private val FileNameKeyInGoodies = "tempFileName" + * + * // Set up the temp file needed by the test, taking + * // a file name from the configMap + * override def beforeAll(configMap: Map[String, Any]) { + * + * require( + * configMap.isDefinedAt(FileNameKeyInGoodies), + * "must place a temp file name in the configMap under the key: " + FileNameKeyInGoodies + * ) + * + * val fileName = configMap(tempFileName) + * + * val writer = new FileWriter(fileName) + * try { + * writer.write("Hello, suite of tests!") + * } + * finally { + * writer.close() + * } + * } + * + * override def nestedSuites = + * List(new OneSuite, new TwoSuite, new RedSuite, new BlueSuite) + * + * // Delete the temp file + * override def afterAll(configMap: Map[String, Any]) { + * // No need to require that configMap contains the key again because it won't get + * // here if it didn't contain the key in beforeAll + * val fileName = configMap(tempFileName)) + * val file = new File(fileName) + * file.delete() + * } + * } + * </pre> + * + * <p> + * Because the <code>BeforeAndAfterAll</code> trait invokes <code>super.run</code> to run the suite, you may need to + * mix this trait in last to get the desired behavior. For example, this won't + * work, because <code>BeforeAndAfterAll</code> is "super" to </code>FunSuite</code>: + * </p> + * <pre class="stHighlight"> + * class MySuite extends BeforeAndAfterAll with FunSuite + * </pre> + * <p> + * You'd need to turn it around, so that <code>FunSuite</code> is "super" to <code>BeforeAndAfterAll</code>, like this: + * </p> + * <pre class="stHighlight"> + * class MySuite extends FunSuite with BeforeAndAfterAll + * </pre> + * + * <strong>Note: This trait does not currently ensure that the code in <code>afterAll</code> is executed after + * all the tests and nested suites are executed if a <code>Distributor</code> is passed. The + * plan is to do that eventually, but in the meantime, be aware that <code>afterAll</code> is + * guaranteed to be run after all the tests and nested suites only when they are run + * sequentially.</strong> + * + * @author Bill Venners + */ +trait ParallelBeforeAndAfterAll extends AbstractSuite { + + this: Suite => + + /** + * Defines a method to be run before any of this suite's tests or nested suites are run. + * + * <p> + * This trait's implementation + * of <code>run</code> invokes the overloaded form of this method that + * takes a <code>configMap</code> before executing + * any tests or nested suites. This trait's implementation of that <code>beforeAll(Map[String, Any])</code> + * method simply invokes this <code>beforeAll()</code> + * method. Thus this method can be used to set up a test fixture + * needed by the entire suite, when you don't need anything from the <code>configMap</code>. + * This trait's implementation of this method does nothing. + * </p> + */ + protected def beforeAll() = () + + /** + * Defines a method (that takes a <code>configMap</code>) to be run before any + * of this suite's tests or nested suites are run. + * + * <p> + * This trait's implementation + * of <code>run</code> invokes this method before executing + * any tests or nested suites (passing in the <code>configMap</code> passed to it), thus this + * method can be used to set up a test fixture + * needed by the entire suite. This trait's implementation of this method invokes the + * overloaded form of <code>beforeAll</code> that takes no <code>configMap</code>. + * </p> + */ + protected def beforeAll(configMap: Map[String, Any]) { + beforeAll() + } + + /** + * Defines a method to be run after all of this suite's tests and nested suites have + * been run. + * + * <p> + * This trait's implementation + * of <code>run</code> invokes the overloaded form of this method that + * takes a <code>configMap</code> after executing + * all tests and nested suites. This trait's implementation of that <code>afterAll(Map[String, Any])</code> method simply invokes this + * <code>afterAll()</code> method. Thus this method can be used to tear down a test fixture + * needed by the entire suite, when you don't need anything from the <code>configMap</code>. + * This trait's implementation of this method does nothing. + * </p> + */ + protected def afterAll() = () + + /** + * Defines a method (that takes a <code>configMap</code>) to be run after + * all of this suite's tests and nested suites have been run. + * + * <p> + * This trait's implementation + * of <code>run</code> invokes this method after executing all tests + * and nested suites (passing in the <code>configMap</code> passed to it), thus this + * method can be used to tear down a test fixture + * needed by the entire suite. This trait's implementation of this method invokes the + * overloaded form of <code>afterAll</code> that takes no <code>configMap</code>. + * </p> + */ + protected def afterAll(configMap: Map[String, Any]) { + afterAll() + } + + /** + * Execute a suite surrounded by calls to <code>beforeAll</code> and <code>afterAll</code>. + * + * <p> + * This trait's implementation of this method ("this method") invokes <code>beforeAll(Map[String, Any])</code> + * before executing any tests or nested suites and <code>afterAll(Map[String, Any])</code> + * after executing all tests and nested suites. It runs the suite by invoking <code>super.run</code>, passing along + * the seven parameters passed to it. + * </p> + * + * <p> + * If any invocation of <code>beforeAll</code> completes abruptly with an exception, this + * method will complete abruptly with the same exception. If any call to + * <code>super.run</code> completes abruptly with an exception, this method + * will complete abruptly with the same exception, however, before doing so, it will + * invoke <code>afterAll</code>. If <cod>afterAll</code> <em>also</em> completes abruptly with an exception, this + * method will nevertheless complete abruptly with the exception previously thrown by <code>super.run</code>. + * If <code>super.run</code> returns normally, but <code>afterAll</code> completes abruptly with an + * exception, this method will complete abruptly with the same exception. + * </p> + */ + abstract override def run(testName: Option[String], reporter: Reporter, stopper: Stopper, filter: Filter, + configMap: Map[String, Any], distributor: Option[Distributor], tracker: Tracker) { + var thrownException: Option[Throwable] = None + + def waitUntilDistributorIsDone = { + // If you are using a concurrent distributor.. wait for all + // concurrent tasks to complete before executing the afterAll. + distributor match { + case Some(distributor) => distributor match { + case distributor: ConcurrentDistributor => + distributor.waitUntilDone(); + case _ => + } + case _ => + } + } + + beforeAll(configMap) + waitUntilDistributorIsDone + try { + super.run(testName, reporter, stopper, filter, configMap, distributor, tracker) + } + catch { + case e: Exception => thrownException = Some(e) + } + finally { + waitUntilDistributorIsDone + try { + afterAll(configMap) // Make sure that afterAll is called even if run completes abruptly. + thrownException match { + case Some(e) => throw e + case None => + } + } + catch { + case laterException: Exception => + thrownException match { + // If both run and afterAll throw an exception, report the test exception + case Some(earlierException) => throw earlierException + case None => throw laterException + } + } + } + } +}
Added: activemq/activemq-apollo/trunk/apollo-util/src/test/scala/org/scalatest/junit/ParallelJUnitRunner.scala URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-util/src/test/scala/org/scalatest/junit/ParallelJUnitRunner.scala?rev=1366431&view=auto ============================================================================== --- activemq/activemq-apollo/trunk/apollo-util/src/test/scala/org/scalatest/junit/ParallelJUnitRunner.scala (added) +++ activemq/activemq-apollo/trunk/apollo-util/src/test/scala/org/scalatest/junit/ParallelJUnitRunner.scala Fri Jul 27 16:04:01 2012 @@ -0,0 +1,153 @@ +/* + * Copyright 2001-2008 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.junit + +import org.junit.runner.{Description, RunWith} +import org.scalatest._ +import org.junit.runner.notification.RunNotifier +import tools.ConcurrentDistributor +import java.util.concurrent.{ExecutorService, Executors} +import scala.Some + +/* + I think that Stopper really should be a no-op, like it is, because the user has + no way to stop it. This is wierd, because it will call nested suites. So the tests + just pile up. Oh, I see, the darn information about which test it is is in the + stupid Description displayName. We probably need to add optional test name and + suite class name to Report, just to satisfy JUnit integration. +*/ +/** + * A JUnit <code>Runner</code> that knows how to run any ScalaTest <code>Suite</code> + * (or <code>Spec</code>, which extends <code>Suite</code>). + * This enables you to provide a JUnit <code>RunWith</code> annotation on any + * ScalaTest <code>Suite</code>. Here's an example: + * + * <pre> + * import org.junit.runner.RunWith + * import org.scalatest.junit.JUnitRunner + * import org.scalatest.FunSuite + * + * @RunWith( c l a s s O f[ J U n i t R u n n e r ] ) + * class MySuite extends FunSuite { + * // ... + * } + * </pre> + * + * <p> + * This <code>RunWith</code> annotation will enable the <code>MySuite</code> class + * to be run by JUnit 4. + * </p> + * + * @author Bill Venners + * @author Daniel Watson + * @author Jon-Anders Teigen + * @author Colin Howe + */ +@RunWith(classOf[JUnitRunner]) +final class ParallelJUnitRunner(suiteClass: java.lang.Class[Suite]) extends org.junit.runner.Runner { + + private val canInstantiate = Suite.checkForPublicNoArgConstructor(suiteClass) + require(canInstantiate, "Must pass an org.scalatest.Suite with a public no-arg constructor") + + private val suiteToRun = suiteClass.newInstance + + /** + * Get a JUnit <code>Description</code> for this ScalaTest <code>Suite</code> of tests. + * + * return a <code>Description</code> of this suite of tests + */ + val getDescription = createDescription(suiteToRun) + + private def createDescription(suite: Suite): Description = { + val description = Description.createSuiteDescription(suite.getClass) + // If we don't add the testNames and nested suites in, we get + // Unrooted Tests show up in Eclipse + for (name <- suite.testNames) { + description.addChild(Description.createTestDescription(suite.getClass, name)) + } + for (nestedSuite <- suite.nestedSuites) { + description.addChild(createDescription(nestedSuite)) + } + description + } + + /** + * Run this <code>Suite</code> of tests, reporting results to the passed <code>RunNotifier</code>. + * This class's implementation of this method invokes <code>run</code> on an instance of the + * <code>suiteClass</code> <code>Class</code> passed to the primary constructor, passing + * in a <code>Reporter</code> that forwards to the <code>RunNotifier</code> passed to this + * method as <code>notifier</code>. + * + * @param notifier the JUnit <code>RunNotifier</code> to which to report the results of executing + * this suite of tests + */ + def run(notifier: RunNotifier) { + val reporter = new org.scalatest.junit.RunNotifierReporter(notifier) + var stopper = new Stopper {} + var filter = Filter() + var configMap = Map[String, Any]() + ParallelJUnitRunner.withExecutor { executor => + val distributor = new ConcurrentDistributor(reporter, stopper, filter, configMap, executor) + try { + suiteToRun.run(None, reporter, stopper, filter, configMap, Some(distributor), new Tracker) + } finally { + distributor.waitUntilDone() + } + } + } + + /** + * Returns the number of tests that are expected to run when this ScalaTest <code>Suite</code> + * is run. + * + * @return the expected number of tests that will run when this suite is run + */ + override def testCount() = suiteToRun.expectedTestCount(Filter()) +} + +object ParallelJUnitRunner { + + private var useCounter = 0 + private var executor:ExecutorService = _ + + // We share an executor across multiple concurrent test executions. + def withExecutor[T](fun: (ExecutorService)=>T):T= { + val value = this.synchronized { + useCounter+=1 + if( executor == null) { + executor = Executors.newFixedThreadPool(Integer.getInteger("test.threads", Runtime.getRuntime.availableProcessors)); + } + executor + } + try { + fun(value) + } finally { + val shutdown = this.synchronized { + useCounter-=1 + if( useCounter == 0) { + executor = null + true + } else { + false + } + } + if ( shutdown ) { + value.shutdown() + } + } + } + +} \ No newline at end of file Modified: activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala?rev=1366431&r1=1366430&r2=1366431&view=diff ============================================================================== --- activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala (original) +++ activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala Fri Jul 27 16:04:01 2012 @@ -35,6 +35,7 @@ import org.apache.activemq.apollo.dto._ import javax.ws.rs.core.MediaType._ import com.wordnik.swagger.core._ import javax.servlet.http.HttpServletResponse +import FutureResult._ @Path( "/api/json/broker") @Api(value = "/api/json/broker", Modified: activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/ConfigurationResource.scala URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/ConfigurationResource.scala?rev=1366431&r1=1366430&r2=1366431&view=diff ============================================================================== --- activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/ConfigurationResource.scala (original) +++ activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/ConfigurationResource.scala Fri Jul 27 16:04:01 2012 @@ -24,6 +24,8 @@ import javax.ws.rs._ import javax.ws.rs.core.Response.Status._ import javax.ws.rs.core.MediaType._ import com.wordnik.swagger.core.{ApiOperation, Api} +import org.apache.activemq.apollo.util.FutureResult +import FutureResult._ case class EditConfig(file:String, config:String, can_write:Boolean) case class ListConfigs(files:Array[String]) Modified: activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/SessionResource.scala URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/SessionResource.scala?rev=1366431&r1=1366430&r2=1366431&view=diff ============================================================================== --- activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/SessionResource.scala (original) +++ activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/SessionResource.scala Fri Jul 27 16:04:01 2012 @@ -28,6 +28,7 @@ import org.apache.activemq.apollo.dto._ import javax.ws.rs.core.MediaType._ import org.apache.activemq.apollo.broker.security.SecurityContext import com.wordnik.swagger.core._ +import FutureResult._ @Path( "/api/json/session") @Api(value = "/api/json/session", Modified: activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/Support.scala URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/Support.scala?rev=1366431&r1=1366430&r2=1366431&view=diff ============================================================================== --- activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/Support.scala (original) +++ activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/Support.scala Fri Jul 27 16:04:01 2012 @@ -88,7 +88,7 @@ abstract class Resource(parent:Resource= } def ok[T](value:FutureResult[T]):Unit = { - unwrap_future_result(value) + FutureResult.unwrap_future_result(value) throw new WebApplicationException(Response.ok().build) } Modified: activemq/activemq-apollo/trunk/pom.xml URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/pom.xml?rev=1366431&r1=1366430&r2=1366431&view=diff ============================================================================== --- activemq/activemq-apollo/trunk/pom.xml (original) +++ activemq/activemq-apollo/trunk/pom.xml Fri Jul 27 16:04:01 2012 @@ -41,7 +41,7 @@ <!-- dependencies that track scala version changes --> <scala-version>2.9.1-1</scala-version> - <scalatest-version>1.6.1</scalatest-version> + <scalatest-version>1.8</scalatest-version> <activemq-version>5.4.1</activemq-version> <servicemix.kernel.version>1.1.0</servicemix.kernel.version> @@ -72,7 +72,7 @@ <jdom-version>1.0</jdom-version> <jetty-version>7.6.1.v20120215</jetty-version> <jmock-version>1.0.1</jmock-version> - <junit-version>4.7</junit-version> + <junit-version>4.10</junit-version> <jxta-version>2.0</jxta-version> <log4j-version>1.2.14</log4j-version> <nlog4j-version>1.5.2</nlog4j-version> @@ -120,7 +120,7 @@ <!-- maven plugin versions --> <maven-scala-plugin-version>2.15.2</maven-scala-plugin-version> - <maven-surefire-plugin-version>2.4.3</maven-surefire-plugin-version> + <maven-surefire-plugin-version>2.12</maven-surefire-plugin-version> <jetty-plugin-version>7.0.1.v20091125</jetty-plugin-version> <!-- disable unique version timestamps in snapshots --> @@ -288,7 +288,7 @@ <configuration> <redirectTestOutputToFile>false</redirectTestOutputToFile> <forkMode>once</forkMode> - <argLine>-enableassertions</argLine> + <argLine>-enableassertions -Xmx500m</argLine> <failIfNoTests>false</failIfNoTests> <workingDirectory>${project.build.directory}</workingDirectory> <includes> @@ -299,10 +299,9 @@ <exclude>**/legacy/**</exclude> <exclude>**/jaxb/**</exclude> </excludes> - <!-- - <parallel>methods</parallel> - <threadCount>16</threadCount> - --> + <parallel>classes</parallel> + <perCoreThreadCount>false</perCoreThreadCount> + <threadCount>2</threadCount> </configuration> </plugin>
