Skip to content

Run tests for partest #554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 12, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ classes/

# Partest
tests/partest-generated/
tests/locks/
/test-classes/
105 changes: 66 additions & 39 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import sbt.Keys._
import sbt._
import java.io.{ RandomAccessFile, File }
import java.nio.channels.FileLock
import scala.reflect.io.Path

object DottyBuild extends Build {

Expand All @@ -16,8 +17,6 @@ object DottyBuild extends Build {
// "-XX:+HeapDumpOnOutOfMemoryError", "-Xmx1g", "-Xss2m"
)

var partestLock: FileLock = null

val defaults = Defaults.defaultSettings ++ Seq(
scalaVersion in Global := "2.11.5",
version in Global := "0.1-SNAPSHOT",
Expand All @@ -42,16 +41,16 @@ object DottyBuild extends Build {
// to get Scala 2.11
resolvers += Resolver.sonatypeRepo("releases"),

// get reflect and xml onboard
libraryDependencies ++= Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value,
"org.scala-lang.modules" %% "scala-xml" % "1.0.1",
"me.d-d" % "scala-compiler" % "2.11.5-20150506-175515-8fc7635b56",
// get libraries onboard
partestDeps := Seq("me.d-d" % "scala-compiler" % "2.11.5-20150506-175515-8fc7635b56",
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
"org.scala-lang" % "scala-library" % scalaVersion.value % "test"),
libraryDependencies ++= partestDeps.value,
libraryDependencies ++= Seq("org.scala-lang.modules" %% "scala-xml" % "1.0.1",
"org.scala-lang.modules" %% "scala-partest" % "1.0.5" % "test",
"com.novocode" % "junit-interface" % "0.11" % "test",
"jline" % "jline" % "2.12"),

// get junit onboard
libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test",

// scalac options
scalacOptions in Global ++= Seq("-feature", "-deprecation", "-language:_"),

Expand All @@ -62,14 +61,26 @@ object DottyBuild extends Build {

// enable verbose exception messages for JUnit
testOptions in Test += Tests.Argument(TestFrameworks.JUnit, "-a", "-v", "--run-listener=test.ContextEscapeDetector"),
testOptions in Test += Tests.Cleanup({ () => if (partestLock != null) partestLock.release }),
// when this file is locked, running test generates the files for partest
// otherwise it just executes the tests directly
testOptions in Test += Tests.Cleanup({ () => partestLockFile.delete }),

lockPartestFile := {
val partestLockFile = "." + File.separator + "tests" + File.separator + "partest.lock"
partestLock = new RandomAccessFile(partestLockFile, "rw").getChannel.tryLock
// When this file is present, running `test` generates the files for
// partest. Otherwise it just executes the tests directly.
val lockDir = partestLockFile.getParentFile
lockDir.mkdirs
// Cannot have concurrent partests as they write to the same directory.
if (lockDir.list.size > 0)
throw new RuntimeException("ERROR: sbt partest: another partest is already running, pid in lock file: " + lockDir.list.toList.mkString(" "))
partestLockFile.createNewFile
partestLockFile.deleteOnExit
},
runPartestRunner <<= Def.taskDyn {
val jars = Seq((packageBin in Compile).value.getAbsolutePath) ++
getJarPaths(partestDeps.value, ivyPaths.value.ivyHome)
val dottyJars = "-dottyJars " + jars.length + " " + jars.mkString(" ")
// Provide the jars required on the classpath of run tests
runTask(Test, "dotty.partest.DPConsoleRunner", dottyJars)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please document what dottyJars option does?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, see commit below.

},
runPartestRunner <<= runTask(Test, "dotty.partest.DPConsoleRunner", "") dependsOn (test in Test),

// Adjust classpath for running dotty
mainClass in (Compile, run) := Some("dotty.tools.dotc.Main"),
Expand All @@ -79,31 +90,31 @@ object DottyBuild extends Build {

// http://grokbase.com/t/gg/simple-build-tool/135ke5y90p/sbt-setting-jvm-boot-paramaters-for-scala
javaOptions <++= (managedClasspath in Runtime, packageBin in Compile) map { (attList, bin) =>
// put the Scala {library, reflect} in the classpath
val path = for {
file <- attList.map(_.data)
path = file.getAbsolutePath
} yield "-Xbootclasspath/p:" + path
// dotty itself needs to be in the bootclasspath
val fullpath = ("-Xbootclasspath/a:" + bin) :: path.toList
// System.err.println("BOOTPATH: " + fullpath)

val travis_build = // propagate if this is a travis build
if (sys.props.isDefinedAt(TRAVIS_BUILD))
List(s"-D$TRAVIS_BUILD=${sys.props(TRAVIS_BUILD)}") ::: travisMemLimit
else
List()

val tuning =
if (sys.props.isDefinedAt("Oshort"))
// Optimize for short-running applications, see https://github.com/lampepfl/dotty/issues/222
List("-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1")
// put the Scala {library, reflect} in the classpath
val path = for {
file <- attList.map(_.data)
path = file.getAbsolutePath
} yield "-Xbootclasspath/p:" + path
// dotty itself needs to be in the bootclasspath
val fullpath = ("-Xbootclasspath/a:" + bin) :: path.toList
// System.err.println("BOOTPATH: " + fullpath)

val travis_build = // propagate if this is a travis build
if (sys.props.isDefinedAt(TRAVIS_BUILD))
List(s"-D$TRAVIS_BUILD=${sys.props(TRAVIS_BUILD)}") ::: travisMemLimit
else
List()

tuning ::: agentOptions ::: travis_build ::: fullpath
val tuning =
if (sys.props.isDefinedAt("Oshort"))
// Optimize for short-running applications, see https://github.com/lampepfl/dotty/issues/222
List("-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1")
else
List()

("-DpartestParentID=" + pid) :: tuning ::: agentOptions ::: travis_build ::: fullpath
}
) ++ addCommandAlias("partest", ";lockPartestFile;runPartestRunner")
) ++ addCommandAlias("partest", ";test:compile;lockPartestFile;test:test;runPartestRunner")

lazy val dotty = Project(id = "dotty", base = file("."), settings = defaults)

Expand Down Expand Up @@ -154,7 +165,23 @@ object DottyBuild extends Build {
lazy val benchmarks = Project(id = "dotty-bench", settings = benchmarkSettings,
base = file("bench")) dependsOn(dotty % "compile->test")

lazy val lockPartestFile = TaskKey[Unit]("lockPartestFile", "Creates the file lock on ./tests/partest.lock")
lazy val runPartestRunner = TaskKey[Unit]("runPartestRunner", "Runs partests")

// Partest tasks
lazy val lockPartestFile = TaskKey[Unit]("lockPartestFile", "Creates the lock file at ./tests/locks/partest-<pid>.lock")
lazy val partestLockFile = new File("." + File.separator + "tests" + File.separator + "locks" + File.separator + s"partest-$pid.lock")
def pid = java.lang.Long.parseLong(java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")(0))

lazy val runPartestRunner = TaskKey[Unit]("runPartestRunner", "Runs partest")

lazy val partestDeps = SettingKey[Seq[ModuleID]]("partestDeps", "Finds jars for partest dependencies")
def getJarPaths(modules: Seq[ModuleID], ivyHome: Option[File]): Seq[String] = ivyHome match {
case Some(home) =>
modules.map({ module =>
val file = Path(home) / Path("cache") /
Path(module.organization) / Path(module.name) / Path("jars") /
Path(module.name + "-" + module.revision + ".jar")
if (!file.isFile) throw new RuntimeException("ERROR: sbt getJarPaths: dependency jar not found: " + file)
else file.jfile.getAbsolutePath
})
case None => throw new RuntimeException("ERROR: sbt getJarPaths: ivyHome not defined")
}
}
15 changes: 11 additions & 4 deletions test/dotc/tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class tests extends CompilerTest {
val posDir = testsDir + "pos/"
val posSpecialDir = testsDir + "pos-special/"
val negDir = testsDir + "neg/"
val runDir = testsDir + "run/"
val newDir = testsDir + "new/"

val sourceDir = "./src/"
Expand All @@ -44,7 +45,8 @@ class tests extends CompilerTest {
val coreDir = dotcDir + "core/"

@Test def pickle_pickleOK = compileDir(testsDir, "pickling", testPickling)
@Test def pickle_pickling = compileDir(coreDir, "pickling", testPickling)
// This directory doesn't exist anymore
// @Test def pickle_pickling = compileDir(coreDir, "pickling", testPickling)
@Test def pickle_ast = compileDir(dotcDir, "ast", testPickling)

//@Test def pickle_core = compileDir(dotcDir, "core", testPickling, xerrors = 2) // two spurious comparison errors in Types and TypeOps
Expand Down Expand Up @@ -136,14 +138,19 @@ class tests extends CompilerTest {
@Test def neg_instantiateAbstract = compileFile(negDir, "instantiateAbstract", xerrors = 8)
@Test def neg_selfInheritance = compileFile(negDir, "selfInheritance", xerrors = 5)

@Test def dotty = compileDir(toolsDir, "", "-deep" :: allowDeepSubtypes ++ twice) // note the -deep argument
@Test def run_hello = runFile(runDir, "hello")
@Test def run_lazyVals = runFile(runDir, "lazyVals")


@Test def dotty = compileDir(dottyDir, "tools", "-deep" :: allowDeepSubtypes ++ twice) // note the -deep argument


@Test def dotc_ast = compileDir(dotcDir, "ast")
@Test def dotc_config = compileDir(dotcDir, "config")
@Test def dotc_core = compileDir(dotcDir, "core")("-Yno-double-bindings" :: allowDeepSubtypes)// twice omitted to make tests run faster


@Test def dotc_core_pickling = compileDir(coreDir, "pickling")(allowDeepSubtypes)// twice omitted to make tests run faster
// This directory doesn't exist anymore
// @Test def dotc_core_pickling = compileDir(coreDir, "pickling")(allowDeepSubtypes)// twice omitted to make tests run faster

@Test def dotc_transform = compileDir(dotcDir, "transform")// twice omitted to make tests run faster

Expand Down
41 changes: 34 additions & 7 deletions test/dotty/partest/DPConsoleRunner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,59 @@

package dotty.partest

import scala.reflect.io.AbstractFile
import scala.tools.partest._
import scala.tools.partest.nest._
import scala.util.matching.Regex
import tools.nsc.io.{ File => NSCFile }
import java.io.File
import java.net.URLClassLoader

/** Runs dotty partest from the Console, discovering test sources in
* DPConfig.testRoot that have been generated automatically by
* DPPrepJUnitRunner. Use `sbt test` to run.
* DPPrepJUnitRunner. Use `sbt partest` to run. If additional jars are
* required by some run tests, add them to partestDeps in the sbt Build.scala.
*/
object DPConsoleRunner {
def main(args: Array[String]): Unit = {
new DPConsoleRunner(args mkString (" ")).runPartest
// unfortunately sbt runTask passes args as single string
// extra jars for run tests are passed with -dottyJars <count> <jar1> <jar2> ...
val jarFinder = """-dottyJars (\d*) (.*)""".r
val (jarList, otherArgs) = args.toList.partition(jarFinder.findFirstIn(_).isDefined)
val extraJars = jarList match {
case Nil => sys.error("Error: DPConsoleRunner needs \"-dottyJars <jarCount> <jars>*\".")
case jarFinder(nr, jarString) :: Nil =>
val jars = jarString.split(" ").toList
if (jars.length.toString != nr)
sys.error("Error: DPConsoleRunner found wrong number of dottyJars: " + jars + ", expected: " + nr + ". Make sure the path doesn't contain any spaces.")
else jars
case list => sys.error("Error: DPConsoleRunner found several -dottyJars options: " + list)
}
new DPConsoleRunner(otherArgs mkString (" "), extraJars).runPartest
}
}

// console runner has a suite runner which creates a test runner for each test
class DPConsoleRunner(args: String) extends ConsoleRunner(args) {
class DPConsoleRunner(args: String, extraJars: List[String]) extends ConsoleRunner(args) {
override val suiteRunner = new DPSuiteRunner (
testSourcePath = optSourcePath getOrElse DPConfig.testRoot,
fileManager = null, // new FileManager(ClassPath split PathResolver.Environment.javaUserClassPath map (Path(_))), // the script sets up our classpath for us via ant
fileManager = new DottyFileManager(extraJars),
updateCheck = optUpdateCheck,
failed = optFailed)

override def run = {}
def runPartest = super.run
}

class DottyFileManager(extraJars: List[String]) extends FileManager(Nil) {
lazy val extraJarList = extraJars.map(NSCFile(_))
override lazy val libraryUnderTest = Path(extraJars.find(_.contains("scala-library")).getOrElse(""))
override lazy val reflectUnderTest = Path(extraJars.find(_.contains("scala-reflect")).getOrElse(""))
override lazy val compilerUnderTest = Path(extraJars.find(_.contains("dotty")).getOrElse(""))
}

class DPSuiteRunner(testSourcePath: String, // relative path, like "files", or "pending"
fileManager: FileManager,
fileManager: DottyFileManager,
updateCheck: Boolean,
failed: Boolean,
javaCmdPath: String = PartestDefaults.javaCmd,
Expand Down Expand Up @@ -83,7 +107,7 @@ extends SuiteRunner(testSourcePath, fileManager, updateCheck, failed, javaCmdPat
// but it doesn't seem to be used anywhere
}

class DPTestRunner(testFile: File, suiteRunner: SuiteRunner) extends nest.Runner(testFile, suiteRunner) {
class DPTestRunner(testFile: File, suiteRunner: DPSuiteRunner) extends nest.Runner(testFile, suiteRunner) {
// override to provide DottyCompiler
override def newCompiler = new dotty.partest.DPDirectCompiler(this)

Expand Down Expand Up @@ -117,7 +141,6 @@ class DPTestRunner(testFile: File, suiteRunner: SuiteRunner) extends nest.Runner
case class CompSucceeded() extends NegTestState

def nerrIsOk(reason: String) = {
import scala.util.matching.Regex
val nerrFinder = """compilation failed with (\d+) errors""".r
reason match {
case nerrFinder(found) =>
Expand Down Expand Up @@ -187,4 +210,8 @@ class DPTestRunner(testFile: File, suiteRunner: SuiteRunner) extends nest.Runner
def description = s"dotc $fsString"
lazy val result = { pushTranscript(description) ; attemptCompile(fs) }
}

// override to add dotty and scala jars to classpath
override def extraClasspath = suiteRunner.fileManager.asInstanceOf[DottyFileManager].extraJarList ::: super.extraClasspath

}
12 changes: 12 additions & 0 deletions test/partest
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
# partest error message references partest script to update check files, but
# doesn't work for dotty because we don't know where tests came from.

if [ $1='--update-check' ];
then
echo """ERROR: Since dotty partest runs on generated files, please update the check
files in the original location (run tests) or update the expected error count
(neg tests) in the test file."
else
echo "This script doesn't launch partest, please use sbt partest instead."
fi
Loading