Skip to content

Commit

Permalink
Print done message from test framework to stdout (com-lihaoyi#2993)
Browse files Browse the repository at this point in the history
Fixes com-lihaoyi#2992 

We are returning the doneMessage from the test framework as value of the
test task, but we are not printing it. Moreover, the output is
shortcircuited when a task fails, so it's not passed to the `test`
command.
This PR uses `ctx.log.outputStream.println(doneMessage)` to print the
message before returning it so users can clearly see it in case of both
success and failure.
This was discovered because of the way weaver works on Scala.js Since
the `TestRunnerTests` are on `scalalib` and can't use Scala.js code, I
implemented some dummy `sbt.testing.Framework`s which just return a
fixed `done` message.

Pull Request: com-lihaoyi#2993
  • Loading branch information
lolgab authored Jan 28, 2024
1 parent e171ad4 commit cc332c9
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 1 deletion.
1 change: 1 addition & 0 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ trait MillBaseTestsModule extends MillJavaModule with TestModule {
s"-DTEST_SCALANATIVE_VERSION=${Deps.Scalanative_0_4.scalanativeVersion}",
s"-DTEST_UTEST_VERSION=${Deps.utest.dep.version}",
s"-DTEST_SCALATEST_VERSION=${Deps.TestDeps.scalaTest.dep.version}",
s"-DTEST_TEST_INTERFACE_VERSION=${Deps.sbtTestInterface.dep.version}",
s"-DTEST_ZIOTEST_VERSION=${Deps.TestDeps.zioTest.dep.version}",
s"-DTEST_ZINC_VERSION=${Deps.zinc.dep.version}"
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package mill.scalalib

import sbt.testing._

class DoneMessageFailureFramework extends Framework {
def fingerprints() = Array.empty
def name() = "DoneMessageFailureFramework"
def runner(
args: Array[String],
remoteArgs: Array[String],
testClassLoader: ClassLoader
): Runner = new Runner {
def args() = Array.empty
def done() = "test failure done message"
def remoteArgs() = Array.empty
def tasks(taskDefs: Array[TaskDef]) = Array(new Task {
def taskDef(): TaskDef = null
def execute(
eventHandler: EventHandler,
loggers: Array[Logger]
): Array[Task] = {
eventHandler.handle(new Event {

override def fullyQualifiedName(): String = "foo.bar"

override def fingerprint(): Fingerprint = new Fingerprint {}

override def selector(): Selector = new TestSelector("foo.bar")

override def status(): Status = Status.Failure

override def throwable(): OptionalThrowable = new OptionalThrowable()

override def duration(): Long = 0L

})
Array.empty
}
def tags = Array.empty
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package mill.scalalib

import sbt.testing._

class DoneMessageNullFramework extends Framework {
def fingerprints() = Array.empty
def name() = "DoneMessageNullFramework"
def runner(
args: Array[String],
remoteArgs: Array[String],
testClassLoader: ClassLoader
): Runner = new Runner {
def args() = Array.empty
def done() = null
def remoteArgs() = Array.empty
def tasks(taskDefs: Array[TaskDef]) = Array.empty
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package mill.scalalib

import sbt.testing._

class DoneMessageSuccessFramework extends Framework {
def fingerprints() = Array.empty
def name() = "DoneMessageSuccessFramework"
def runner(
args: Array[String],
remoteArgs: Array[String],
testClassLoader: ClassLoader
): Runner = new Runner {
def args() = Array.empty
def done() = "test success done message"
def remoteArgs() = Array.empty
def tasks(taskDefs: Array[TaskDef]) = Array.empty
}
}
46 changes: 45 additions & 1 deletion scalalib/test/src/mill/scalalib/TestRunnerTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package mill.scalalib

import mill.{Agg, T}

import mill.api.Result
import mill.util.{TestEvaluator, TestUtil}
import utest._
import utest.framework.TestPath

import java.io.{ByteArrayOutputStream, PrintStream}

object TestRunnerTests extends TestSuite {
object testrunner extends TestUtil.BaseModule with ScalaModule {
override def millSourcePath = TestUtil.getSrcPathBase() / millOuterCtx.enclosing.split('.')
Expand All @@ -28,6 +31,23 @@ object TestRunnerTests extends TestSuite {
}
}

trait DoneMessage extends ScalaTests {
override def ivyDeps = T {
super.ivyDeps() ++ Agg(
ivy"org.scala-sbt:test-interface:${sys.props.getOrElse("TEST_TEST_INTERFACE_VERSION", ???)}"
)
}
}
object doneMessageSuccess extends DoneMessage {
def testFramework = "mill.scalalib.DoneMessageSuccessFramework"
}
object doneMessageFailure extends DoneMessage {
def testFramework = "mill.scalalib.DoneMessageFailureFramework"
}
object doneMessageNull extends DoneMessage {
def testFramework = "mill.scalalib.DoneMessageNullFramework"
}

object ziotest extends ScalaTests with TestModule.ZioTest {
override def ivyDeps = T {
super.ivyDeps() ++ Agg(
Expand All @@ -42,11 +62,12 @@ object TestRunnerTests extends TestSuite {

def workspaceTest[T](
m: TestUtil.BaseModule,
outStream: PrintStream = System.out,
resourcePath: os.Path = resourcePath
)(t: TestEvaluator => T)(
implicit tp: TestPath
): T = {
val eval = new TestEvaluator(m)
val eval = new TestEvaluator(m, outStream = outStream)
os.remove.all(m.millSourcePath)
os.remove.all(eval.outPath)
os.makeDir.all(m.millSourcePath / os.up)
Expand Down Expand Up @@ -88,6 +109,29 @@ object TestRunnerTests extends TestSuite {
}
}

"doneMessage" - {
test("failure") {
val outStream = new ByteArrayOutputStream()
workspaceTest(testrunner, outStream = new PrintStream(outStream, true)) { eval =>
val Left(Result.Failure(msg, _)) = eval(testrunner.doneMessageFailure.test())
val stdout = new String(outStream.toByteArray)
assert(stdout.contains("test failure done message"))
}
}
test("success") {
val outStream = new ByteArrayOutputStream()
workspaceTest(testrunner, outStream = new PrintStream(outStream, true)) { eval =>
val Right(_) = eval(testrunner.doneMessageSuccess.test())
val stdout = new String(outStream.toByteArray)
assert(stdout.contains("test success done message"))
}
}
test("null") {
workspaceTest(testrunner) { eval =>
val Right(_) = eval(testrunner.doneMessageNull.test())
}
}
}
"ScalaTest" - {
test("scalatest.test") {
workspaceTest(testrunner) { eval =>
Expand Down
7 changes: 7 additions & 0 deletions testrunner/src/mill/testrunner/TestRunnerUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@ import scala.jdk.CollectionConverters.IteratorHasAsScala
runner.done()
}

if (doneMessage != null && doneMessage.nonEmpty) {
if (doneMessage.endsWith("\n"))
ctx.log.outputStream.print(doneMessage)
else
ctx.log.outputStream.println(doneMessage)
}

val results = for (e <- events.iterator().asScala) yield {
val ex =
if (e.throwable().isDefined) Some(e.throwable().get) else None
Expand Down

0 comments on commit cc332c9

Please sign in to comment.