diff --git a/main/Defaults.scala b/main/Defaults.scala index 3e0550ead..145aeab06 100755 --- a/main/Defaults.scala +++ b/main/Defaults.scala @@ -57,6 +57,7 @@ object Defaults extends BuildCommon onComplete <<= taskTemporaryDirectory { dir => () => IO.delete(dir); IO.createDirectory(dir) }, concurrentRestrictions <<= concurrentRestrictions or defaultRestrictions, parallelExecution :== true, + parallelTestGroups := 1, sbtVersion <<= appConfiguration { _.provider.id.version }, sbtBinaryVersion <<= sbtVersion apply binarySbtVersion, sbtResolver <<= sbtVersion { sbtV => if(sbtV endsWith "-SNAPSHOT") Classpaths.typesafeSnapshots else Classpaths.typesafeReleases }, @@ -117,10 +118,10 @@ object Defaults extends BuildCommon excludeFilter :== (".*" - ".") || HiddenFileFilter, pomIncludeRepository :== Classpaths.defaultRepositoryFilter )) - def defaultTestTasks(key: Scoped): Seq[Setting[_]] = Seq( - tags in key := Seq(Tags.Test -> 1, Tags.Subprocess -> 1), - logBuffered in key := true - ) + def defaultTestTasks(key: Scoped): Seq[Setting[_]] = inTask(key)(Seq( + tags := Seq(Tags.Test -> 1), + logBuffered := true + )) def projectCore: Seq[Setting[_]] = Seq( name <<= thisProject(_.id), logManager <<= extraLoggers(LogManager.defaults), @@ -337,8 +338,9 @@ object Defaults extends BuildCommon } def testExecutionTask(task: Scoped): Initialize[Task[Tests.Execution]] = - (testOptions in task, parallelExecution in task, fork in task, javaOptions in task, tags in task) map { - (opts, par, fork, jvmOpts, ts) => new Tests.Execution(opts, par, if (fork) Tests.Fork(jvmOpts) else Tests.InProcess, ts) + (testOptions in task, parallelExecution in task, fork in task, javaOptions in task, tags in task, parallelTestGroups in task) map { + (opts, par, fork, jvmOpts, ts, lim) => + new Tests.Execution(opts, par, if (fork) Tests.Fork(jvmOpts) else Tests.InProcess, if (fork) ts :+ (Tags.ForkedTestGroup -> lim) else ts) } def testQuickFilter: Initialize[Task[Seq[String] => String => Boolean]] = diff --git a/main/Keys.scala b/main/Keys.scala index f332a7a6c..4aab237c4 100644 --- a/main/Keys.scala +++ b/main/Keys.scala @@ -199,6 +199,7 @@ object Keys val testExecution = TaskKey[Tests.Execution]("test-execution", "Settings controlling test execution") val testFilter = TaskKey[Seq[String] => String => Boolean]("test-filter", "Filter controlling whether the test is executed") val testGrouping = TaskKey[Seq[Tests.Group]]("test-grouping", "Groups discovered tests into groups.") + val parallelTestGroups = SettingKey[Int]("parallel-test-groups", "Maximum number of test groups that may run at the same time.") val isModule = AttributeKey[Boolean]("is-module", "True if the target is a module.") // Classpath/Dependency Management Keys diff --git a/main/Tags.scala b/main/Tags.scala index 25df28a3c..9d32dde25 100644 --- a/main/Tags.scala +++ b/main/Tags.scala @@ -18,7 +18,8 @@ object Tags val CPU = Tag("cpu") val Network = Tag("network") val Disk = Tag("disk") - val Subprocess = Tag("subprocess") + + val ForkedTestGroup = Tag("forked-test-group") /** Describes a restriction on concurrently executing tasks. * A Rule is constructed using one of the Tags.limit* methods. */ diff --git a/testing/agent/src/main/java/sbt/ForkMain.java b/testing/agent/src/main/java/sbt/ForkMain.java index 5a2ecfdc2..3abab7953 100755 --- a/testing/agent/src/main/java/sbt/ForkMain.java +++ b/testing/agent/src/main/java/sbt/ForkMain.java @@ -70,7 +70,12 @@ public class ForkMain { Socket socket = new Socket(InetAddress.getByName(null), Integer.valueOf(args[0])); final ObjectInputStream is = new ObjectInputStream(socket.getInputStream()); final ObjectOutputStream os = new ObjectOutputStream(socket.getOutputStream()); - new Run().run(is, os); + try { + new Run().run(is, os); + } finally { + is.close(); + os.close(); + } } private static class Run { boolean matches(Fingerprint f1, Fingerprint f2) {