mirror of https://github.com/sbt/sbt.git
-Changed behavior so that only a single Runner instance is used to run tests in multiple test groups.
-Added code to support remoteArgs in test-interface 1.0.
This commit is contained in:
parent
d2e40c1c56
commit
244e65cd79
|
|
@ -11,7 +11,7 @@ import Tests.{Output => TestOutput, _}
|
||||||
import ForkMain._
|
import ForkMain._
|
||||||
|
|
||||||
private[sbt] object ForkTests {
|
private[sbt] object ForkTests {
|
||||||
def apply(frameworks: Seq[TestFramework], tests: List[TestDefinition], config: Execution, classpath: Seq[File], fork: ForkOptions, log: Logger): Task[TestOutput] = {
|
def apply(runners: Map[TestFramework, Runner], tests: List[TestDefinition], config: Execution, classpath: Seq[File], fork: ForkOptions, log: Logger): Task[TestOutput] = {
|
||||||
val opts = config.options.toList
|
val opts = config.options.toList
|
||||||
val listeners = opts flatMap {
|
val listeners = opts flatMap {
|
||||||
case Listeners(ls) => ls
|
case Listeners(ls) => ls
|
||||||
|
|
@ -25,12 +25,6 @@ private[sbt] object ForkTests {
|
||||||
case Filter(f) => Some(f)
|
case Filter(f) => Some(f)
|
||||||
case _ => None
|
case _ => None
|
||||||
}
|
}
|
||||||
val argMap = frameworks.map {
|
|
||||||
f => f.implClassName -> opts.flatMap {
|
|
||||||
case Argument(None | Some(`f`), args) => args
|
|
||||||
case _ => Nil
|
|
||||||
}
|
|
||||||
}.toMap
|
|
||||||
|
|
||||||
std.TaskExtra.task {
|
std.TaskExtra.task {
|
||||||
if (!tests.isEmpty) {
|
if (!tests.isEmpty) {
|
||||||
|
|
@ -56,10 +50,12 @@ private[sbt] object ForkTests {
|
||||||
}.toArray
|
}.toArray
|
||||||
os.writeObject(testsFiltered)
|
os.writeObject(testsFiltered)
|
||||||
|
|
||||||
os.writeInt(frameworks.size)
|
os.writeInt(runners.size)
|
||||||
for ((clazz, args) <- argMap) {
|
for ((testFramework, mainRunner) <- runners) {
|
||||||
os.writeObject(clazz)
|
val remoteArgs = mainRunner.remoteArgs()
|
||||||
os.writeObject(args.toArray)
|
os.writeObject(testFramework.implClassName)
|
||||||
|
os.writeObject(mainRunner.args)
|
||||||
|
os.writeObject(remoteArgs)
|
||||||
}
|
}
|
||||||
os.flush()
|
os.flush()
|
||||||
|
|
||||||
|
|
@ -86,6 +82,7 @@ private[sbt] object ForkTests {
|
||||||
acceptorThread.join()
|
acceptorThread.join()
|
||||||
Acceptor.result
|
Acceptor.result
|
||||||
}
|
}
|
||||||
|
|
||||||
testListeners.foreach(_.doComplete(result._1))
|
testListeners.foreach(_.doComplete(result._1))
|
||||||
result
|
result
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ package sbt
|
||||||
import xsbti.api.Definition
|
import xsbti.api.Definition
|
||||||
import ConcurrentRestrictions.Tag
|
import ConcurrentRestrictions.Tag
|
||||||
|
|
||||||
import testing.{AnnotatedFingerprint, Fingerprint, Framework, SubclassFingerprint}
|
import testing.{AnnotatedFingerprint, Fingerprint, Framework, SubclassFingerprint, Runner}
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
|
@ -43,7 +43,7 @@ object Tests
|
||||||
|
|
||||||
final case class Execution(options: Seq[TestOption], parallel: Boolean, tags: Seq[(Tag, Int)])
|
final case class Execution(options: Seq[TestOption], parallel: Boolean, tags: Seq[(Tag, Int)])
|
||||||
|
|
||||||
def apply(frameworks: Map[TestFramework, Framework], testLoader: ClassLoader, discovered: Seq[TestDefinition], config: Execution, log: Logger): Task[Output] =
|
def apply(frameworks: Map[TestFramework, Framework], testLoader: ClassLoader, runners: Map[TestFramework, Runner], discovered: Seq[TestDefinition], config: Execution, log: Logger): Task[Output] =
|
||||||
{
|
{
|
||||||
import collection.mutable.{HashSet, ListBuffer, Map, Set}
|
import collection.mutable.{HashSet, ListBuffer, Map, Set}
|
||||||
val testFilters = new ListBuffer[String => Boolean]
|
val testFilters = new ListBuffer[String => Boolean]
|
||||||
|
|
@ -94,10 +94,10 @@ object Tests
|
||||||
val filtered0 = discovered.filter(includeTest).toList.distinct
|
val filtered0 = discovered.filter(includeTest).toList.distinct
|
||||||
val tests = if(orderedFilters.isEmpty) filtered0 else orderedFilters.flatMap(f => filtered0.filter(d => f(d.name))).toList.distinct
|
val tests = if(orderedFilters.isEmpty) filtered0 else orderedFilters.flatMap(f => filtered0.filter(d => f(d.name))).toList.distinct
|
||||||
val arguments = testArgsByFramework.map { case (k,v) => (k, v.toList) } toMap;
|
val arguments = testArgsByFramework.map { case (k,v) => (k, v.toList) } toMap;
|
||||||
testTask(frameworks.values.toSeq, testLoader, tests, setup.readOnly, cleanup.readOnly, log, testListeners.readOnly, arguments, config)
|
testTask(testLoader, frameworks, runners, tests, setup.readOnly, cleanup.readOnly, log, testListeners.readOnly, arguments, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
def testTask(frameworks: Seq[Framework], loader: ClassLoader, tests: Seq[TestDefinition],
|
def testTask(loader: ClassLoader, frameworks: Map[TestFramework, Framework], runners: Map[TestFramework, Runner], tests: Seq[TestDefinition],
|
||||||
userSetup: Iterable[ClassLoader => Unit], userCleanup: Iterable[ClassLoader => Unit],
|
userSetup: Iterable[ClassLoader => Unit], userCleanup: Iterable[ClassLoader => Unit],
|
||||||
log: Logger, testListeners: Seq[TestReportListener], arguments: Map[Framework, Seq[String]], config: Execution): Task[Output] =
|
log: Logger, testListeners: Seq[TestReportListener], arguments: Map[Framework, Seq[String]], config: Execution): Task[Output] =
|
||||||
{
|
{
|
||||||
|
|
@ -105,7 +105,7 @@ object Tests
|
||||||
def partApp(actions: Iterable[ClassLoader => Unit]) = actions.toSeq map {a => () => a(loader) }
|
def partApp(actions: Iterable[ClassLoader => Unit]) = actions.toSeq map {a => () => a(loader) }
|
||||||
|
|
||||||
val (frameworkSetup, runnables, frameworkCleanup) =
|
val (frameworkSetup, runnables, frameworkCleanup) =
|
||||||
TestFramework.testTasks(frameworks, loader, tests, log, testListeners, arguments)
|
TestFramework.testTasks(frameworks, runners, loader, tests, log, testListeners, arguments)
|
||||||
|
|
||||||
val setupTasks = fj(partApp(userSetup) :+ frameworkSetup)
|
val setupTasks = fj(partApp(userSetup) :+ frameworkSetup)
|
||||||
val mainTasks =
|
val mainTasks =
|
||||||
|
|
|
||||||
|
|
@ -454,14 +454,28 @@ object Defaults extends BuildCommon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def createTestRunners(frameworks: Map[TestFramework,Framework], loader: ClassLoader, config: Tests.Execution) = {
|
||||||
|
import Tests.Argument
|
||||||
|
val opts = config.options.toList
|
||||||
|
frameworks.map { case (tf, f) =>
|
||||||
|
val args = opts.flatMap {
|
||||||
|
case Argument(None | Some(`tf`), args) => args
|
||||||
|
case _ => Nil
|
||||||
|
}
|
||||||
|
val mainRunner = f.runner(args.toArray, Array.empty[String], loader)
|
||||||
|
tf -> mainRunner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def allTestGroupsTask(s: TaskStreams, frameworks: Map[TestFramework,Framework], loader: ClassLoader, groups: Seq[Tests.Group], config: Tests.Execution, cp: Classpath, javaHome: Option[File]): Task[Tests.Output] = {
|
def allTestGroupsTask(s: TaskStreams, frameworks: Map[TestFramework,Framework], loader: ClassLoader, groups: Seq[Tests.Group], config: Tests.Execution, cp: Classpath, javaHome: Option[File]): Task[Tests.Output] = {
|
||||||
|
val runners = createTestRunners(frameworks, loader, config)
|
||||||
val groupTasks = groups map {
|
val groupTasks = groups map {
|
||||||
case Tests.Group(name, tests, runPolicy) =>
|
case Tests.Group(name, tests, runPolicy) =>
|
||||||
runPolicy match {
|
runPolicy match {
|
||||||
case Tests.SubProcess(opts) =>
|
case Tests.SubProcess(opts) =>
|
||||||
ForkTests(frameworks.keys.toSeq, tests.toList, config, cp.files, opts, s.log) tag Tags.ForkedTestGroup
|
ForkTests(runners, tests.toList, config, cp.files, opts, s.log) tag Tags.ForkedTestGroup
|
||||||
case Tests.InProcess =>
|
case Tests.InProcess =>
|
||||||
Tests(frameworks, loader, tests, config, s.log)
|
Tests(frameworks, loader, runners, tests, config, s.log)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Tests.foldTasks(groupTasks, config.parallel)
|
Tests.foldTasks(groupTasks, config.parallel)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ class CustomReporter extends Reporter {
|
||||||
def apply(event: Event) {
|
def apply(event: Event) {
|
||||||
event match {
|
event match {
|
||||||
case runStarting: RunStarting => writeFile("target/RunStarting", "RunStarting")
|
case runStarting: RunStarting => writeFile("target/RunStarting", "RunStarting")
|
||||||
case runCompleted: RunCompleted => writeFile("target/RunCompleted", "RunCompleted")
|
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,7 @@ public class ForkMain {
|
||||||
for (int i = 0; i < nFrameworks; i++) {
|
for (int i = 0; i < nFrameworks; i++) {
|
||||||
final String implClassName = (String) is.readObject();
|
final String implClassName = (String) is.readObject();
|
||||||
final String[] frameworkArgs = (String[]) is.readObject();
|
final String[] frameworkArgs = (String[]) is.readObject();
|
||||||
|
final String[] remoteFrameworkArgs = (String[]) is.readObject();
|
||||||
|
|
||||||
final Framework framework;
|
final Framework framework;
|
||||||
try {
|
try {
|
||||||
|
|
@ -208,7 +209,7 @@ public class ForkMain {
|
||||||
if (matches(testFingerprint, test.fingerprint)) filteredTests.add(test);
|
if (matches(testFingerprint, test.fingerprint)) filteredTests.add(test);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Runner runner = framework.runner(frameworkArgs, new String[0], getClass().getClassLoader());
|
final Runner runner = framework.runner(frameworkArgs, remoteFrameworkArgs, getClass().getClassLoader());
|
||||||
for (ForkTestDefinition test : filteredTests)
|
for (ForkTestDefinition test : filteredTests)
|
||||||
runTestSafe(test, runner, loggers, os);
|
runTestSafe(test, runner, loggers, os);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,7 @@ final class TestDefinition(val name: String, val fingerprint: Fingerprint)
|
||||||
override def hashCode: Int = (name.hashCode, TestFramework.hashCode(fingerprint)).hashCode
|
override def hashCode: Int = (name.hashCode, TestFramework.hashCode(fingerprint)).hashCode
|
||||||
}
|
}
|
||||||
|
|
||||||
final class TestRunner(framework: Framework, loader: ClassLoader, args: Array[String], listeners: Seq[TestReportListener], log: Logger) {
|
final class TestRunner(delegate: Runner, listeners: Seq[TestReportListener], log: Logger) {
|
||||||
val delegate = framework.runner(args, Array.empty, loader)
|
|
||||||
|
|
||||||
final def run(testDefinition: TestDefinition): TestResult.Value =
|
final def run(testDefinition: TestDefinition): TestResult.Value =
|
||||||
{
|
{
|
||||||
|
|
@ -133,7 +132,8 @@ object TestFramework
|
||||||
case _ => f.toString
|
case _ => f.toString
|
||||||
}
|
}
|
||||||
|
|
||||||
def testTasks(frameworks: Seq[Framework],
|
def testTasks(frameworks: Map[TestFramework, Framework],
|
||||||
|
runners: Map[TestFramework, Runner],
|
||||||
testLoader: ClassLoader,
|
testLoader: ClassLoader,
|
||||||
tests: Seq[TestDefinition],
|
tests: Seq[TestDefinition],
|
||||||
log: Logger,
|
log: Logger,
|
||||||
|
|
@ -142,11 +142,11 @@ object TestFramework
|
||||||
(() => Unit, Seq[(String, () => TestResult.Value)], TestResult.Value => () => Unit) =
|
(() => Unit, Seq[(String, () => TestResult.Value)], TestResult.Value => () => Unit) =
|
||||||
{
|
{
|
||||||
val arguments = testArgsByFramework withDefaultValue Nil
|
val arguments = testArgsByFramework withDefaultValue Nil
|
||||||
val mappedTests = testMap(frameworks, tests, arguments)
|
val mappedTests = testMap(frameworks.values.toSeq, tests, arguments)
|
||||||
if(mappedTests.isEmpty)
|
if(mappedTests.isEmpty)
|
||||||
(() => (), Nil, _ => () => () )
|
(() => (), Nil, _ => () => () )
|
||||||
else
|
else
|
||||||
createTestTasks(testLoader, mappedTests, tests, log, listeners)
|
createTestTasks(testLoader, runners.map { case (tf, r) => (frameworks(tf), new TestRunner(r, listeners, log))}, mappedTests, tests, log, listeners)
|
||||||
}
|
}
|
||||||
|
|
||||||
private[this] def order(mapped: Map[String, () => TestResult.Value], inputs: Seq[TestDefinition]): Seq[(String, () => TestResult.Value)] =
|
private[this] def order(mapped: Map[String, () => TestResult.Value], inputs: Seq[TestDefinition]): Seq[(String, () => TestResult.Value)] =
|
||||||
|
|
@ -181,23 +181,18 @@ object TestFramework
|
||||||
uniqueDefs.toSet
|
uniqueDefs.toSet
|
||||||
}
|
}
|
||||||
|
|
||||||
private def createTestTasks(loader: ClassLoader, tests: Map[Framework, (Set[TestDefinition], Seq[String])], ordered: Seq[TestDefinition], log: Logger, listeners: Seq[TestReportListener]) =
|
private def createTestTasks(loader: ClassLoader, runners: Map[Framework, TestRunner], tests: Map[Framework, (Set[TestDefinition], Seq[String])], ordered: Seq[TestDefinition], log: Logger, listeners: Seq[TestReportListener]) =
|
||||||
{
|
{
|
||||||
val testsListeners = listeners collect { case tl: TestsListener => tl }
|
val testsListeners = listeners collect { case tl: TestsListener => tl }
|
||||||
|
|
||||||
val runnerMap =
|
|
||||||
tests map { case (framework, (testDefinitions, testArgs)) =>
|
|
||||||
(framework, new TestRunner(framework, loader, testArgs.toArray, listeners, log))
|
|
||||||
}
|
|
||||||
|
|
||||||
def foreachListenerSafe(f: TestsListener => Unit): () => Unit = () => safeForeach(testsListeners, log)(f)
|
def foreachListenerSafe(f: TestsListener => Unit): () => Unit = () => safeForeach(testsListeners, log)(f)
|
||||||
|
|
||||||
import TestResult.{Error,Passed,Failed}
|
import TestResult.{Error,Passed,Failed}
|
||||||
|
|
||||||
val startTask = foreachListenerSafe(_.doInit)
|
val startTask = foreachListenerSafe(_.doInit)
|
||||||
val testTasks =
|
val testTasks =
|
||||||
tests flatMap { case (framework, (testDefinitions, testArgs)) =>
|
tests flatMap { case (framework, (testDefinitions, testArgs)) =>
|
||||||
val runner = runnerMap(framework)
|
val runner = runners(framework)
|
||||||
for(testDefinition <- testDefinitions) yield
|
for(testDefinition <- testDefinitions) yield
|
||||||
{
|
{
|
||||||
val runTest = () => withContextLoader(loader) { runner.run(testDefinition) }
|
val runTest = () => withContextLoader(loader) { runner.run(testDefinition) }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue