in src/jvm/main/org/jetbrains/kotlinx/lincheck/runner/ExecutionScenarioRunner.kt [300:361]
override fun runInvocation(): InvocationResult {
var timeout = timeoutMs * 1_000_000
try {
// Create a new testing class instance.
createTestInstance()
// Set the event tracker.
setEventTracker()
// Execute the initial part.
initialPartExecution?.let {
beforePart(INIT)
val initPartTask = threadMapOf<Runnable>(INIT_THREAD_ID to it)
timeout -= executor.submitAndAwait(initPartTask, timeout)
}
onThreadSwitchesOrActorFinishes()
val afterInitStateRepresentation = constructStateRepresentation()
// Execute the parallel part.
beforePart(PARALLEL)
val parallelPartTasks = threadMapOf(*parallelPartExecutions
.mapIndexed { i, execution -> i to execution }
.toTypedArray()
)
timeout -= executor.submitAndAwait(parallelPartTasks, timeout)
// Wait for all user threads to finish at the end of the parallel part
timeout -= strategy.awaitUserThreads(timeout)
val afterParallelStateRepresentation: String? = constructStateRepresentation()
onThreadSwitchesOrActorFinishes()
// Execute the post part.
postPartExecution?.let {
beforePart(POST)
val postPartTask = threadMapOf<Runnable>(POST_THREAD_ID to it)
timeout -= executor.submitAndAwait(postPartTask, timeout)
}
val afterPostStateRepresentation = constructStateRepresentation()
// Execute validation functions
validationPartExecution?.let { validationPart ->
beforePart(VALIDATION)
val validationTask = threadMapOf<Runnable>(VALIDATION_THREAD_ID to validationPart)
executor.submitAndAwait(validationTask, timeout)
val validationResult = validationPart.results.single()
if (validationResult is ExceptionResult) {
return ValidationFailureInvocationResult(scenario, validationResult.throwable, collectExecutionResults())
}
}
// Combine the results and convert them for the standard class loader (if they are of non-primitive types).
// We do not want the transformed code to be reachable outside of the runner and strategy classes.
return CompletedInvocationResult(collectExecutionResults(afterInitStateRepresentation, afterParallelStateRepresentation, afterPostStateRepresentation))
} catch (_: TimeoutException) {
return RunnerTimeoutInvocationResult()
} catch (e: ExecutionException) {
// In case when invocation raised an exception,
// we need to wait for all user threads to finish before continuing.
// In case if waiting for threads termination abrupt with the timeout,
// we return `RunnerTimeoutInvocationResult`.
// Otherwise, we return `UnexpectedExceptionInvocationResult` with the original exception.
runCatching { strategy.awaitUserThreads(timeout) }.onFailure { exception ->
if (exception is TimeoutException) return RunnerTimeoutInvocationResult()
}
return UnexpectedExceptionInvocationResult(e.cause!!, collectExecutionResults())
} finally {
resetState()
}
}