summaryrefslogtreecommitdiff
path: root/src/partest
diff options
context:
space:
mode:
authorSom Snytt <som.snytt@gmail.com>2013-04-19 15:49:03 -0700
committerPaul Phillips <paulp@improving.org>2013-04-30 08:18:22 -0700
commit0c6bcc9cc24eeeb13f88ab91e858e5d246e0947d (patch)
tree95710f12c67433bb3f5be16621718252b6986a35 /src/partest
parentbf4466982854ffa8be57068752ea31daf7776eee (diff)
downloadscala-0c6bcc9cc24eeeb13f88ab91e858e5d246e0947d.tar.gz
scala-0c6bcc9cc24eeeb13f88ab91e858e5d246e0947d.tar.bz2
scala-0c6bcc9cc24eeeb13f88ab91e858e5d246e0947d.zip
Partest has an optionable wait period.
Partest --timeout "30 seconds" to time out the test run. It will not hang on timeout ("I hang with Par-Test" t-shirts not-withstanding). It's beyond the scope of this commit to investigate argument parsing: `partest --timeout "\"30 seconds"\" --pos`
Diffstat (limited to 'src/partest')
-rw-r--r--src/partest/scala/tools/partest/PartestDefaults.scala4
-rw-r--r--src/partest/scala/tools/partest/nest/ConsoleRunner.scala3
-rw-r--r--src/partest/scala/tools/partest/nest/FileManager.scala1
-rw-r--r--src/partest/scala/tools/partest/nest/Runner.scala38
-rw-r--r--src/partest/scala/tools/partest/package.scala10
5 files changed, 43 insertions, 13 deletions
diff --git a/src/partest/scala/tools/partest/PartestDefaults.scala b/src/partest/scala/tools/partest/PartestDefaults.scala
index 16f1a6933f..8478edeb4d 100644
--- a/src/partest/scala/tools/partest/PartestDefaults.scala
+++ b/src/partest/scala/tools/partest/PartestDefaults.scala
@@ -1,6 +1,7 @@
package scala.tools
package partest
+import scala.concurrent.duration.Duration
import scala.tools.nsc.Properties.{ propOrElse, propOrNone, propOrEmpty }
import java.lang.Runtime.{ getRuntime => runtime }
@@ -21,6 +22,7 @@ object PartestDefaults {
def testBuild = propOrNone("partest.build")
def errorCount = propOrElse("partest.errors", "0").toInt
def numThreads = propOrNone("partest.threads") map (_.toInt) getOrElse runtime.availableProcessors
+ def waitTime = propOrNone("partest.timeout") map (Duration.apply) getOrElse Duration("4 hours")
- def timeout = "1200000"
+ //def timeout = "1200000" // per-test timeout
}
diff --git a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala
index ddd42f5601..e5ace20062 100644
--- a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala
+++ b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala
@@ -86,7 +86,7 @@ class ConsoleRunner extends DirectRunner {
) ::: standardArgs
private val binaryArgs = List(
- "--grep", "--srcpath", "--buildpath", "--classpath"
+ "--grep", "--srcpath", "--buildpath", "--classpath", "--timeout"
)
def main(argstr: String) {
@@ -109,6 +109,7 @@ class ConsoleRunner extends DirectRunner {
}
parsed get "--srcpath" foreach (x => setProp("partest.srcdir", x))
+ parsed get "--timeout" foreach (x => setProp("partest.timeout", x))
fileManager =
if (parsed isSet "--buildpath") new ConsoleFileManager(parsed("--buildpath"))
diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala
index 25371b7d54..230ada4803 100644
--- a/src/partest/scala/tools/partest/nest/FileManager.scala
+++ b/src/partest/scala/tools/partest/nest/FileManager.scala
@@ -85,7 +85,6 @@ trait FileManager extends FileUtil {
var SCALAC_OPTS = PartestDefaults.scalacOpts.split(' ').toSeq
var JAVA_OPTS = PartestDefaults.javaOpts
- var timeout = PartestDefaults.timeout
/** Only when --debug is given. */
lazy val testTimings = new mutable.HashMap[String, Long]
diff --git a/src/partest/scala/tools/partest/nest/Runner.scala b/src/partest/scala/tools/partest/nest/Runner.scala
index e823c6b09f..363adc0a07 100644
--- a/src/partest/scala/tools/partest/nest/Runner.scala
+++ b/src/partest/scala/tools/partest/nest/Runner.scala
@@ -8,8 +8,10 @@ package nest
import java.io.{ Console => _, _ }
import java.net.URL
import java.nio.charset.{ Charset, CharsetDecoder, CharsetEncoder, CharacterCodingException, CodingErrorAction => Action }
-import java.util.concurrent.{ Executors, TimeUnit }
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit.NANOSECONDS
import scala.collection.mutable.ListBuffer
+import scala.concurrent.duration.Duration
import scala.io.Codec
import scala.sys.process.Process
import scala.tools.nsc.Properties.{ envOrElse, isWin, jdkHome, javaHome, propOrElse, propOrEmpty, setProp }
@@ -19,6 +21,7 @@ import scala.tools.nsc.reporters.ConsoleReporter
import scala.tools.nsc.util.{ Exceptional, ScalaClassLoader, stackTraceString }
import scala.tools.scalap.Main.decompileScala
import scala.tools.scalap.scalax.rules.scalasig.ByteCode
+import scala.util.{ Try, Success, Failure }
import ClassPath.{ join, split }
import PartestDefaults.{ javaCmd, javacCmd }
@@ -682,7 +685,7 @@ case class TestRunParams(val scalaCheckParentClassLoader: ScalaClassLoader)
trait DirectRunner {
def fileManager: FileManager
- import PartestDefaults.numThreads
+ import PartestDefaults.{ numThreads, waitTime }
Thread.setDefaultUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler {
@@ -708,17 +711,34 @@ trait DirectRunner {
val futures = kindFiles map (f => pool submit callable(manager runTest f))
pool.shutdown()
- try if (!pool.awaitTermination(4, TimeUnit.HOURS))
- NestUI warning "Thread pool timeout elapsed before all tests were complete!"
- catch { case t: InterruptedException =>
- NestUI warning "Thread pool was interrupted"
- t.printStackTrace()
+ Try (pool.awaitTermination(waitTime) {
+ throw TimeoutException(waitTime)
+ }) match {
+ case Success(_) => futures map (_.get)
+ case Failure(e) =>
+ e match {
+ case TimeoutException(d) =>
+ NestUI warning "Thread pool timeout elapsed before all tests were complete!"
+ case ie: InterruptedException =>
+ NestUI warning "Thread pool was interrupted"
+ ie.printStackTrace()
+ }
+ pool.shutdownNow() // little point in continuing
+ // try to get as many completions as possible, in case someone cares
+ val results = for (f <- futures) yield {
+ try {
+ Some(f.get(0, NANOSECONDS))
+ } catch {
+ case _: Throwable => None
+ }
+ }
+ results.flatten
}
-
- futures map (_.get)
}
}
+case class TimeoutException(duration: Duration) extends RuntimeException
+
class LogContext(val file: File, val writers: Option[(StringWriter, PrintWriter)])
object LogContext {
diff --git a/src/partest/scala/tools/partest/package.scala b/src/partest/scala/tools/partest/package.scala
index 0b169c767a..4a516d620b 100644
--- a/src/partest/scala/tools/partest/package.scala
+++ b/src/partest/scala/tools/partest/package.scala
@@ -4,8 +4,9 @@
package scala.tools
+import java.util.concurrent.{ Callable, ExecutorService }
+import scala.concurrent.duration.Duration
import scala.sys.process.javaVmArguments
-import java.util.concurrent.Callable
import scala.tools.partest.nest.NestUI
import scala.tools.nsc.util.{ ScalaClassLoader, Exceptional }
@@ -99,6 +100,13 @@ package object partest {
)
}
+ implicit class ExecutorOps(val executor: ExecutorService) {
+ def awaitTermination[A](wait: Duration)(failing: => A = ()): Option[A] = (
+ if (executor awaitTermination (wait.length, wait.unit)) None
+ else Some(failing)
+ )
+ }
+
implicit def temporaryPath2File(x: Path): File = x.jfile
implicit def stringPathToJavaFile(path: String): File = new File(path)