mirror of https://github.com/sbt/sbt.git
Fixes after review, take 2.
This commit is contained in:
parent
e3a7a331d5
commit
4d5effcb28
|
|
@ -286,26 +286,29 @@ object Defaults extends BuildCommon
|
|||
testOptions in GlobalScope :== Nil,
|
||||
testFilter in testOnly :== (selectedFilter _),
|
||||
testFilter in testQuick <<= testQuickFilter,
|
||||
executeTests <<= (streams in test, loadedTestFrameworks, testLoader, testGrouping in test, fullClasspath in test, javaOptions in test, javaHome in test, resolvedScoped, state) flatMap {
|
||||
(s, frameworkMap, loader, groups, cp, javaOpts, javaHome, scoped, st) =>
|
||||
implicit val display = Project.showContextKey(st)
|
||||
executeTests <<= (streams in test, loadedTestFrameworks, testLoader, testGrouping in test, fullClasspath in test, javaOptions in test, javaHome in test) flatMap {
|
||||
(s, frameworkMap, loader, groups, cp, javaOpts, javaHome) =>
|
||||
val results = groups map {
|
||||
case Tests.TestGroup(name, tests, config) =>
|
||||
case Tests.Group(name, tests, config) =>
|
||||
config.subproc match {
|
||||
case Tests.Fork(extraJvm) =>
|
||||
ForkTests(frameworkMap.keys.toSeq, tests.toList, config, cp.files, javaHome, javaOpts, s.log)
|
||||
case Tests.InProcess =>
|
||||
Tests(frameworkMap, loader, tests, config, noTestsMessage(scoped, name), s.log)
|
||||
Tests(frameworkMap, loader, tests, config, s.log)
|
||||
}
|
||||
}
|
||||
Tests.reduce(results)
|
||||
Tests.flatten(results)
|
||||
},
|
||||
test <<= (executeTests, streams, resolvedScoped, state) map {
|
||||
(results, s, scoped, st) =>
|
||||
implicit val display = Project.showContextKey(st)
|
||||
Tests.showResults(s.log, results, noTestsMessage(scoped))
|
||||
},
|
||||
test <<= (executeTests, streams) map { (results, s) => Tests.showResults(s.log, results) },
|
||||
testOnly <<= inputTests(testOnly),
|
||||
testQuick <<= inputTests(testQuick)
|
||||
)
|
||||
private[this] def noTestsMessage(scoped: ScopedKey[_], group: String)(implicit display: Show[ScopedKey[_]]): String =
|
||||
"No tests to run for group " + group + " in " + display(scoped)
|
||||
private[this] def noTestsMessage(scoped: ScopedKey[_])(implicit display: Show[ScopedKey[_]]): String =
|
||||
"No tests to run for " + display(scoped)
|
||||
|
||||
lazy val TaskGlobal: Scope = ThisScope.copy(task = Global)
|
||||
lazy val ConfigGlobal: Scope = ThisScope.copy(config = Global)
|
||||
|
|
@ -316,7 +319,7 @@ object Defaults extends BuildCommon
|
|||
testOptions <<= (testOptions in TaskGlobal, testListeners) map { (options, ls) => Tests.Listeners(ls) +: options },
|
||||
testExecution <<= testExecutionTask(key),
|
||||
testGrouping <<= ((definedTests, testExecution) map {
|
||||
(tests, exec) => Seq(new Tests.TestGroup("<default>", tests, exec))
|
||||
(tests, exec) => Seq(new Tests.Group("<default>", tests, exec))
|
||||
})
|
||||
) )
|
||||
def testLogger(manager: Streams, baseKey: Scoped)(tdef: TestDefinition): Logger =
|
||||
|
|
@ -372,17 +375,17 @@ object Defaults extends BuildCommon
|
|||
case (s, frameworks, filter, groups, loader, scoped, (selected, frameworkOptions), cp, javaOpts, javaHome, st) =>
|
||||
implicit val display = Project.showContextKey(st)
|
||||
val results = groups map {
|
||||
case Tests.TestGroup(name, tests, config) =>
|
||||
case Tests.Group(name, tests, config) =>
|
||||
val modifiedOpts = Tests.Filter(filter(selected)) +: Tests.Argument(frameworkOptions : _*) +: config.options
|
||||
val newConfig = config.copy(options = modifiedOpts)
|
||||
newConfig.subproc match {
|
||||
case Tests.Fork(extraJvm) =>
|
||||
ForkTests(frameworks.keys.toSeq, tests.toList, newConfig, cp.files, javaHome, javaOpts, s.log)
|
||||
case Tests.InProcess =>
|
||||
Tests(frameworks, loader, tests, newConfig, noTestsMessage(scoped, name), s.log)
|
||||
Tests(frameworks, loader, tests, newConfig, s.log)
|
||||
}
|
||||
}
|
||||
Tests.reduce(results) map (Tests.showResults(s.log, _))
|
||||
Tests.flatten(results) map (Tests.showResults(s.log, _, noTestsMessage(scoped)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ object Keys
|
|||
val testListeners = TaskKey[Seq[TestReportListener]]("test-listeners", "Defines test listeners.")
|
||||
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.TestGroup]]("test-grouping", "Groups discovered tests into groups. Groups are run sequentially.")
|
||||
val testGrouping = TaskKey[Seq[Tests.Group]]("test-grouping", "Groups discovered tests into groups. Groups are run sequentially.")
|
||||
val isModule = AttributeKey[Boolean]("is-module", "True if the target is a module.")
|
||||
|
||||
// Classpath/Dependency Management Keys
|
||||
|
|
|
|||
|
|
@ -58,12 +58,13 @@ private[sbt] object ForkTests {
|
|||
os.writeObject(args.toArray)
|
||||
}
|
||||
|
||||
import Tags._
|
||||
@annotation.tailrec def react: Unit = is.readObject match {
|
||||
case `TestsDone` => os.writeObject(TestsDone);
|
||||
case Array(`ErrorTag`, s: String) => log.error(s); react
|
||||
case Array(`WarnTag`, s: String) => log.warn(s); react
|
||||
case Array(`InfoTag`, s: String) => log.info(s); react
|
||||
case Array(`DebugTag`, s: String) => log.debug(s); react
|
||||
case `Done` => os.writeObject(Done);
|
||||
case Array(`Error`, s: String) => log.error(s); react
|
||||
case Array(`Warn`, s: String) => log.warn(s); react
|
||||
case Array(`Info`, s: String) => log.info(s); react
|
||||
case Array(`Debug`, s: String) => log.debug(s); react
|
||||
case t: Throwable => log.trace(t); react
|
||||
case tEvents: Array[Event] =>
|
||||
for (first <- tEvents.headOption) listeners.foreach(_ startGroup first.testName)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ object Tests
|
|||
|
||||
final case class Execution(options: Seq[TestOption], parallel: Boolean, subproc: SubProcessPolicy, tags: Seq[(Tag, Int)])
|
||||
|
||||
def apply(frameworks: Map[TestFramework, Framework], testLoader: ClassLoader, discovered: Seq[TestDefinition], config: Execution, noTestsMessage: => String, log: Logger): Task[Output] =
|
||||
def apply(frameworks: Map[TestFramework, Framework], testLoader: ClassLoader, discovered: Seq[TestDefinition], config: Execution, log: Logger): Task[Output] =
|
||||
{
|
||||
import collection.mutable.{HashSet, ListBuffer, Map, Set}
|
||||
val testFilters = new ListBuffer[String => Boolean]
|
||||
|
|
@ -93,10 +93,10 @@ object Tests
|
|||
def includeTest(test: TestDefinition) = !excludeTestsSet.contains(test.name) && testFilters.forall(filter => filter(test.name))
|
||||
val tests = discovered.filter(includeTest).toSet.toSeq
|
||||
val arguments = testArgsByFramework.map { case (k,v) => (k, v.toList) } toMap;
|
||||
testTask(frameworks.values.toSeq, testLoader, tests, noTestsMessage, setup.readOnly, cleanup.readOnly, log, testListeners.readOnly, arguments, config)
|
||||
testTask(frameworks.values.toSeq, testLoader, tests, setup.readOnly, cleanup.readOnly, log, testListeners.readOnly, arguments, config)
|
||||
}
|
||||
|
||||
def testTask(frameworks: Seq[Framework], loader: ClassLoader, tests: Seq[TestDefinition], noTestsMessage: => String,
|
||||
def testTask(frameworks: Seq[Framework], loader: ClassLoader, tests: Seq[TestDefinition],
|
||||
userSetup: Iterable[ClassLoader => Unit], userCleanup: Iterable[ClassLoader => Unit],
|
||||
log: Logger, testListeners: Seq[TestReportListener], arguments: Map[Framework, Seq[String]], config: Execution): Task[Output] =
|
||||
{
|
||||
|
|
@ -104,7 +104,7 @@ object Tests
|
|||
def partApp(actions: Iterable[ClassLoader => Unit]) = actions.toSeq map {a => () => a(loader) }
|
||||
|
||||
val (frameworkSetup, runnables, frameworkCleanup) =
|
||||
TestFramework.testTasks(frameworks, loader, tests, noTestsMessage, log, testListeners, arguments)
|
||||
TestFramework.testTasks(frameworks, loader, tests, log, testListeners, arguments)
|
||||
|
||||
val setupTasks = fj(partApp(userSetup) :+ frameworkSetup)
|
||||
val mainTasks =
|
||||
|
|
@ -126,7 +126,7 @@ object Tests
|
|||
|
||||
def processResults(results: Iterable[(String, TestResult.Value)]): (TestResult.Value, Map[String, TestResult.Value]) =
|
||||
(overall(results.map(_._2)), results.toMap)
|
||||
def reduce(results: Seq[Task[Output]]): Task[Output] =
|
||||
def flatten(results: Seq[Task[Output]]): Task[Output] =
|
||||
reduced(results.toIndexedSeq, {
|
||||
case ((v1, m1), (v2, m2)) => (if (v1.id < v2.id) v2 else v1, m1 ++ m2)
|
||||
})
|
||||
|
|
@ -157,31 +157,35 @@ object Tests
|
|||
(tests, mains.toSet)
|
||||
}
|
||||
|
||||
def showResults(log: Logger, results: (TestResult.Value, Map[String, TestResult.Value])): Unit =
|
||||
def showResults(log: Logger, results: (TestResult.Value, Map[String, TestResult.Value]), noTestsMessage: =>String): Unit =
|
||||
{
|
||||
if (results._2.isEmpty)
|
||||
log.info(noTestsMessage)
|
||||
else {
|
||||
import TestResult.{Error, Failed, Passed}
|
||||
|
||||
def select(Tpe: TestResult.Value) = results._2 collect { case (name, Tpe) => name }
|
||||
def select(Tpe: TestResult.Value) = results._2 collect { case (name, Tpe) => name }
|
||||
|
||||
val failures = select(Failed)
|
||||
val errors = select(Error)
|
||||
val passed = select(Passed)
|
||||
val failures = select(Failed)
|
||||
val errors = select(Error)
|
||||
val passed = select(Passed)
|
||||
|
||||
def show(label: String, level: Level.Value, tests: Iterable[String]): Unit =
|
||||
if(!tests.isEmpty)
|
||||
{
|
||||
log.log(level, label)
|
||||
log.log(level, tests.mkString("\t", "\n\t", ""))
|
||||
}
|
||||
def show(label: String, level: Level.Value, tests: Iterable[String]): Unit =
|
||||
if(!tests.isEmpty)
|
||||
{
|
||||
log.log(level, label)
|
||||
log.log(level, tests.mkString("\t", "\n\t", ""))
|
||||
}
|
||||
|
||||
show("Passed tests:", Level.Debug, passed )
|
||||
show("Failed tests:", Level.Error, failures)
|
||||
show("Error during tests:", Level.Error, errors)
|
||||
show("Passed tests:", Level.Debug, passed )
|
||||
show("Failed tests:", Level.Error, failures)
|
||||
show("Error during tests:", Level.Error, errors)
|
||||
|
||||
if(!failures.isEmpty || !errors.isEmpty)
|
||||
error("Tests unsuccessful")
|
||||
if(!failures.isEmpty || !errors.isEmpty)
|
||||
error("Tests unsuccessful")
|
||||
}
|
||||
}
|
||||
|
||||
final case class TestGroup(name: String, tests: Seq[TestDefinition], config: Execution)
|
||||
final case class Group(name: String, tests: Seq[TestDefinition], config: Execution)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,6 @@ object TestFramework
|
|||
def testTasks(frameworks: Seq[Framework],
|
||||
testLoader: ClassLoader,
|
||||
tests: Seq[TestDefinition],
|
||||
noTestsMessage: => String,
|
||||
log: Logger,
|
||||
listeners: Seq[TestReportListener],
|
||||
testArgsByFramework: Map[Framework, Seq[String]]):
|
||||
|
|
@ -138,7 +137,7 @@ object TestFramework
|
|||
val arguments = testArgsByFramework withDefaultValue Nil
|
||||
val mappedTests = testMap(frameworks, tests, arguments)
|
||||
if(mappedTests.isEmpty)
|
||||
(() => (), Nil, _ => () => log.info(noTestsMessage) )
|
||||
(() => (), Nil, _ => () => () )
|
||||
else
|
||||
createTestTasks(testLoader, mappedTests, log, listeners)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,11 +15,9 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
public class ForkMain {
|
||||
public static final String TestsDone = "TestsDone";
|
||||
public static final String ErrorTag = "[error]";
|
||||
public static final String WarnTag = "[warn]";
|
||||
public static final String InfoTag = "[info]";
|
||||
public static final String DebugTag = "[debug]";
|
||||
public static enum Tags {
|
||||
Error, Warn, Info, Debug, Done;
|
||||
}
|
||||
|
||||
static class SubclassFingerscan implements TestFingerprint, Serializable {
|
||||
private boolean isModule;
|
||||
|
|
@ -95,18 +93,18 @@ public class ForkMain {
|
|||
Logger[] loggers = {
|
||||
new Logger() {
|
||||
public boolean ansiCodesSupported() { return false; }
|
||||
void print(Object obj) {
|
||||
void write(Object obj) {
|
||||
try {
|
||||
os.writeObject(obj);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Cannot write to socket");
|
||||
}
|
||||
}
|
||||
public void error(String s) { print(new String[]{ErrorTag, s}); }
|
||||
public void warn(String s) { print(new String[]{WarnTag, s}); }
|
||||
public void info(String s) { print(new String[]{InfoTag, s}); }
|
||||
public void debug(String s) { print(new String[]{DebugTag, s}); }
|
||||
public void trace(Throwable t) { print(t); }
|
||||
public void error(String s) { write(new Object[]{Tags.Error, s}); }
|
||||
public void warn(String s) { write(new Object[]{Tags.Warn, s}); }
|
||||
public void info(String s) { write(new Object[]{Tags.Info, s}); }
|
||||
public void debug(String s) { write(new Object[]{Tags.Debug, s}); }
|
||||
public void trace(Throwable t) { write(t); }
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -144,7 +142,7 @@ public class ForkMain {
|
|||
os.writeObject(events.toArray(new ForkEvent[events.size()]));
|
||||
}
|
||||
}
|
||||
os.writeObject(TestsDone);
|
||||
os.writeObject(Tags.Done);
|
||||
is.readObject();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue