Throw when test framework cannot be loaded due to MatchError or NoClassDefFoundError

Problem
-------
In some situations like Dotty Community Build, sbt version is
mechanically upgraded on an old commit without humans checking the log.
For reasons we're not completely sure (likely change in ClassLoader
structure) sbt 1.6.x started to fail to load test frameworks during
tests, but since the failure of the test framework loading doesn't fail
the task, this silently succeeded the builds.

Solution
--------
On MatchError and NoClassDefFound Error, rethrow the exception.
Note that ClassNotFoundException is considered ok since we have
predefined test frameworks listed in sbt, which often are not included
in the users' classpath.
This commit is contained in:
Eugene Yokota 2022-01-31 16:37:38 -05:00
parent f5fb537c6d
commit a549e79c1d
2 changed files with 15 additions and 9 deletions

View File

@ -10,7 +10,7 @@ import scala.util.Try
// ThisBuild settings take lower precedence,
// but can be shared across the multi projects.
ThisBuild / version := {
val v = "1.6.0-SNAPSHOT"
val v = "1.6.2-SNAPSHOT"
nightlyVersion.getOrElse(v)
}
ThisBuild / version2_13 := "2.0.0-SNAPSHOT"

View File

@ -49,12 +49,14 @@ final class TestFramework(val implClassNames: String*) extends Serializable {
): Option[Framework] = {
def logError(e: Throwable): Option[Framework] = {
log.error(
s"Error loading test framework ($e). This usually means that you are"
+ " using a layered class loader that cannot reach the sbt.testing.Framework class."
+ " The most likely cause is that your project has a runtime dependency on your"
+ " test framework, e.g. scalatest. To fix this, you can try to set\n"
+ "Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.ScalaLibrary\nor\n"
+ "Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat"
s"""Error loading test framework ($e).
|This often means that you are using a layered class loader that cannot reach the sbt.testing.Framework class.
|The most likely cause is that your project has a runtime dependency on your
|test framework, e.g. ScalaTest. To fix this, you can try to set
|
| Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.ScalaLibrary
|or
| Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat""".stripMargin
)
None
}
@ -66,8 +68,12 @@ final class TestFramework(val implClassNames: String*) extends Serializable {
case oldFramework: OldFramework => new FrameworkWrapper(oldFramework)
})
} catch {
case e: NoClassDefFoundError => logError(e)
case e: MatchError => logError(e)
case e: NoClassDefFoundError =>
logError(e)
throw e
case e: MatchError =>
logError(e)
throw e
case _: ClassNotFoundException =>
log.debug("Framework implementation '" + head + "' not present.")
createFramework(loader, log, tail)