From 546aa324e070ada49237ca5e0fd47b90645a23f0 Mon Sep 17 00:00:00 2001 From: Philipp Haller Date: Tue, 8 Jul 2008 17:26:56 +0000 Subject: Added timeouts to protect against hanging tests. --- src/partest/scala/tools/partest/PartestTask.scala | 6 ++ .../scala/tools/partest/nest/CompileManager.scala | 66 +++++++++++++--------- .../scala/tools/partest/nest/FileManager.scala | 2 + src/partest/scala/tools/partest/nest/Worker.scala | 25 +++++++- 4 files changed, 70 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala index 67c1ab8f98..60f0479904 100644 --- a/src/partest/scala/tools/partest/PartestTask.scala +++ b/src/partest/scala/tools/partest/PartestTask.scala @@ -61,6 +61,9 @@ class PartestTask extends Task { def setScalacOpts(opts: String): Unit = scalacOpts = Some(opts) + def setTimeout(delay: String): Unit = + timeout = Some(delay) + private var classpath: Option[Path] = None private var javacmd: Option[File] = None private var showDiff: Boolean = false @@ -72,6 +75,7 @@ class PartestTask extends Task { private var residentFiles: Option[FileSet] = None private var errorOnFailed: Boolean = false private var scalacOpts: Option[String] = None + private var timeout: Option[String] = None private def getPosFiles: Array[File] = if (!posFiles.isEmpty) { @@ -159,6 +163,8 @@ class PartestTask extends Task { setFileManagerStringProperty("LATEST_LIB", scalaLibrary.get.getAbsolutePath) if (!scalacOpts.isEmpty) setFileManagerStringProperty("SCALAC_OPTS", scalacOpts.get) + if (!timeout.isEmpty) + setFileManagerStringProperty("timeout", timeout.get) var allSucesses: Int = 0 var allFailures: Int = 0 diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala index 647b8144e8..995bad0f80 100644 --- a/src/partest/scala/tools/partest/nest/CompileManager.scala +++ b/src/partest/scala/tools/partest/nest/CompileManager.scala @@ -158,6 +158,10 @@ class ReflectiveCompiler(val fileManager: ConsoleFileManager) extends SimpleComp } class CompileManager(val fileManager: FileManager) { + + import scala.actors.Actor._ + import scala.actors.{Actor, Exit, TIMEOUT} + var compiler: SimpleCompiler = new /*ReflectiveCompiler*/ DirectCompiler(fileManager) var numSeparateCompilers = 1 @@ -166,43 +170,51 @@ class CompileManager(val fileManager: FileManager) { compiler = new /*ReflectiveCompiler*/ DirectCompiler(fileManager) } - /* This method returns true iff compilation succeeds. - */ - def shouldCompile(file: File, kind: String, log: File): Boolean = { + def withTimeout(file: File)(thunk: => Boolean): Boolean = { createSeparateCompiler() - try { - compiler.compile(file, kind, log) - } catch { - case t: Throwable => - NestUI.verbose("while invoking compiler ("+file+"):") - NestUI.verbose("caught "+t) - t.printStackTrace - if (t.getCause != null) - t.getCause.printStackTrace + val parent = self + self.trapExit = true + val child = link { + parent ! (self, thunk) + } + + receiveWithin(fileManager.timeout.toLong) { + case TIMEOUT => + NestUI.verbose("action timed out") false + case Exit(from, reason) if from == child => + val From = from + reason match { + case 'normal => + receive { + case (From, result: Boolean) => result + } + case t: Throwable => + NestUI.verbose("while invoking compiler ("+file+"):") + NestUI.verbose("caught "+t) + t.printStackTrace + if (t.getCause != null) + t.getCause.printStackTrace + false + } } } + /* This method returns true iff compilation succeeds. + */ + def shouldCompile(file: File, kind: String, log: File): Boolean = + withTimeout(file) { + compiler.compile(file, kind, log) + } + /* This method returns true iff compilation fails - * _and_ the compiler does _not_ crash. + * _and_ the compiler does _not_ crash or loop. * * If the compiler crashes, this method returns false. */ - def shouldFailCompile(file: File, kind: String, log: File): Boolean = { - // always create new separate compiler - createSeparateCompiler() - - try { + def shouldFailCompile(file: File, kind: String, log: File): Boolean = + withTimeout(file) { !compiler.compile(file, kind, log) - } catch { - case t: Throwable => - NestUI.verbose("while invoking compiler ("+file+"):") - NestUI.verbose("caught "+t) - t.printStackTrace - if (t.getCause != null) - t.getCause.printStackTrace - false } - } } diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala index 5de1aeb538..4b9082d8f2 100644 --- a/src/partest/scala/tools/partest/nest/FileManager.scala +++ b/src/partest/scala/tools/partest/nest/FileManager.scala @@ -54,4 +54,6 @@ trait FileManager { var failed = false var SCALAC_OPTS = System.getProperty("scalatest.scalac_opts", "-deprecation") + + var timeout = "600000" } diff --git a/src/partest/scala/tools/partest/nest/Worker.scala b/src/partest/scala/tools/partest/nest/Worker.scala index 6f607c8f7c..898d26108e 100644 --- a/src/partest/scala/tools/partest/nest/Worker.scala +++ b/src/partest/scala/tools/partest/nest/Worker.scala @@ -14,7 +14,7 @@ import java.net.URL import scala.tools.nsc.{ObjectRunner, GenericRunnerCommand} -import scala.actors.Actor +import scala.actors.{Actor, Exit, TIMEOUT} import scala.actors.Actor._ case class RunTests(kind: String, files: List[File]) @@ -456,7 +456,28 @@ class Worker(val fileManager: FileManager) extends Actor { logWriter.print(prompt) val line = resReader.readLine() if ((line ne null) && line.length() > 0) { - action(line) + val parent = self + self.trapExit = true + val child = link { + action(line) + } + + receiveWithin(fileManager.timeout.toLong) { + case TIMEOUT => + NestUI.verbose("action timed out") + false + case Exit(from, reason) if from == child => reason match { + case 'normal => // do nothing + case t: Throwable => + NestUI.verbose("while invoking compiler:") + NestUI.verbose("caught "+t) + t.printStackTrace + if (t.getCause != null) + t.getCause.printStackTrace + false + } + } + loop(action) } } -- cgit v1.2.3