mirror of
https://github.com/sbt/sbt.git
synced 2026-10-06 10:03:56 +02:00
[2.x] test: Compare sbt 1.x vs 2.x vs remote cache
This commit is contained in:
@@ -1449,7 +1449,7 @@ lazy val `community-build` = (project in file("community-build"))
|
||||
scalaVersion := scala3,
|
||||
libraryDependencies ++= Seq(junit % Test, junitInterface % Test),
|
||||
Test / parallelExecution := false,
|
||||
prepareCommunityBuild := {
|
||||
prepareCommunityBuild := Def.uncached {
|
||||
val _ = (sbtRoot / publishLocalBinAll).value
|
||||
IO.write(baseDirectory.value / "target" / "sbt.version", version.value)
|
||||
},
|
||||
|
||||
+41
-25
@@ -7,7 +7,7 @@ import java.nio.file.{ Files, Paths, StandardOpenOption }
|
||||
final case class ParsedCacheSummary(
|
||||
success: Boolean,
|
||||
elapsedSeconds: Long,
|
||||
hitRate: Double,
|
||||
hitRate: Option[Double],
|
||||
remoteCacheHits: Int,
|
||||
diskCacheHits: Int,
|
||||
onsiteTasks: Int,
|
||||
@@ -44,25 +44,41 @@ object ParsedTestSummary:
|
||||
case _ => None
|
||||
end ParsedTestSummary
|
||||
|
||||
/** Collects cache summaries, attaching the preceding test summary to each. */
|
||||
/**
|
||||
* Collects cache summaries, attaching the preceding test summary to each.
|
||||
* Summaries without a cache hit rate (sbt 1.x) are used only when there are none with it,
|
||||
* since sbt 2.x also prints a plain total after each cache summary.
|
||||
*/
|
||||
final class CacheSummaryCollector:
|
||||
private var pendingTests: Option[ParsedTestSummary] = None
|
||||
private val summaries = List.newBuilder[ParsedCacheSummary]
|
||||
private val withCache = List.newBuilder[ParsedCacheSummary]
|
||||
private val withoutCache = List.newBuilder[ParsedCacheSummary]
|
||||
|
||||
def add(line: String): Unit =
|
||||
ParsedTestSummary.parse(line) match
|
||||
case Some(tests) => pendingTests = Some(tests)
|
||||
case None =>
|
||||
case None =>
|
||||
ParsedCacheSummary
|
||||
.parse(line)
|
||||
.foreach(summary =>
|
||||
summaries += summary.copy(tests = pendingTests)
|
||||
val target = if summary.hitRate.isDefined then withCache else withoutCache
|
||||
target += summary.copy(tests = pendingTests)
|
||||
pendingTests = None
|
||||
)
|
||||
|
||||
def result(): List[ParsedCacheSummary] = summaries.result()
|
||||
def result(): List[ParsedCacheSummary] =
|
||||
val cached = withCache.result()
|
||||
if cached.nonEmpty then cached else withoutCache.result()
|
||||
end CacheSummaryCollector
|
||||
|
||||
/** Describes one sbt invocation of a community project. */
|
||||
final case class RunInfo(
|
||||
project: String,
|
||||
run: String,
|
||||
sbtVersion: String,
|
||||
wallClockSeconds: Double,
|
||||
)
|
||||
|
||||
object ParsedCacheSummary:
|
||||
private val Elapsed = """elapsed time: (\d+) s""".r.unanchored
|
||||
private val HitRate = """\bcache (\d+)%""".r.unanchored
|
||||
@@ -72,17 +88,16 @@ object ParsedCacheSummary:
|
||||
private val Errors = """(\d+) errors?\b""".r.unanchored
|
||||
|
||||
def parse(line: String): Option[ParsedCacheSummary] =
|
||||
for
|
||||
elapsed <- first(Elapsed, line)
|
||||
hitRate <- first(HitRate, line)
|
||||
yield ParsedCacheSummary(
|
||||
success = !line.contains("[error]"),
|
||||
elapsedSeconds = elapsed.toLong,
|
||||
hitRate = hitRate.toInt / 100.0,
|
||||
remoteCacheHits = count(RemoteHits, line),
|
||||
diskCacheHits = count(DiskHits, line),
|
||||
onsiteTasks = count(Onsite, line),
|
||||
errors = count(Errors, line),
|
||||
first(Elapsed, line).map(elapsed =>
|
||||
ParsedCacheSummary(
|
||||
success = !line.contains("[error]"),
|
||||
elapsedSeconds = elapsed.toLong,
|
||||
hitRate = first(HitRate, line).map(_.toInt / 100.0),
|
||||
remoteCacheHits = count(RemoteHits, line),
|
||||
diskCacheHits = count(DiskHits, line),
|
||||
onsiteTasks = count(Onsite, line),
|
||||
errors = count(Errors, line),
|
||||
)
|
||||
)
|
||||
|
||||
private def first(regex: scala.util.matching.Regex, line: String): Option[String] =
|
||||
@@ -92,27 +107,28 @@ object ParsedCacheSummary:
|
||||
first(regex, line).fold(0)(_.toInt)
|
||||
|
||||
private[communitybuild] val tableHeader =
|
||||
"""|| Project | Status | Elapsed | Cache | Remote hits | Disk hits | Onsite tasks | Errors | Tests | Cached tests |
|
||||
||---|---|---|---|---|---|---|---|---|---|
|
||||
"""|| Project | Run | sbt | Status | Wall clock | Elapsed | Cache | Remote hits | Disk hits | Onsite tasks | Errors | Tests | Cached tests |
|
||||
||---|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||
|""".stripMargin
|
||||
|
||||
def markdownRow(project: String, summary: ParsedCacheSummary): String =
|
||||
def markdownRow(info: RunInfo, summary: ParsedCacheSummary): String =
|
||||
import summary.*
|
||||
val status = if success then "success" else "error"
|
||||
val percent = f"${hitRate * 100}%.0f%%"
|
||||
val wallClock = f"${info.wallClockSeconds}%.1fs"
|
||||
val percent = hitRate.fold("")(rate => f"${rate * 100}%.0f%%")
|
||||
val testCount = tests.fold("")(_.total.toString)
|
||||
val cachedTests = tests.fold("")(_.cached.toString)
|
||||
s"| `$project` | $status | ${elapsedSeconds}s | $percent | $remoteCacheHits | $diskCacheHits | $onsiteTasks | $errors | $testCount | $cachedTests |\n"
|
||||
s"| `${info.project}` | ${info.run} | ${info.sbtVersion} | $status | $wallClock | ${elapsedSeconds}s | $percent | $remoteCacheHits | $diskCacheHits | $onsiteTasks | $errors | $testCount | $cachedTests |\n"
|
||||
|
||||
def report(project: String, summaries: Seq[ParsedCacheSummary]): Unit =
|
||||
summaries.foreach(s => log(s"[$project] $s"))
|
||||
def report(info: RunInfo, summaries: Seq[ParsedCacheSummary]): Unit =
|
||||
summaries.foreach(s => log(s"[${info.project}] ${info.run}: $s"))
|
||||
sys.env
|
||||
.get("GITHUB_STEP_SUMMARY")
|
||||
.filter(_ => summaries.nonEmpty)
|
||||
.foreach(p =>
|
||||
val path = Paths.get(p)
|
||||
val hasHeader = Files.exists(path) && Files.readString(path).contains(tableHeader)
|
||||
val rows = summaries.map(markdownRow(project, _)).mkString
|
||||
val rows = summaries.map(markdownRow(info, _)).mkString
|
||||
Files.writeString(
|
||||
path,
|
||||
(if hasHeader then "" else tableHeader) + rows,
|
||||
|
||||
@@ -32,6 +32,30 @@ lazy val remoteCachePluginDir: Path =
|
||||
)
|
||||
dir
|
||||
|
||||
lazy val sbt1PluginDir: Path =
|
||||
val dir = communitybuildDir.resolve("target").resolve("sbt1-plugins")
|
||||
Files.createDirectories(dir)
|
||||
Files.writeString(
|
||||
dir.resolve("plugins.sbt"),
|
||||
"""addSbtPlugin("com.eed3si9n" % "sbt-projectmatrix" % "0.11.0")
|
||||
|addSbtPlugin("com.github.sbt" % "sbt2-compat" % "0.2.0")
|
||||
|""".stripMargin,
|
||||
)
|
||||
Files.writeString(
|
||||
dir.resolve("Sbt2Shims.scala"),
|
||||
"""import sbt._
|
||||
|
|
||||
|object Sbt2Shims extends AutoPlugin {
|
||||
| override def trigger = allRequirements
|
||||
| object autoImport {
|
||||
| val allowMismatchScala = settingKey[Boolean]("sbt 2.x shim")
|
||||
| }
|
||||
|}
|
||||
|""".stripMargin,
|
||||
)
|
||||
dir
|
||||
end sbt1PluginDir
|
||||
|
||||
lazy val sbtPluginFilePath: String =
|
||||
// Workaround for https://github.com/sbt/sbt/issues/4395
|
||||
new File(sys.props("user.home") + "/config/sbt/2/plugins").mkdirs()
|
||||
@@ -65,6 +89,7 @@ enum Scenario:
|
||||
case Test
|
||||
case Build
|
||||
case TestTest(minHitRate: Double, minTestHitRate: Double = 1.0)
|
||||
case TestSbt1
|
||||
|
||||
sealed trait CommunityProject:
|
||||
def project: String
|
||||
@@ -74,6 +99,10 @@ sealed trait CommunityProject:
|
||||
def docCommand: String
|
||||
def binaryName: String
|
||||
def runCommandsArgs: List[String] = Nil
|
||||
def sbt1CommandsArgs: List[String] = Nil
|
||||
def sbt1TestCommand: String = testCommand
|
||||
def warmupCommand: Option[String] = None
|
||||
def sbt1WarmupCommand: Option[String] = None
|
||||
def environment: Map[String, String] = Map.empty
|
||||
def diskCacheDir: Option[File] = None
|
||||
def scenarioType: Scenario
|
||||
@@ -87,7 +116,7 @@ sealed trait CommunityProject:
|
||||
throw RuntimeException(
|
||||
s"Publish command is not specified for $project. Project details:\n$this"
|
||||
)
|
||||
val (exitCode, _) = execAndShutdown(runCommandsArgs :+ publishCommand)
|
||||
val (exitCode, _) = execAndShutdown(runCommandsArgs :+ publishCommand, "publish")
|
||||
if exitCode != 0 then
|
||||
throw RuntimeException(
|
||||
s"Publish command exited with code $exitCode for project $project. Project details:\n$this"
|
||||
@@ -97,7 +126,7 @@ sealed trait CommunityProject:
|
||||
log(s"Documenting $project")
|
||||
if docCommand eq null then
|
||||
throw RuntimeException(s"Doc command is not specified for $project. Project details:\n$this")
|
||||
val (exitCode, _) = execAndShutdown(runCommandsArgs :+ docCommand)
|
||||
val (exitCode, _) = execAndShutdown(runCommandsArgs :+ docCommand, "doc")
|
||||
if exitCode != 0 then
|
||||
throw RuntimeException(
|
||||
s"Doc command exited with code $exitCode for project $project. Project details:\n$this"
|
||||
@@ -107,22 +136,33 @@ sealed trait CommunityProject:
|
||||
case Scenario.Test => test()
|
||||
case Scenario.Build => build()
|
||||
case Scenario.TestTest(minHitRate, minTestHitRate) => testTest(minHitRate, minTestHitRate)
|
||||
case Scenario.TestSbt1 => testSbt1()
|
||||
|
||||
final def build(): Int = execAndShutdown(buildCommands)._1
|
||||
final def build(): Int = execAndShutdown(buildCommands, "build")._1
|
||||
|
||||
final def buildCommands = runCommandsArgs :+ testCompileCommand
|
||||
|
||||
final def test(): Int = execAndShutdown(runCommandsArgs :+ testCommand)._1
|
||||
final def test(): Int = execAndShutdown(runCommandsArgs :+ testCommand, "test")._1
|
||||
|
||||
/** Runs the tests twice using sbt 1.x. */
|
||||
final def testSbt1(): Int =
|
||||
warmup(sbt1CommandsArgs, sbt1WarmupCommand)
|
||||
val (firstExitCode, _) =
|
||||
execAndShutdown(sbt1CommandsArgs :+ sbt1TestCommand, "test (1st)", sbt1CommandsArgs)
|
||||
if firstExitCode != 0 then firstExitCode
|
||||
else execAndShutdown(sbt1CommandsArgs :+ sbt1TestCommand, "test (2nd)", sbt1CommandsArgs)._1
|
||||
|
||||
/** Runs the tests twice, and asserts the second run is served from the cache. */
|
||||
final def testTest(minHitRate: Double, minTestHitRate: Double): Int =
|
||||
val (firstExitCode, _) = execAndShutdown(runCommandsArgs :+ testCommand)
|
||||
warmup(runCommandsArgs, warmupCommand)
|
||||
val (firstExitCode, _) = execAndShutdown(runCommandsArgs :+ testCommand, "test (1st)")
|
||||
if firstExitCode != 0 then firstExitCode
|
||||
else
|
||||
diskCacheDir.foreach(wipeDirectory)
|
||||
val (exitCode, summaries) = execAndShutdown(runCommandsArgs :+ testCommand)
|
||||
val (exitCode, summaries) =
|
||||
execAndShutdown(runCommandsArgs :+ testCommand, "test (2nd, disk cache wiped)")
|
||||
assert(summaries.nonEmpty, s"no cache summary found in the second test run of $project")
|
||||
val belowThreshold = summaries.filter(_.hitRate < minHitRate)
|
||||
val belowThreshold = summaries.filter(_.hitRate.forall(_ < minHitRate))
|
||||
assert(
|
||||
belowThreshold.isEmpty,
|
||||
s"cache hit rate of the second test run of $project is below $minHitRate: $belowThreshold"
|
||||
@@ -135,13 +175,22 @@ sealed trait CommunityProject:
|
||||
s"test hit rate of the second test run of $project is below $minTestHitRate: $testsBelowThreshold"
|
||||
)
|
||||
exitCode
|
||||
end testTest
|
||||
|
||||
private def warmup(baseArgs: List[String], command: Option[String]): Unit =
|
||||
command.foreach(cmd => execAndShutdown(baseArgs :+ cmd, "warm-up", baseArgs))
|
||||
|
||||
private def wipeDirectory(dir: File): Unit =
|
||||
log(s"Wiping disk cache $dir")
|
||||
IO.delete(IO.listFiles(dir))
|
||||
|
||||
private def execAndShutdown(arguments: List[String]): (Int, List[ParsedCacheSummary]) =
|
||||
private def execAndShutdown(
|
||||
arguments: List[String],
|
||||
run: String,
|
||||
baseArgs: List[String] = runCommandsArgs,
|
||||
): (Int, List[ParsedCacheSummary]) =
|
||||
val summaries = CacheSummaryCollector()
|
||||
val start = System.nanoTime()
|
||||
val exitCode = exec(
|
||||
projectDir,
|
||||
binaryName,
|
||||
@@ -151,20 +200,31 @@ sealed trait CommunityProject:
|
||||
println(line)
|
||||
summaries.add(line)
|
||||
)
|
||||
exec(projectDir, binaryName, runCommandsArgs :+ "shutdown", environment)
|
||||
val commandEnd = System.nanoTime()
|
||||
exec(projectDir, binaryName, baseArgs :+ "shutdown", environment)
|
||||
val shutdownEnd = System.nanoTime()
|
||||
val wallClockSeconds = (commandEnd - start) / 1e9
|
||||
log(
|
||||
f"[$project] $run wall clock: $wallClockSeconds%.1f s command, ${(shutdownEnd - commandEnd) / 1e9}%.1f s shutdown"
|
||||
)
|
||||
val sbtVersionUsed = baseArgs.collectFirst { case s"-Dsbt.version=$v" => v }.getOrElse("")
|
||||
val result = summaries.result()
|
||||
ParsedCacheSummary.report(project, result)
|
||||
ParsedCacheSummary.report(RunInfo(project, run, sbtVersionUsed, wallClockSeconds), result)
|
||||
(exitCode, result)
|
||||
end execAndShutdown
|
||||
|
||||
end CommunityProject
|
||||
|
||||
val sbt1Version = "1.12.1"
|
||||
val sbt1Version = "1.13.0"
|
||||
val sbt2Version = "2.0.3"
|
||||
|
||||
final case class SbtCommunityProject(
|
||||
project: String,
|
||||
testCmd: String = "test",
|
||||
testCompileCmd: String = "Test/compile",
|
||||
sbt1TestCmd: Option[String] = None,
|
||||
warmupCmd: Option[String] = None,
|
||||
sbt1WarmupCmd: Option[String] = None,
|
||||
extraSbtArgs: List[String] = Nil,
|
||||
publishCmd: String = "publishLocal",
|
||||
docCmd: String = "doc",
|
||||
@@ -178,13 +238,19 @@ final case class SbtCommunityProject(
|
||||
scalacOptions.map("\"" + _ + "\"").mkString("List(", ",", ")")
|
||||
|
||||
private val baseCommand =
|
||||
"set Global/logLevel := Level.Error; "
|
||||
++ (if scalacOptions.isEmpty then ""
|
||||
else s"""set Global/scalacOptions ++= $scalacOptionsString;""")
|
||||
(if scalacOptions.isEmpty then ""
|
||||
else s"""set Global/scalacOptions ++= $scalacOptionsString;""")
|
||||
|
||||
override val testCommand =
|
||||
"""set Global/testOptions += Tests.Argument(TestFramework("munit.Framework"), "+l"); """
|
||||
++ s"$baseCommand$testCmd"
|
||||
private def mkTestCommand(cmd: String): String =
|
||||
s"$baseCommand$cmd"
|
||||
|
||||
override val testCommand = mkTestCommand(testCmd)
|
||||
|
||||
override def sbt1TestCommand: String = sbt1TestCmd.fold(testCommand)(mkTestCommand)
|
||||
|
||||
override def warmupCommand: Option[String] = warmupCmd
|
||||
|
||||
override def sbt1WarmupCommand: Option[String] = sbt1WarmupCmd
|
||||
|
||||
override val testCompileCommand =
|
||||
s"$baseCommand$testCompileCmd"
|
||||
@@ -202,11 +268,21 @@ final case class SbtCommunityProject(
|
||||
|
||||
override def diskCacheDir: Option[File] = Some(localCacheDir)
|
||||
|
||||
private val sbtProps: List[String] = Option(System.getProperty("sbt.ivy.home")) match
|
||||
case Some(ivyHome) => List(s"-Dsbt.ivy.home=$ivyHome")
|
||||
case _ => Nil
|
||||
|
||||
override val sbt1CommandsArgs: List[String] =
|
||||
extraSbtArgs ++ sbtProps ++ List(
|
||||
s"-Dsbt.global.plugins=$sbt1PluginDir",
|
||||
s"-Dsbt.version=$sbt1Version",
|
||||
s"-Dsbt.boot=$bootDir",
|
||||
"-Dsbt.supershell=false",
|
||||
"--error",
|
||||
)
|
||||
|
||||
override val runCommandsArgs: List[String] =
|
||||
// Run the sbt command with the compiler version and sbt plugin set in the build
|
||||
val sbtProps = Option(System.getProperty("sbt.ivy.home")) match
|
||||
case Some(ivyHome) => List(s"-Dsbt.ivy.home=$ivyHome")
|
||||
case _ => Nil
|
||||
val remoteCacheProps = SbtCommunityProject.remoteCache.toList.flatMap(uri =>
|
||||
List(
|
||||
s"-Dsbt.global.plugins=$remoteCachePluginDir",
|
||||
@@ -218,6 +294,7 @@ final case class SbtCommunityProject(
|
||||
s"-Dsbt.boot=$bootDir",
|
||||
s"-Dsbt.global.localcache=$localCacheDir",
|
||||
"-Dsbt.supershell=false",
|
||||
"--error",
|
||||
)
|
||||
end SbtCommunityProject
|
||||
|
||||
@@ -265,10 +342,17 @@ object projects:
|
||||
project = "chimney",
|
||||
testCmd = all(chimneyJvmProjects.map(p => s"$p/test")*),
|
||||
testCompileCmd = all(chimneyJvmProjects.map(p => s"$p/Test/compile")*),
|
||||
warmupCmd = Some(all(chimneyJvmProjects.map(p => s"$p/update")*)),
|
||||
environment = Map("_JAVA_OPTIONS" -> "-Xmx2g"),
|
||||
scenarioType = Scenario.TestTest(minHitRate = 0.9),
|
||||
)
|
||||
|
||||
lazy val `chimney-sbt1` = chimney.copy(
|
||||
sbt1TestCmd = Some(all(chimneyJvmProjects.map(p => s"${p}3/test")*)),
|
||||
sbt1WarmupCmd = Some(all(chimneyJvmProjects.map(p => s"${p}3/update")*)),
|
||||
scenarioType = Scenario.TestSbt1,
|
||||
)
|
||||
|
||||
lazy val `sbt-compile-benchmark` = SbtCommunityProject(
|
||||
project = "sbt-compile-benchmark",
|
||||
scenarioType = Scenario.Build,
|
||||
|
||||
@@ -16,6 +16,7 @@ given testRunner: CommunityBuildRunner with
|
||||
|
||||
@Category(Array(classOf[TestCategory]))
|
||||
class CommunityBuildTestA:
|
||||
@Test def `chimney-sbt1` = projects.`chimney-sbt1`.run()
|
||||
@Test def chimney = projects.chimney.run()
|
||||
end CommunityBuildTestA
|
||||
|
||||
|
||||
+48
-14
@@ -11,27 +11,41 @@ class ParsedCacheSummaryTest:
|
||||
val summary = ParsedCacheSummary.parse(
|
||||
"[success] elapsed time: 4 s, cache 100%, 191 remote cache hits, 8 disk cache hits"
|
||||
)
|
||||
assert(summary == Some(ParsedCacheSummary(true, 4, 1.0, 191, 8, 0, 0)))
|
||||
assert(summary == Some(ParsedCacheSummary(true, 4, Some(1.0), 191, 8, 0, 0)))
|
||||
|
||||
@Test def parseSingularCountsAndDuration(): Unit =
|
||||
val summary = ParsedCacheSummary.parse(
|
||||
"[success] elapsed time: 74 s (0:01:14.0), cache 58%, 1 disk cache hit, 13 onsite tasks"
|
||||
)
|
||||
assert(summary == Some(ParsedCacheSummary(true, 74, 0.58, 0, 1, 13, 0)))
|
||||
assert(summary == Some(ParsedCacheSummary(true, 74, Some(0.58), 0, 1, 13, 0)))
|
||||
|
||||
@Test def parseErrors(): Unit =
|
||||
val summary = ParsedCacheSummary.parse(
|
||||
"[error] elapsed time: 9 s, cache 91%, 1624 disk cache hits, 157 onsite tasks, 35 errors"
|
||||
)
|
||||
assert(summary == Some(ParsedCacheSummary(false, 9, 0.91, 0, 1624, 157, 35)))
|
||||
assert(summary == Some(ParsedCacheSummary(false, 9, Some(0.91), 0, 1624, 157, 35)))
|
||||
|
||||
@Test def ignoreLinesWithoutCache(): Unit =
|
||||
assert(ParsedCacheSummary.parse("[success] elapsed time: 18 s").isEmpty)
|
||||
@Test def parseElapsedWithoutCache(): Unit =
|
||||
val summary = ParsedCacheSummary.parse("[success] elapsed time: 5 s")
|
||||
assert(summary == Some(ParsedCacheSummary(true, 5, None, 0, 0, 0, 0)))
|
||||
|
||||
@Test def ignoreLinesWithoutElapsed(): Unit =
|
||||
assert(ParsedCacheSummary.parse("[info] compiling 3 Scala sources").isEmpty)
|
||||
|
||||
@Test def markdownRow(): Unit =
|
||||
val row = ParsedCacheSummary.markdownRow("scalaz", ParsedCacheSummary(true, 4, 1.0, 191, 8, 0, 0))
|
||||
assert(row == "| `scalaz` | success | 4s | 100% | 191 | 8 | 0 | 0 | | |\n")
|
||||
val info = RunInfo("scalaz", "build", "2.1.0-SNAPSHOT", 12.34)
|
||||
val row =
|
||||
ParsedCacheSummary.markdownRow(info, ParsedCacheSummary(true, 4, Some(1.0), 191, 8, 0, 0))
|
||||
assert(
|
||||
row == "| `scalaz` | build | 2.1.0-SNAPSHOT | success | 12.3s | 4s | 100% | 191 | 8 | 0 | 0 | | |\n"
|
||||
)
|
||||
|
||||
@Test def markdownRowWithoutCache(): Unit =
|
||||
val info = RunInfo("chimney", "test (2nd)", "1.13.0", 9.5)
|
||||
val row = ParsedCacheSummary.markdownRow(info, ParsedCacheSummary(true, 5, None, 0, 0, 0, 0))
|
||||
assert(
|
||||
row == "| `chimney` | test (2nd) | 1.13.0 | success | 9.5s | 5s | | 0 | 0 | 0 | 0 | | |\n"
|
||||
)
|
||||
|
||||
@Test def tableHeaderLines(): Unit =
|
||||
val lines = ParsedCacheSummary.tableHeader.linesIterator.toList
|
||||
@@ -39,11 +53,13 @@ class ParsedCacheSummaryTest:
|
||||
assert(lines.forall(line => line.startsWith("|") && line.endsWith("|")))
|
||||
|
||||
@Test def parseTestSummary(): Unit =
|
||||
val tests = ParsedTestSummary.parse("[info] passed: total 94, failed 0, errors 0, passed 94, cached 94")
|
||||
val tests =
|
||||
ParsedTestSummary.parse("[info] passed: total 94, failed 0, errors 0, passed 94, cached 94")
|
||||
assert(tests == Some(ParsedTestSummary(94, 0, 0, 94, 94)))
|
||||
|
||||
@Test def parseFailedTestSummary(): Unit =
|
||||
val tests = ParsedTestSummary.parse("[error] failed: total 1, failed 1, errors 0, passed 0, cached 0")
|
||||
val tests =
|
||||
ParsedTestSummary.parse("[error] failed: total 1, failed 1, errors 0, passed 0, cached 0")
|
||||
assert(tests == Some(ParsedTestSummary(1, 1, 0, 0, 0)))
|
||||
|
||||
@Test def collectorAttachesPrecedingTestSummary(): Unit =
|
||||
@@ -51,20 +67,38 @@ class ParsedCacheSummaryTest:
|
||||
List(
|
||||
"[info] passed: total 94, failed 0, errors 0, passed 94, cached 94",
|
||||
"[success] elapsed time: 5 s, cache 93%, 126 remote cache hits, 21 disk cache hits, 10 onsite tasks",
|
||||
"[success] elapsed time: 5 s",
|
||||
"[success] elapsed time: 1 s, cache 100%, 3 disk cache hits",
|
||||
).foreach(collector.add)
|
||||
val tests = Some(ParsedTestSummary(94, 0, 0, 94, 94))
|
||||
assert(
|
||||
collector.result() == List(
|
||||
ParsedCacheSummary(true, 5, 0.93, 126, 21, 10, 0, tests),
|
||||
ParsedCacheSummary(true, 1, 1.0, 0, 3, 0, 0, None),
|
||||
ParsedCacheSummary(true, 5, Some(0.93), 126, 21, 10, 0, tests),
|
||||
ParsedCacheSummary(true, 1, Some(1.0), 0, 3, 0, 0, None),
|
||||
)
|
||||
)
|
||||
|
||||
@Test def collectorFallsBackToElapsedOnly(): Unit =
|
||||
val collector = CacheSummaryCollector()
|
||||
List("[info] compiling 3 Scala sources", "[success] elapsed time: 5 s").foreach(collector.add)
|
||||
assert(collector.result() == List(ParsedCacheSummary(true, 5, None, 0, 0, 0, 0)))
|
||||
|
||||
@Test def markdownRowWithTests(): Unit =
|
||||
val summary = ParsedCacheSummary(true, 5, 0.93, 126, 21, 10, 0, Some(ParsedTestSummary(94, 0, 0, 94, 94)))
|
||||
val row = ParsedCacheSummary.markdownRow("chimney", summary)
|
||||
assert(row == "| `chimney` | success | 5s | 93% | 126 | 21 | 10 | 0 | 94 | 94 |\n")
|
||||
val info = RunInfo("chimney", "test (1st)", "2.1.0-SNAPSHOT", 9.7)
|
||||
val summary = ParsedCacheSummary(
|
||||
true,
|
||||
5,
|
||||
Some(0.93),
|
||||
126,
|
||||
21,
|
||||
10,
|
||||
0,
|
||||
Some(ParsedTestSummary(94, 0, 0, 94, 94)),
|
||||
)
|
||||
val row = ParsedCacheSummary.markdownRow(info, summary)
|
||||
assert(
|
||||
row == "| `chimney` | test (1st) | 2.1.0-SNAPSHOT | success | 9.7s | 5s | 93% | 126 | 21 | 10 | 0 | 94 | 94 |\n"
|
||||
)
|
||||
|
||||
@Test def testHitRate(): Unit =
|
||||
assert(ParsedTestSummary(94, 0, 0, 94, 94).testHitRate == 1.0)
|
||||
|
||||
Reference in New Issue
Block a user