Skip to content

Commit f709ae9

Browse files
committed
Make sure that everything is dumped to log files
1 parent 8e58264 commit f709ae9

File tree

3 files changed

+120
-57
lines changed

3 files changed

+120
-57
lines changed

compiler/test/dotty/tools/dotc/reporting/TestReporter.scala

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M
2323
final def errors: Iterator[MessageContainer] = _errorBuf.iterator
2424

2525
protected final val _messageBuf = mutable.ArrayBuffer.empty[String]
26+
final def messages: Iterator[String] = _messageBuf.iterator
27+
28+
private[this] var _didCrash = false
29+
final def compilerCrashed: Boolean = _didCrash
2630

2731
final def flushToFile(): Unit =
2832
_messageBuf
@@ -33,7 +37,6 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M
3337
final def flushToStdErr(): Unit =
3438
_messageBuf
3539
.iterator
36-
.map(_.replaceAll("\u001b\\[.*?m", ""))
3740
.foreach(System.err.println)
3841

3942
final def inlineInfo(pos: SourcePosition): String =
@@ -44,9 +47,17 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M
4447
}
4548
else ""
4649

47-
def echo(msg: String) =
50+
def log(msg: String) =
4851
_messageBuf.append(msg)
4952

53+
def logStackTrace(thrown: Throwable): Unit = {
54+
_didCrash = true
55+
val sw = new java.io.StringWriter
56+
val pw = new java.io.PrintWriter(sw)
57+
thrown.printStackTrace(pw)
58+
log(sw.toString)
59+
}
60+
5061
/** Prints the message with the given position indication. */
5162
def printMessageAndPos(m: MessageContainer, extra: String)(implicit ctx: Context): Unit = {
5263
val msg = messageAndPos(m.contained, m.pos, diagnosticLevel(m))
@@ -73,15 +84,14 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M
7384
_errorBuf.append(m)
7485
printMessageAndPos(m, extra)
7586
}
76-
case w: Warning =>
77-
printMessageAndPos(w, extra)
78-
case _ =>
87+
case m =>
88+
printMessageAndPos(m, extra)
7989
}
8090
}
8191
}
8292

8393
object TestReporter {
84-
private[this] lazy val logWriter = {
94+
lazy val logWriter = {
8595
val df = new SimpleDateFormat("yyyy-MM-dd-HH:mm")
8696
val timestamp = df.format(new Date)
8797
new JFile("../testlogs").mkdirs()

compiler/test/dotty/tools/vulpix/ParallelTesting.scala

Lines changed: 97 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,39 @@ trait ParallelTesting extends RunnerOrchestration { self =>
183183
/** Each `Test` takes the `testSources` and performs the compilation and assertions
184184
* according to the implementing class "neg", "run" or "pos".
185185
*/
186-
private abstract class Test(testSources: List[TestSource], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean) {
186+
private abstract class Test(testSources: List[TestSource], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean) { test =>
187187
protected final val realStdout = System.out
188188
protected final val realStderr = System.err
189189

190+
/** A runnable that logs its contents in a buffer */
191+
trait LoggedRunnable extends Runnable {
192+
import TestReporter.logWriter
193+
194+
/** Instances of `LoggedRunnable` implement this method instead of the
195+
* `run` method
196+
*/
197+
def checkTestSource(): Unit
198+
199+
private[this] val logBuffer = mutable.ArrayBuffer.empty[String]
200+
def log(msg: String): Unit = logBuffer.append(msg)
201+
202+
def logReporterContents(reporter: TestReporter): Unit =
203+
reporter.messages.foreach(log)
204+
205+
def echo(msg: String): Unit = {
206+
log(msg)
207+
test.echo(msg)
208+
}
209+
210+
final def run(): Unit = {
211+
checkTestSource()
212+
logBuffer.iterator.foreach(logWriter.println)
213+
logWriter.flush()
214+
}
215+
}
216+
190217
/** Actual compilation run logic, the test behaviour is defined here */
191-
protected def compilationRunnable(testSource: TestSource): Runnable
218+
protected def encapsulatedCompilation(testSource: TestSource): LoggedRunnable
192219

193220
/** All testSources left after filtering out */
194221
private val filteredSources =
@@ -220,7 +247,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
220247
protected[this] final def fail(): Unit = synchronized { _failed = true }
221248
def didFail: Boolean = _failed
222249

223-
protected def echoBuildInstructions(reporter: TestReporter, testSource: TestSource, err: Int, war: Int) = {
250+
protected def logBuildInstructions(reporter: TestReporter, testSource: TestSource, err: Int, war: Int) = {
224251
val errorMsg = testSource.buildInstructions(reporter.errorCount, reporter.warningCount)
225252
addFailureInstruction(errorMsg)
226253
failTestSource(testSource)
@@ -278,7 +305,9 @@ trait ParallelTesting extends RunnerOrchestration { self =>
278305
*/
279306
protected def tryCompile(testSource: TestSource)(op: => Unit): Unit =
280307
try {
281-
if (!isInteractive) realStdout.println(s"Testing ${testSource.title}")
308+
val testing = s"Testing ${testSource.title}"
309+
TestReporter.logWriter.println(testing)
310+
if (!isInteractive) realStdout.println(testing)
282311
op
283312
} catch {
284313
case NonFatal(e) => {
@@ -342,10 +371,17 @@ trait ParallelTesting extends RunnerOrchestration { self =>
342371
}
343372

344373
val allArgs = addOutDir(flags)
345-
driver.process(allArgs ++ files.map(_.getAbsolutePath), reporter = reporter)
346374

347-
val javaFiles = files.filter(_.getName.endsWith(".java")).map(_.getAbsolutePath)
348-
assert(compileWithJavac(javaFiles), s"java compilation failed for ${javaFiles.mkString(", ")}")
375+
// Compile with a try to catch any StackTrace generated by the compiler:
376+
try {
377+
driver.process(allArgs ++ files.map(_.getAbsolutePath), reporter = reporter)
378+
379+
val javaFiles = files.filter(_.getName.endsWith(".java")).map(_.getAbsolutePath)
380+
assert(compileWithJavac(javaFiles), s"java compilation failed for ${javaFiles.mkString(", ")}")
381+
}
382+
catch {
383+
case NonFatal(ex) => reporter.logStackTrace(ex)
384+
}
349385

350386
reporter
351387
}
@@ -362,7 +398,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
362398
if (isInteractive && !suppressAllOutput) pool.submit(createProgressMonitor)
363399

364400
filteredSources.foreach { target =>
365-
pool.submit(compilationRunnable(target))
401+
pool.submit(encapsulatedCompilation(target))
366402
}
367403

368404
pool.shutdown()
@@ -392,22 +428,25 @@ trait ParallelTesting extends RunnerOrchestration { self =>
392428

393429
private final class PosTest(testSources: List[TestSource], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean)
394430
extends Test(testSources, times, threadLimit, suppressAllOutput) {
395-
protected def compilationRunnable(testSource: TestSource): Runnable = new Runnable {
396-
def run(): Unit = tryCompile(testSource) {
431+
protected def encapsulatedCompilation(testSource: TestSource) = new LoggedRunnable {
432+
def checkTestSource(): Unit = tryCompile(testSource) {
397433
testSource match {
398434
case testSource @ JointCompilationSource(_, files, flags, outDir) => {
399435
val reporter = compile(testSource.sourceFiles, flags, false, outDir)
400436
registerCompletion(reporter.errorCount)
401437

402-
if (reporter.errorCount > 0)
403-
echoBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
438+
if (reporter.compilerCrashed || reporter.errorCount > 0) {
439+
logReporterContents(reporter)
440+
logBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
441+
}
404442
}
405443

406444
case testSource @ SeparateCompilationSource(_, dir, flags, outDir) => {
407445
val reporters = testSource.compilationGroups.map(files => compile(files, flags, false, outDir))
446+
val compilerCrashed = reporters.exists(_.compilerCrashed)
408447
val errorCount = reporters.foldLeft(0) { (acc, reporter) =>
409448
if (reporter.errorCount > 0)
410-
echoBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
449+
logBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
411450

412451
acc + reporter.errorCount
413452
}
@@ -416,8 +455,10 @@ trait ParallelTesting extends RunnerOrchestration { self =>
416455

417456
registerCompletion(errorCount)
418457

419-
if (errorCount > 0)
420-
echoBuildInstructions(reporters.head, testSource, errorCount, warningCount)
458+
if (compilerCrashed || errorCount > 0) {
459+
reporters.foreach(logReporterContents)
460+
logBuildInstructions(reporters.head, testSource, errorCount, warningCount)
461+
}
421462
}
422463
}
423464
}
@@ -483,9 +524,9 @@ trait ParallelTesting extends RunnerOrchestration { self =>
483524
}
484525
}
485526

486-
protected def compilationRunnable(testSource: TestSource): Runnable = new Runnable {
487-
def run(): Unit = tryCompile(testSource) {
488-
val (errorCount, warningCount, hasCheckFile, verifier: Function0[Unit]) = testSource match {
527+
protected def encapsulatedCompilation(testSource: TestSource) = new LoggedRunnable {
528+
def checkTestSource(): Unit = tryCompile(testSource) {
529+
val (compilerCrashed, errorCount, warningCount, hasCheckFile, verifier: Function0[Unit]) = testSource match {
489530
case testSource @ JointCompilationSource(_, files, flags, outDir) => {
490531
val checkFile = files.flatMap { file =>
491532
if (file.isDirectory) Nil
@@ -498,33 +539,37 @@ trait ParallelTesting extends RunnerOrchestration { self =>
498539
}.headOption
499540
val reporter = compile(testSource.sourceFiles, flags, false, outDir)
500541

501-
if (reporter.errorCount > 0)
502-
echoBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
542+
if (reporter.compilerCrashed || reporter.errorCount > 0) {
543+
logReporterContents(reporter)
544+
logBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
545+
}
503546

504-
(reporter.errorCount, reporter.warningCount, checkFile.isDefined, () => verifyOutput(checkFile.get, outDir, testSource, reporter.warningCount))
547+
(reporter.compilerCrashed, reporter.errorCount, reporter.warningCount, checkFile.isDefined, () => verifyOutput(checkFile.get, outDir, testSource, reporter.warningCount))
505548
}
506549

507550
case testSource @ SeparateCompilationSource(_, dir, flags, outDir) => {
508551
val checkFile = new JFile(dir.getAbsolutePath.reverse.dropWhile(_ == '/').reverse + ".check")
552+
val reporters = testSource.compilationGroups.map(compile(_, flags, false, outDir))
553+
val compilerCrashed = reporters.exists(_.compilerCrashed)
509554
val (errorCount, warningCount) =
510-
testSource
511-
.compilationGroups
512-
.map(compile(_, flags, false, outDir))
513-
.foldLeft((0,0)) { case ((errors, warnings), reporter) =>
514-
if (reporter.errorCount > 0)
515-
echoBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
555+
reporters.foldLeft((0,0)) { case ((errors, warnings), reporter) =>
556+
if (reporter.errorCount > 0)
557+
logBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
516558

517-
(errors + reporter.errorCount, warnings + reporter.warningCount)
518-
}
559+
(errors + reporter.errorCount, warnings + reporter.warningCount)
560+
}
519561

520-
if (errorCount > 0) fail()
562+
if (errorCount > 0) {
563+
reporters.foreach(logReporterContents)
564+
logBuildInstructions(reporters.head, testSource, errorCount, warningCount)
565+
}
521566

522-
(errorCount, warningCount, checkFile.exists, () => verifyOutput(checkFile, outDir, testSource, warningCount))
567+
(compilerCrashed, errorCount, warningCount, checkFile.exists, () => verifyOutput(checkFile, outDir, testSource, warningCount))
523568
}
524569
}
525570

526-
if (errorCount == 0 && hasCheckFile) verifier()
527-
else if (errorCount == 0) {
571+
if (!compilerCrashed && errorCount == 0 && hasCheckFile) verifier()
572+
else if (!compilerCrashed && errorCount == 0) {
528573
if (Properties.testsNoRun) addNoRunWarning()
529574
else runMain(testSource.classPath) match {
530575
case Success(_) => // success!
@@ -537,26 +582,21 @@ trait ParallelTesting extends RunnerOrchestration { self =>
537582
failTestSource(testSource, Some("test timed out"))
538583
}
539584
}
540-
else if (errorCount > 0) {
585+
else {
541586
echo(s"\n Compilation failed for: '$testSource'")
542587
val buildInstr = testSource.buildInstructions(errorCount, warningCount)
543588
addFailureInstruction(buildInstr)
544589
failTestSource(testSource)
545590
}
546-
else {
547-
realStdout.println("Got a super weird error that I haven't handled yet")
548-
realStdout.println("errorCount: " + errorCount)
549-
realStdout.println("test: " + testSource.title + " " + testSource.name)
550-
}
551591
registerCompletion(errorCount)
552592
}
553593
}
554594
}
555595

556596
private final class NegTest(testSources: List[TestSource], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean)
557597
extends Test(testSources, times, threadLimit, suppressAllOutput) {
558-
protected def compilationRunnable(testSource: TestSource): Runnable = new Runnable {
559-
def run(): Unit = tryCompile(testSource) {
598+
protected def encapsulatedCompilation(testSource: TestSource) = new LoggedRunnable {
599+
def checkTestSource(): Unit = tryCompile(testSource) {
560600
// In neg-tests we allow two types of error annotations,
561601
// "nopos-error" which doesn't care about position and "error" which
562602
// has to be annotated on the correct line number.
@@ -608,27 +648,39 @@ trait ParallelTesting extends RunnerOrchestration { self =>
608648
}
609649
}
610650

611-
val (expectedErrors, actualErrors, hasMissingAnnotations, errorMap) = testSource match {
651+
val (compilerCrashed, expectedErrors, actualErrors, hasMissingAnnotations, errorMap) = testSource match {
612652
case testSource @ JointCompilationSource(_, files, flags, outDir) => {
613653
val sourceFiles = testSource.sourceFiles
614654
val (errorMap, expectedErrors) = getErrorMapAndExpectedCount(sourceFiles)
615655
val reporter = compile(sourceFiles, flags, true, outDir)
616656
val actualErrors = reporter.errorCount
617657

618-
(expectedErrors, actualErrors, () => getMissingExpectedErrors(errorMap, reporter.errors), errorMap)
658+
if (reporter.compilerCrashed || actualErrors > 0)
659+
logReporterContents(reporter)
660+
661+
(reporter.compilerCrashed, expectedErrors, actualErrors, () => getMissingExpectedErrors(errorMap, reporter.errors), errorMap)
619662
}
620663

621664
case testSource @ SeparateCompilationSource(_, dir, flags, outDir) => {
622665
val compilationGroups = testSource.compilationGroups
623666
val (errorMap, expectedErrors) = getErrorMapAndExpectedCount(compilationGroups.toArray.flatten)
624667
val reporters = compilationGroups.map(compile(_, flags, true, outDir))
668+
val compilerCrashed = reporters.exists(_.compilerCrashed)
625669
val actualErrors = reporters.foldLeft(0)(_ + _.errorCount)
626670
val errors = reporters.iterator.flatMap(_.errors)
627-
(expectedErrors, actualErrors, () => getMissingExpectedErrors(errorMap, errors), errorMap)
671+
672+
if (actualErrors > 0)
673+
reporters.foreach(logReporterContents)
674+
675+
(compilerCrashed, expectedErrors, actualErrors, () => getMissingExpectedErrors(errorMap, errors), errorMap)
628676
}
629677
}
630678

631-
if (expectedErrors != actualErrors) {
679+
if (compilerCrashed) {
680+
echo(s"Compiler crashed when compiling: ${testSource.title}")
681+
failTestSource(testSource)
682+
}
683+
else if (expectedErrors != actualErrors) {
632684
echo {
633685
s"\nWrong number of errors encountered when compiling $testSource, expected: $expectedErrors, actual: $actualErrors\n"
634686
}

compiler/test/dotty/tools/vulpix/SummaryReport.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.junit.BeforeClass;
44
import org.junit.AfterClass;
5+
import java.util.Iterator;
56
import java.util.ArrayDeque;
67
import java.util.function.Supplier;
78
import scala.Function0;
@@ -75,7 +76,7 @@ public final static void addCleanup(Function0<Unit> func) {
7576
}
7677

7778
@AfterClass public final static void teardown() {
78-
rep.echo(
79+
rep.log(
7980
"\n================================================================================" +
8081
"\nTest Report" +
8182
"\n================================================================================" +
@@ -86,26 +87,26 @@ public final static void addCleanup(Function0<Unit> func) {
8687

8788
startingMessages
8889
.stream()
89-
.forEach(rep::echo);
90+
.forEach(rep::log);
9091

9192
failedTests
9293
.stream()
9394
.map(x -> " " + x)
94-
.forEach(rep::echo);
95+
.forEach(rep::log);
9596

9697
// If we're compiling locally, we don't need reproduce instructions
9798
if (isInteractive) rep.flushToStdErr();
9899

99-
rep.echo("");
100+
rep.log("");
100101

101102
reproduceInstructions
102103
.stream()
103-
.forEach(rep::echo);
104+
.forEach(rep::log);
104105

105106
// If we're on the CI, we want everything
106107
if (!isInteractive) rep.flushToStdErr();
107108

108-
if (failed > 0) rep.flushToFile();
109+
rep.flushToFile();
109110

110111
// Perform cleanup callback:
111112
if (cleanup != null) cleanup.get();

0 commit comments

Comments
 (0)