Skip to content
This repository
Browse code

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`
  • Loading branch information...
commit 0c6bcc9cc24eeeb13f88ab91e858e5d246e0947d 1 parent bf44669
som-snytt authored April 19, 2013 paulp committed April 30, 2013
4  src/partest/scala/tools/partest/PartestDefaults.scala
... ...
@@ -1,6 +1,7 @@
1 1
 package scala.tools
2 2
 package partest
3 3
 
  4
+import scala.concurrent.duration.Duration
4 5
 import scala.tools.nsc.Properties.{ propOrElse, propOrNone, propOrEmpty }
5 6
 import java.lang.Runtime.{ getRuntime => runtime }
6 7
 
@@ -21,6 +22,7 @@ object PartestDefaults {
21 22
   def testBuild  = propOrNone("partest.build")
22 23
   def errorCount = propOrElse("partest.errors", "0").toInt
23 24
   def numThreads = propOrNone("partest.threads") map (_.toInt) getOrElse runtime.availableProcessors
  25
+  def waitTime   = propOrNone("partest.timeout") map (Duration.apply) getOrElse Duration("4 hours")
24 26
 
25  
-  def timeout     = "1200000"
  27
+  //def timeout     = "1200000"   // per-test timeout
26 28
 }
3  src/partest/scala/tools/partest/nest/ConsoleRunner.scala
@@ -86,7 +86,7 @@ class ConsoleRunner extends DirectRunner {
86 86
   ) ::: standardArgs
87 87
 
88 88
   private val binaryArgs = List(
89  
-    "--grep", "--srcpath", "--buildpath", "--classpath"
  89
+    "--grep", "--srcpath", "--buildpath", "--classpath", "--timeout"
90 90
   )
91 91
 
92 92
   def main(argstr: String) {
@@ -109,6 +109,7 @@ class ConsoleRunner extends DirectRunner {
109 109
     }
110 110
 
111 111
     parsed get "--srcpath" foreach (x => setProp("partest.srcdir", x))
  112
+    parsed get "--timeout" foreach (x => setProp("partest.timeout", x))
112 113
 
113 114
     fileManager =
114 115
       if (parsed isSet "--buildpath") new ConsoleFileManager(parsed("--buildpath"))
1  src/partest/scala/tools/partest/nest/FileManager.scala
@@ -85,7 +85,6 @@ trait FileManager extends FileUtil {
85 85
 
86 86
   var SCALAC_OPTS = PartestDefaults.scalacOpts.split(' ').toSeq
87 87
   var JAVA_OPTS   = PartestDefaults.javaOpts
88  
-  var timeout     = PartestDefaults.timeout
89 88
 
90 89
   /** Only when --debug is given. */
91 90
   lazy val testTimings = new mutable.HashMap[String, Long]
38  src/partest/scala/tools/partest/nest/Runner.scala
@@ -8,8 +8,10 @@ package nest
8 8
 import java.io.{ Console => _, _ }
9 9
 import java.net.URL
10 10
 import java.nio.charset.{ Charset, CharsetDecoder, CharsetEncoder, CharacterCodingException, CodingErrorAction => Action }
11  
-import java.util.concurrent.{ Executors, TimeUnit }
  11
+import java.util.concurrent.Executors
  12
+import java.util.concurrent.TimeUnit.NANOSECONDS
12 13
 import scala.collection.mutable.ListBuffer
  14
+import scala.concurrent.duration.Duration
13 15
 import scala.io.Codec
14 16
 import scala.sys.process.Process
15 17
 import scala.tools.nsc.Properties.{ envOrElse, isWin, jdkHome, javaHome, propOrElse, propOrEmpty, setProp }
@@ -19,6 +21,7 @@ import scala.tools.nsc.reporters.ConsoleReporter
19 21
 import scala.tools.nsc.util.{ Exceptional, ScalaClassLoader, stackTraceString }
20 22
 import scala.tools.scalap.Main.decompileScala
21 23
 import scala.tools.scalap.scalax.rules.scalasig.ByteCode
  24
+import scala.util.{ Try, Success, Failure }
22 25
 import ClassPath.{ join, split }
23 26
 import PartestDefaults.{ javaCmd, javacCmd }
24 27
 
@@ -682,7 +685,7 @@ case class TestRunParams(val scalaCheckParentClassLoader: ScalaClassLoader)
682 685
 trait DirectRunner {
683 686
   def fileManager: FileManager
684 687
 
685  
-  import PartestDefaults.numThreads
  688
+  import PartestDefaults.{ numThreads, waitTime }
686 689
 
687 690
   Thread.setDefaultUncaughtExceptionHandler(
688 691
     new Thread.UncaughtExceptionHandler {
@@ -708,17 +711,34 @@ trait DirectRunner {
708 711
     val futures           = kindFiles map (f => pool submit callable(manager runTest f))
709 712
 
710 713
     pool.shutdown()
711  
-    try if (!pool.awaitTermination(4, TimeUnit.HOURS))
712  
-      NestUI warning "Thread pool timeout elapsed before all tests were complete!"
713  
-    catch { case t: InterruptedException =>
714  
-      NestUI warning "Thread pool was interrupted"
715  
-      t.printStackTrace()
  714
+    Try (pool.awaitTermination(waitTime) {
  715
+      throw TimeoutException(waitTime)
  716
+    }) match {
  717
+      case Success(_) => futures map (_.get)
  718
+      case Failure(e) =>
  719
+        e match {
  720
+          case TimeoutException(d)      =>
  721
+            NestUI warning "Thread pool timeout elapsed before all tests were complete!"
  722
+          case ie: InterruptedException =>
  723
+            NestUI warning "Thread pool was interrupted"
  724
+            ie.printStackTrace()
  725
+        }
  726
+        pool.shutdownNow()     // little point in continuing
  727
+        // try to get as many completions as possible, in case someone cares
  728
+        val results = for (f <- futures) yield {
  729
+          try {
  730
+            Some(f.get(0, NANOSECONDS))
  731
+          } catch {
  732
+            case _: Throwable => None
  733
+          }
  734
+        }
  735
+        results.flatten
716 736
     }
717  
-
718  
-    futures map (_.get)
719 737
   }
720 738
 }
721 739
 
  740
+case class TimeoutException(duration: Duration) extends RuntimeException
  741
+
722 742
 class LogContext(val file: File, val writers: Option[(StringWriter, PrintWriter)])
723 743
 
724 744
 object LogContext {
10  src/partest/scala/tools/partest/package.scala
@@ -4,8 +4,9 @@
4 4
 
5 5
 package scala.tools
6 6
 
  7
+import java.util.concurrent.{ Callable, ExecutorService }
  8
+import scala.concurrent.duration.Duration
7 9
 import scala.sys.process.javaVmArguments
8  
-import java.util.concurrent.Callable
9 10
 import scala.tools.partest.nest.NestUI
10 11
 import scala.tools.nsc.util.{ ScalaClassLoader, Exceptional }
11 12
 
@@ -99,6 +100,13 @@ package object partest {
99 100
     )
100 101
   }
101 102
 
  103
+  implicit class ExecutorOps(val executor: ExecutorService) {
  104
+    def awaitTermination[A](wait: Duration)(failing: => A = ()): Option[A] = (
  105
+      if (executor awaitTermination (wait.length, wait.unit)) None
  106
+      else Some(failing)
  107
+    )
  108
+  }
  109
+
102 110
   implicit def temporaryPath2File(x: Path): File = x.jfile
103 111
   implicit def stringPathToJavaFile(path: String): File = new File(path)
104 112
 

0 notes on commit 0c6bcc9

Please sign in to comment.
Something went wrong with that request. Please try again.