Skip to content

Commit

Permalink
Print done message from test framework to stdout
Browse files Browse the repository at this point in the history
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 two dummy `sbt.testing.Framework`s which just
return a fixed `done` message.
  • Loading branch information
lolgab committed Jan 28, 2024
1 parent e171ad4 commit ceade99
Show file tree
Hide file tree
Showing 5 changed files with 101 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 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
}
}
39 changes: 38 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,20 @@ 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 ziotest extends ScalaTests with TestModule.ZioTest {
override def ivyDeps = T {
super.ivyDeps() ++ Agg(
Expand All @@ -42,11 +59,13 @@ object TestRunnerTests extends TestSuite {

def workspaceTest[T](
m: TestUtil.BaseModule,
errStream: PrintStream = System.err,
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, errStream = errStream, 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 +107,24 @@ 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"))
}
}
}
"ScalaTest" - {
test("scalatest.test") {
workspaceTest(testrunner) { eval =>
Expand Down
2 changes: 2 additions & 0 deletions testrunner/src/mill/testrunner/TestRunnerUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ import scala.jdk.CollectionConverters.IteratorHasAsScala
runner.done()
}

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 ceade99

Please sign in to comment.