Skip to content

Commit

Permalink
Log exceptions to files in same directory of the test
Browse files Browse the repository at this point in the history
  • Loading branch information
slinkydeveloper committed Aug 7, 2024
1 parent bf07e17 commit f1c1cb2
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 33 deletions.
110 changes: 79 additions & 31 deletions src/main/kotlin/dev/restate/sdktesting/junit/ExecutionResult.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ import com.github.ajalt.mordant.rendering.TextColors.red
import com.github.ajalt.mordant.rendering.TextStyles.bold
import com.github.ajalt.mordant.terminal.Terminal
import java.io.PrintWriter
import java.lang.IllegalStateException
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
import java.util.*
import kotlin.jvm.optionals.getOrNull
import kotlin.math.min
import kotlin.time.TimeSource
import org.junit.platform.engine.support.descriptor.ClassSource
import org.junit.platform.engine.support.descriptor.MethodSource
import org.junit.platform.launcher.TestIdentifier
import org.junit.platform.launcher.TestPlan

Expand All @@ -37,8 +42,9 @@ class ExecutionResult(

companion object {
private const val TAB = " "
private const val DOUBLE_TAB = TAB + TAB
private const val DEFAULT_MAX_STACKTRACE_LINES = 15
private const val DEFAULT_MAX_STACKTRACE_LINES_TERMINAL = 15
private const val DEFAULT_MAX_STACKTRACE_LINES_FILE = 1000
private const val TEST_EXCEPTIONS_FILE = "test-exceptions.log"

private const val CAUSED_BY = "Caused by: "
private const val SUPPRESSED = "Suppressed: "
Expand Down Expand Up @@ -86,52 +92,94 @@ class ExecutionResult(
.trimIndent())
}

fun printFailuresTo(terminal: Terminal, maxStackTraceLines: Int = DEFAULT_MAX_STACKTRACE_LINES) {

fun printFailuresToTerminal(
terminal: Terminal,
maxStackTraceLines: Int = DEFAULT_MAX_STACKTRACE_LINES_TERMINAL
) {
val classesFailures =
this.classesResults.toList().filter { it.second is Aborted || it.second is Failed }
val testsFailures =
this.testResults.toList().filter { it.second is Aborted || it.second is Failed }

fun printFailures(failureList: List<Pair<TestIdentifier, TestResult>>) {
for (failure in failureList) {
terminal.println("$TAB${describeTestIdentifier(testSuite, testPlan, failure.first)}")
describeTestIdentifierSource(terminal, failure.first)
when (failure.second) {
Aborted -> terminal.println("${DOUBLE_TAB}=> ABORTED")
is Failed -> {
val throwable = (failure.second as Failed).throwable
if (throwable == null) {
terminal.println("${DOUBLE_TAB}=> UNKNOWN FAILURE")
} else {
terminal.println("$DOUBLE_TAB=> $throwable")
printStackTrace(PrintWriter(System.out), throwable, maxStackTraceLines)
}
}
Succeeded -> throw IllegalStateException()
}
}
}

if (classesFailures.isEmpty() && testsFailures.isEmpty()) {
return
}

terminal.println((red + bold)("== '$testSuite' FAILURES"))

val writer = PrintWriter(System.out)
if (classesFailures.isNotEmpty()) {
terminal.println("Classes initialization failures ${red(classesFailures.size.toString())}:")
printFailures(classesFailures)
for (failure in classesFailures) {
printFailure(writer, failure.first, failure.second, maxStackTraceLines)
}
}

if (testsFailures.isNotEmpty()) {
terminal.println("Test failures ${red(testsFailures.size.toString())}:")
printFailures(testsFailures)
for (failure in testsFailures) {
printFailure(writer, failure.first, failure.second, maxStackTraceLines)
}
}
}

fun printFailuresToFiles(
baseReportDir: Path,
maxStackTraceLines: Int = DEFAULT_MAX_STACKTRACE_LINES_FILE
) {
val reportDir = baseReportDir.resolve(testSuite)

val classesFailures =
this.classesResults.toList().filter { it.second is Aborted || it.second is Failed }
val testsFailures =
this.testResults.toList().filter { it.second is Aborted || it.second is Failed }

for (f in classesFailures) {
val clzSimpleName = classSimpleName((f.first.source.getOrNull() as ClassSource).className)
Files.newBufferedWriter(
reportDir.resolve(clzSimpleName).resolve(TEST_EXCEPTIONS_FILE),
StandardOpenOption.WRITE,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND)
.use { printFailure(PrintWriter(it), f.first, f.second, maxStackTraceLines) }
}

for (f in testsFailures) {
// Resolve class name first
val clzSimpleName = classSimpleName((f.first.source.getOrNull() as MethodSource).className)
Files.newBufferedWriter(
reportDir.resolve(clzSimpleName).resolve(TEST_EXCEPTIONS_FILE),
StandardOpenOption.WRITE,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND)
.use { printFailure(PrintWriter(it), f.first, f.second, maxStackTraceLines) }
}
}

private fun printFailure(
printWriter: PrintWriter,
testIdentifier: TestIdentifier,
result: TestResult,
maxStackTraceLines: Int
) {
printWriter.println(describeTestIdentifier(testSuite, testPlan, testIdentifier))
describeTestIdentifierSource(printWriter, testIdentifier)
when (result) {
Aborted -> printWriter.println("${TAB}=> ABORTED")
is Failed -> {
val throwable = result.throwable
if (throwable == null) {
printWriter.println("${TAB}=> UNKNOWN FAILURE")
} else {
printWriter.println("$TAB=> $throwable")
printStackTrace(printWriter, throwable, maxStackTraceLines)
}
}
Succeeded -> {}
}
}

private fun describeTestIdentifierSource(terminal: Terminal, testIdentifier: TestIdentifier) {
testIdentifier.source.ifPresent { terminal.println("${DOUBLE_TAB}$it") }
private fun describeTestIdentifierSource(writer: PrintWriter, testIdentifier: TestIdentifier) {
testIdentifier.source.ifPresent { writer.println("${TAB}$it") }
}

private fun printStackTrace(writer: PrintWriter, throwable: Throwable, max: Int) {
Expand All @@ -140,7 +188,7 @@ class ExecutionResult(
(throwable.suppressed != null && throwable.suppressed.size > 0)) {
max = max / 2
}
printStackTrace(writer, arrayOf(), throwable, "", DOUBLE_TAB + " ", HashSet(), max)
printStackTrace(writer, arrayOf(), throwable, "", TAB + " ", HashSet(), max)
writer.flush()
}

Expand Down
4 changes: 4 additions & 0 deletions src/main/kotlin/dev/restate/sdktesting/junit/utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ fun describeTestIdentifier(
describeTestIdentifier(testSuite, testPlan, testPlan.getParent(identifier).getOrNull())
return "$parent => ${identifier.displayName}"
}

fun classSimpleName(clz: String): String {
return clz.substringAfterLast('.')
}
7 changes: 5 additions & 2 deletions src/main/kotlin/dev/restate/sdktesting/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ Run test suite, executing the service as container.
parallel)

reports.add(report)
// No need to wait the end of the run for this
report.printFailuresToFiles(testRunnerOptions.reportDir)
val failures = report.failedTests
if (failures.isNotEmpty() || exclusions.isNotEmpty()) {
newExclusions[testSuite.name] =
Expand Down Expand Up @@ -208,7 +210,7 @@ Run test suite, executing the service as container.
.trimIndent())

for (report in reports) {
report.printFailuresTo(terminal)
report.printFailuresToTerminal(terminal)
}

if (newFailures) {
Expand Down Expand Up @@ -260,7 +262,8 @@ Run test suite, without executing the service inside a container.

val report = testSuite.runTests(terminal, testRunnerOptions.reportDir, testFilters, true, false)

report.printFailuresTo(terminal)
report.printFailuresToTerminal(terminal)
report.printFailuresToFiles(testRunnerOptions.reportDir)

if (report.failedTests.isNotEmpty()) {
// Exit
Expand Down

0 comments on commit f1c1cb2

Please sign in to comment.