From 691160724d612925a965ad97c1ad76683681554e Mon Sep 17 00:00:00 2001 From: Evgenii Moiseenko Date: Mon, 24 Jul 2023 19:51:49 +0200 Subject: [PATCH] handle exceptions in RunTracker Signed-off-by: Evgenii Moiseenko --- .../kotlinx/lincheck/LincheckOptions.kt | 2 +- .../jetbrains/kotlinx/lincheck/RunTracker.kt | 83 ++++++++++++------- .../jetbrains/kotlinx/lincheck/Statistics.kt | 4 +- .../lincheck_test/AbstractLincheckTest.kt | 2 +- 4 files changed, 58 insertions(+), 33 deletions(-) diff --git a/src/jvm/main/org/jetbrains/kotlinx/lincheck/LincheckOptions.kt b/src/jvm/main/org/jetbrains/kotlinx/lincheck/LincheckOptions.kt index 4a1a27364a..7ca7edf03b 100644 --- a/src/jvm/main/org/jetbrains/kotlinx/lincheck/LincheckOptions.kt +++ b/src/jvm/main/org/jetbrains/kotlinx/lincheck/LincheckOptions.kt @@ -334,7 +334,7 @@ internal data class LincheckOptionsImpl( reporter.logIteration(iteration + 1, scenario) } - override fun iterationEnd(iteration: Int, failure: LincheckFailure?) { + override fun iterationEnd(iteration: Int, failure: LincheckFailure?, exception: Throwable?) { statistics?.apply { reporter.logIterationStatistics( invocations = iterationsStatistics[iteration].totalInvocationsCount, diff --git a/src/jvm/main/org/jetbrains/kotlinx/lincheck/RunTracker.kt b/src/jvm/main/org/jetbrains/kotlinx/lincheck/RunTracker.kt index a41486fbc2..7259b2fadb 100644 --- a/src/jvm/main/org/jetbrains/kotlinx/lincheck/RunTracker.kt +++ b/src/jvm/main/org/jetbrains/kotlinx/lincheck/RunTracker.kt @@ -25,13 +25,30 @@ import org.jetbrains.kotlinx.lincheck.strategy.LincheckFailure interface RunTracker { fun runStart(name: String, options: LincheckOptions) {} - fun runEnd(name: String, failure: LincheckFailure? = null, statistics: Statistics? = null) {} + + fun runEnd( + name: String, + failure: LincheckFailure? = null, + exception: Throwable? = null, + statistics: Statistics? = null + ) {} fun iterationStart(iteration: Int, scenario: ExecutionScenario) {} - fun iterationEnd(iteration: Int, failure: LincheckFailure? = null) {} + + fun iterationEnd( + iteration: Int, + failure: LincheckFailure? = null, + exception: Throwable? = null, + ) {} fun invocationStart(invocation: Int) {} - fun invocationEnd(invocation: Int, failure: LincheckFailure? = null) {} + + fun invocationEnd( + invocation: Int, + failure: LincheckFailure? = null, + exception: Throwable? = null, + ) {} + } inline fun RunTracker?.trackRun( @@ -39,44 +56,52 @@ inline fun RunTracker?.trackRun( options: LincheckOptions, block: () -> Pair ): Pair { + var failure: LincheckFailure? = null + var exception: Throwable? = null + var statistics: Statistics? = null this?.runStart(name, options) try { - val (failure, statistics) = block() - this?.runEnd(name, failure, statistics) - return (failure to statistics) - } catch (exception: Throwable) { - // TODO: once https://github.com/JetBrains/lincheck/issues/170 is implemented, - // we can put `check(false)` here instead - this?.runEnd(name) - throw exception + return block().also { + failure = it.first + statistics = it.second + } + } catch (throwable: Throwable) { + exception = throwable + throw throwable + } finally { + this?.runEnd(name, failure, exception, statistics) } } inline fun RunTracker?.trackIteration(iteration: Int, scenario: ExecutionScenario, block: () -> LincheckFailure?): LincheckFailure? { + var failure: LincheckFailure? = null + var exception: Throwable? = null this?.iterationStart(iteration, scenario) try { return block().also { - this?.iterationEnd(iteration, failure = it) + failure = it } - } catch (exception: Throwable) { - // TODO: once https://github.com/JetBrains/lincheck/issues/170 is implemented, - // we can put `check(false)` here instead - this?.iterationEnd(iteration) - throw exception + } catch (throwable: Throwable) { + exception = throwable + throw throwable + } finally { + this?.iterationEnd(iteration, failure, exception) } } inline fun RunTracker?.trackInvocation(invocation: Int, block: () -> LincheckFailure?): LincheckFailure? { + var failure: LincheckFailure? = null + var exception: Throwable? = null this?.invocationStart(invocation) try { return block().also { - this?.invocationEnd(invocation, failure = it) + failure = it } - } catch (exception: Throwable) { - // TODO: once https://github.com/JetBrains/lincheck/issues/170 is implemented, - // we can put `check(false)` here instead - this?.invocationEnd(invocation) - throw exception + } catch (throwable: Throwable) { + exception = throwable + throw throwable + } finally { + this?.invocationEnd(invocation, failure, exception) } } @@ -91,9 +116,9 @@ fun trackersList(trackers: List): RunTracker? = } } - override fun runEnd(name: String, failure: LincheckFailure?, statistics: Statistics?) { + override fun runEnd(name: String, failure: LincheckFailure?, exception: Throwable?, statistics: Statistics?) { for (tracker in trackers) { - tracker.runEnd(name, failure, statistics) + tracker.runEnd(name, failure, exception, statistics) } } @@ -103,9 +128,9 @@ fun trackersList(trackers: List): RunTracker? = } } - override fun iterationEnd(iteration: Int, failure: LincheckFailure?) { + override fun iterationEnd(iteration: Int, failure: LincheckFailure?, exception: Throwable?) { for (tracker in trackers) { - tracker.iterationEnd(iteration, failure) + tracker.iterationEnd(iteration, failure, exception) } } @@ -115,9 +140,9 @@ fun trackersList(trackers: List): RunTracker? = } } - override fun invocationEnd(invocation: Int, failure: LincheckFailure?) { + override fun invocationEnd(invocation: Int, failure: LincheckFailure?, exception: Throwable?) { for (tracker in trackers) { - tracker.invocationEnd(invocation, failure) + tracker.invocationEnd(invocation, failure, exception) } } diff --git a/src/jvm/main/org/jetbrains/kotlinx/lincheck/Statistics.kt b/src/jvm/main/org/jetbrains/kotlinx/lincheck/Statistics.kt index 4c6447b856..232e5cfa6b 100644 --- a/src/jvm/main/org/jetbrains/kotlinx/lincheck/Statistics.kt +++ b/src/jvm/main/org/jetbrains/kotlinx/lincheck/Statistics.kt @@ -169,7 +169,7 @@ internal class StatisticsTracker : Statistics, RunTracker { warmUpFlag = false } - override fun iterationEnd(iteration: Int, failure: LincheckFailure?) { + override fun iterationEnd(iteration: Int, failure: LincheckFailure?, exception: Throwable?) { invocation = -1 } @@ -181,7 +181,7 @@ internal class StatisticsTracker : Statistics, RunTracker { lastInvocationStartTimeNano = System.nanoTime() } - override fun invocationEnd(invocation: Int, failure: LincheckFailure?) { + override fun invocationEnd(invocation: Int, failure: LincheckFailure?, exception: Throwable?) { val invocationTimeNano = System.nanoTime() - lastInvocationStartTimeNano check(invocationTimeNano >= 0) if (warmUpFlag) { diff --git a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/AbstractLincheckTest.kt b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/AbstractLincheckTest.kt index 5acfa9931f..badcf6bd48 100644 --- a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/AbstractLincheckTest.kt +++ b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/AbstractLincheckTest.kt @@ -116,7 +116,7 @@ abstract class AbstractLincheckTest( runOptions[name] = options } - override fun runEnd(name: String, failure: LincheckFailure?, statistics: Statistics?) { + override fun runEnd(name: String, failure: LincheckFailure?, exception: Throwable?, statistics: Statistics?) { check(statistics != null) runStatistics[name] = statistics }