diff --git a/build.gradle.kts b/build.gradle.kts index 2b9daf46f..0fd14d369 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -110,9 +110,9 @@ tasks { fun Test.configureJvmTestCommon() { maxParallelForks = 1 maxHeapSize = "6g" - val instrumentAllClassesInModelCheckingMode: String by project - if (instrumentAllClassesInModelCheckingMode.toBoolean()) { - systemProperty("lincheck.instrumentAllClassesInModelCheckingMode", "true") + val instrumentAllClasses: String by project + if (instrumentAllClasses.toBoolean()) { + systemProperty("lincheck.instrumentAllClasses", "true") } val extraArgs = mutableListOf() val withEventIdSequentialCheck: String by project diff --git a/gradle.properties b/gradle.properties index 4899f545a..d46891532 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,7 @@ lastCopyrightYear=2023 jdkToolchainVersion=17 runAllTestsInSeparateJVMs=false -instrumentAllClassesInModelCheckingMode=false +instrumentAllClasses=false withEventIdSequentialCheck=false kotlinVersion=1.9.21 diff --git a/src/jvm/main/org/jetbrains/kotlinx/lincheck/LinChecker.kt b/src/jvm/main/org/jetbrains/kotlinx/lincheck/LinChecker.kt index 4c0aa0b7c..7b7895416 100644 --- a/src/jvm/main/org/jetbrains/kotlinx/lincheck/LinChecker.kt +++ b/src/jvm/main/org/jetbrains/kotlinx/lincheck/LinChecker.kt @@ -42,23 +42,32 @@ class LinChecker (private val testClass: Class<*>, options: Options<*, *>?) { * @throws LincheckAssertionError if the testing data structure is incorrect. */ fun check() { - val failure = checkImpl() ?: return - throw LincheckAssertionError(failure) + checkImpl { failure -> + if (failure != null) throw LincheckAssertionError(failure) + } } /** - * @return TestReport with information about concurrent test run. + * Runs Lincheck to check the tested class under given configurations. + * + * @param cont Optional continuation taking [LincheckFailure] as an argument. + * The continuation is run in the context when Lincheck java-agent is still attached. + * @return [LincheckFailure] if a failure is discovered, null otherwise. */ @Synchronized // never run Lincheck tests in parallel - internal fun checkImpl(): LincheckFailure? { + internal fun checkImpl(cont: LincheckFailureContinuation? = null): LincheckFailure? { check(testConfigurations.isNotEmpty()) { "No Lincheck test configuration to run" } lincheckVerificationStarted() for (testCfg in testConfigurations) { withLincheckJavaAgent(testCfg.instrumentationMode) { val failure = testCfg.checkImpl() - if (failure != null) return failure + if (failure != null) { + if (cont != null) cont(failure) + return failure + } } } + if (cont != null) cont(null) return null } @@ -203,6 +212,36 @@ fun > O.check(testClass: Class<*>) = LinChecker.check(testClas */ fun > O.check(testClass: KClass<*>) = this.check(testClass.java) -internal fun > O.checkImpl(testClass: Class<*>) = LinChecker(testClass, this).checkImpl() +/** + * Runs Lincheck to check the tested class under given configurations. + * + * @param testClass Tested class. + * @return [LincheckFailure] if a failure is discovered, null otherwise. + */ +internal fun > O.checkImpl(testClass: Class<*>): LincheckFailure? = + LinChecker(testClass, this).checkImpl() + +/** + * Runs Lincheck to check the tested class under given configurations. + * + * Takes the [LincheckFailureContinuation] as an argument. + * This is required due to current limitations of our testing infrastructure. + * Some tests need to inspect the internals of the failure object + * (for example, the stack traces of exceptions thrown during the execution). + * However, because Lincheck dynamically installs java-agent and then uninstalls it, + * this process can invalidate some internal state of the failure object + * (for example, the source code mapping information in the stack traces is typically lost). + * To overcome this problem, we run the continuation in the context when Lincheck java-agent is still attached. + * + * @param testClass Tested class. + * @param cont Continuation taking [LincheckFailure] as an argument. + * The continuation is run in the context when Lincheck java-agent is still attached. + * @return [LincheckFailure] if a failure is discovered, null otherwise. + */ +internal fun > O.checkImpl(testClass: Class<*>, cont: LincheckFailureContinuation) { + LinChecker(testClass, this).checkImpl(cont) +} + +internal typealias LincheckFailureContinuation = (LincheckFailure?) -> Unit internal const val NO_OPERATION_ERROR_MESSAGE = "You must specify at least one operation to test. Please refer to the user guide: https://kotlinlang.org/docs/introduction.html" diff --git a/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/LincheckClassVisitor.kt b/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/LincheckClassVisitor.kt index baa695fa7..bb6a02af2 100644 --- a/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/LincheckClassVisitor.kt +++ b/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/LincheckClassVisitor.kt @@ -18,6 +18,7 @@ import org.objectweb.asm.commons.* import org.jetbrains.kotlinx.lincheck.transformation.InstrumentationMode.* import org.jetbrains.kotlinx.lincheck.transformation.transformers.* import sun.nio.ch.lincheck.* +import kotlin.collections.HashSet internal class LincheckClassVisitor( private val instrumentationMode: InstrumentationMode, @@ -26,8 +27,8 @@ internal class LincheckClassVisitor( private val ideaPluginEnabled = ideaPluginEnabled() private var classVersion = 0 - private lateinit var fileName: String - private lateinit var className: String + private var fileName: String = "" + private var className: String = "" // internal class name override fun visitField( access: Int, @@ -73,7 +74,7 @@ internal class LincheckClassVisitor( if (access and ACC_NATIVE != 0) return mv if (instrumentationMode == STRESS) { return if (methodName != "" && methodName != "") { - CoroutineCancellabilitySupportTransformer(mv, access, methodName, desc) + CoroutineCancellabilitySupportTransformer(mv, access, className, methodName, desc) } else { mv } @@ -103,7 +104,7 @@ internal class LincheckClassVisitor( } mv = JSRInlinerAdapter(mv, access, methodName, desc, signature, exceptions) mv = TryCatchBlockSorter(mv, access, methodName, desc, signature, exceptions) - mv = CoroutineCancellabilitySupportTransformer(mv, access, methodName, desc) + mv = CoroutineCancellabilitySupportTransformer(mv, access, className, methodName, desc) if (access and ACC_SYNCHRONIZED != 0) { mv = SynchronizedMethodTransformer(fileName, className, methodName, mv.newAdapter(), classVersion) } @@ -192,4 +193,9 @@ private class WrapMethodInIgnoredSectionTransformer( } visitInsn(opcode) } -} \ No newline at end of file +} + +// Set storing canonical names of the classes that call internal coroutine functions; +// it is used to optimize class re-transformation in stress mode by remembering +// exactly what classes need to be re-transformed (only the coroutines calling classes) +internal val coroutineCallingClasses = HashSet() \ No newline at end of file diff --git a/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/LincheckJavaAgent.kt b/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/LincheckJavaAgent.kt index c33266a7c..bdb3c21df 100644 --- a/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/LincheckJavaAgent.kt +++ b/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/LincheckJavaAgent.kt @@ -13,12 +13,13 @@ package org.jetbrains.kotlinx.lincheck.transformation import net.bytebuddy.agent.* import org.jetbrains.kotlinx.lincheck.* import org.jetbrains.kotlinx.lincheck.transformation.InstrumentationMode.* -import org.jetbrains.kotlinx.lincheck.transformation.LincheckClassFileTransformer.nonTransformedClasses import org.jetbrains.kotlinx.lincheck.transformation.LincheckClassFileTransformer.shouldTransform +import org.jetbrains.kotlinx.lincheck.transformation.LincheckClassFileTransformer.transformedClassesStress +import org.jetbrains.kotlinx.lincheck.transformation.LincheckClassFileTransformer.nonTransformedClasses import org.jetbrains.kotlinx.lincheck.transformation.LincheckJavaAgent.instrumentation import org.jetbrains.kotlinx.lincheck.transformation.LincheckJavaAgent.instrumentationMode -import org.jetbrains.kotlinx.lincheck.transformation.LincheckJavaAgent.instrumentedClassesInTheModelCheckingMode -import org.jetbrains.kotlinx.lincheck.transformation.LincheckJavaAgent.INSTRUMENT_ALL_CLASSES_IN_MODEL_CHECKING_MODE +import org.jetbrains.kotlinx.lincheck.transformation.LincheckJavaAgent.instrumentedClasses +import org.jetbrains.kotlinx.lincheck.transformation.LincheckJavaAgent.INSTRUMENT_ALL_CLASSES import org.jetbrains.kotlinx.lincheck.util.readFieldViaUnsafe import sun.misc.Unsafe import org.objectweb.asm.* @@ -82,9 +83,9 @@ internal object LincheckJavaAgent { private var isBootstrapJarAddedToClasspath = false /** - * TODO + * Names (canonical) of the classes that were instrumented since the last agent installation. */ - val instrumentedClassesInTheModelCheckingMode = HashSet() + val instrumentedClasses = HashSet() /** * Dynamically attaches [LincheckClassFileTransformer] to this JVM instance. @@ -106,18 +107,36 @@ internal object LincheckJavaAgent { // allowing already loaded classes re-transformation. instrumentation.addTransformer(LincheckClassFileTransformer, true) // The transformation logic depends on the testing strategy. - // In the stress testing mode, Lincheck needs to track coroutine suspensions, - // so it processes all classes (including those that are already loaded), - // and looks for suspension points. In case of the model checking, Lincheck - // could also process all the classes, but it would lead to a significant - // performance degradation. Instead, in the model checking mode, Lincheck - // processes classes lazily, only when they are used. However, we have an - // option to enable the global transformation in the model checking mode - // for testing purposes. - if (instrumentationMode == STRESS || INSTRUMENT_ALL_CLASSES_IN_MODEL_CHECKING_MODE) { - // Re-transform the already loaded classes. - // New classes will be transformed automatically. - instrumentation.retransformClasses(*getLoadedClassesToInstrument().toTypedArray()) + when { + // If an option to enable transformation of all classes is explicitly set, + // then we re-transform all the classes + // (this option is used for testing purposes). + INSTRUMENT_ALL_CLASSES -> { + // Re-transform the already loaded classes. + // New classes will be transformed automatically. + instrumentation.retransformClasses(*getLoadedClassesToInstrument().toTypedArray()) + } + + // In the stress testing mode, Lincheck needs to track coroutine suspensions. + // As an optimization, we remember the set of loaded classes that actually + // have suspension points, so later we can re-transform only those classes. + instrumentationMode == STRESS -> { + check(instrumentedClasses.isEmpty()) + val classes = getLoadedClassesToInstrument().filter { + val canonicalClassName = it.name + // new classes that were loaded after the latest STRESS mode re-transformation + !transformedClassesStress.containsKey(canonicalClassName) || + // old classes that were already loaded before and have coroutine method calls inside + canonicalClassName in coroutineCallingClasses + } + instrumentation.retransformClasses(*classes.toTypedArray()) + instrumentedClasses.addAll(classes.map { it.name }) + } + + // In the model checking mode, Lincheck processes classes lazily, only when they are used. + instrumentationMode == MODEL_CHECKING -> { + check(instrumentedClasses.isEmpty()) + } } } @@ -139,7 +158,7 @@ internal object LincheckJavaAgent { instrumentation.appendToBootstrapClassLoaderSearch(JarFile(tempBootstrapJarFile)) } - private fun getLoadedClassesToInstrument() = + private fun getLoadedClassesToInstrument(): List> = instrumentation.allLoadedClasses .filter(instrumentation::isModifiableClass) .filter { shouldTransform(it.name, instrumentationMode) } @@ -153,23 +172,24 @@ internal object LincheckJavaAgent { instrumentation.removeTransformer(LincheckClassFileTransformer) // Collect the original bytecode of the instrumented classes. val classDefinitions = getLoadedClassesToInstrument() - .filter { - // Filter classes that were transformed by Lincheck and should be restored. - if (instrumentationMode == MODEL_CHECKING || !INSTRUMENT_ALL_CLASSES_IN_MODEL_CHECKING_MODE) { - it.name in instrumentedClassesInTheModelCheckingMode - } else { - true + .mapNotNull { clazz -> + val canonicalClassName = clazz.name + // Skip classes not transformed by Lincheck. + if (!INSTRUMENT_ALL_CLASSES && canonicalClassName !in instrumentedClasses) { + return@mapNotNull null } - }.mapNotNull { clazz -> - // For each class, get its original bytecode. + // For each class, retrieve its original bytecode. val bytes = nonTransformedClasses[clazz.name] - bytes?.let { ClassDefinition(clazz, it) } + check(bytes != null) { + "Original bytecode for the transformed class ${clazz.name} is missing!" + } + ClassDefinition(clazz, bytes) } // Redefine the instrumented classes back to their original state // using the original bytecodes collected previously. instrumentation.redefineClasses(*classDefinitions.toTypedArray()) // Clear the set of classes instrumented in the model checking mode. - instrumentedClassesInTheModelCheckingMode.clear() + instrumentedClasses.clear() } /** @@ -185,15 +205,15 @@ internal object LincheckJavaAgent { * thus, initializing it here, in an ignored section of the analysis, re-transforming * the class after that. * - * @param className The name of the class to be transformed. + * @param canonicalClassName The name of the class to be transformed. */ - fun ensureClassHierarchyIsTransformed(className: String) { - if (INSTRUMENT_ALL_CLASSES_IN_MODEL_CHECKING_MODE) { - Class.forName(className) + fun ensureClassHierarchyIsTransformed(canonicalClassName: String) { + if (INSTRUMENT_ALL_CLASSES) { + Class.forName(canonicalClassName) return } - if (className in instrumentedClassesInTheModelCheckingMode) return // already instrumented - ensureClassHierarchyIsTransformed(Class.forName(className), Collections.newSetFromMap(IdentityHashMap())) + if (canonicalClassName in instrumentedClasses) return // already instrumented + ensureClassHierarchyIsTransformed(Class.forName(canonicalClassName), Collections.newSetFromMap(IdentityHashMap())) } @@ -206,7 +226,7 @@ internal object LincheckJavaAgent { * @param testInstance the object to be transformed */ fun ensureObjectIsTransformed(testInstance: Any) { - if (INSTRUMENT_ALL_CLASSES_IN_MODEL_CHECKING_MODE) { + if (INSTRUMENT_ALL_CLASSES) { return } ensureObjectIsTransformed(testInstance, Collections.newSetFromMap(IdentityHashMap())) @@ -218,10 +238,10 @@ internal object LincheckJavaAgent { * @param clazz the class to transform */ private fun ensureClassHierarchyIsTransformed(clazz: Class<*>) { - if (INSTRUMENT_ALL_CLASSES_IN_MODEL_CHECKING_MODE) { + if (INSTRUMENT_ALL_CLASSES) { return } - if (clazz.name in instrumentedClassesInTheModelCheckingMode) return // already instrumented + if (clazz.name in instrumentedClasses) return // already instrumented ensureClassHierarchyIsTransformed(clazz, Collections.newSetFromMap(IdentityHashMap())) } @@ -264,7 +284,7 @@ internal object LincheckJavaAgent { */ private fun ensureClassHierarchyIsTransformed(clazz: Class<*>, processedObjects: MutableSet) { if (instrumentation.isModifiableClass(clazz) && shouldTransform(clazz.name, instrumentationMode)) { - instrumentedClassesInTheModelCheckingMode += clazz.name + instrumentedClasses += clazz.name instrumentation.retransformClasses(clazz) } else { return @@ -278,18 +298,22 @@ internal object LincheckJavaAgent { ensureObjectIsTransformed(it, processedObjects) } clazz.superclass?.let { - if (it.name in instrumentedClassesInTheModelCheckingMode) return // already instrumented + if (it.name in instrumentedClasses) return // already instrumented ensureClassHierarchyIsTransformed(it, processedObjects) } } /** * FOR TEST PURPOSE ONLY! - * To test the byte-code transformation correctness for the - * model-checking strategy, we can transform all classes. + * To test the byte-code transformation correctness, we can transform all classes. + * + * Both stress and model checking modes implement some optimizations + * to avoid re-transforming all loaded into VM classes on each run of a Lincheck test. + * When this flag is set, these optimizations are disabled, and so + * the Lincheck agent re-transforms all the loaded classes on each run. */ - internal val INSTRUMENT_ALL_CLASSES_IN_MODEL_CHECKING_MODE = - System.getProperty("lincheck.instrumentAllClassesInModelCheckingMode")?.toBoolean() ?: false + internal val INSTRUMENT_ALL_CLASSES = + System.getProperty("lincheck.instrumentAllClasses")?.toBoolean() ?: false } internal object LincheckClassFileTransformer : ClassFileTransformer { @@ -299,9 +323,9 @@ internal object LincheckClassFileTransformer : ClassFileTransformer { * Notice that the transformation depends on the [InstrumentationMode]. * Additionally, this object caches bytes of non-transformed classes. */ - private val transformedClassesModelChecking = ConcurrentHashMap() - private val transformedClassesStress = ConcurrentHashMap() - val nonTransformedClasses = ConcurrentHashMap() + val transformedClassesModelChecking = ConcurrentHashMap() + val transformedClassesStress = ConcurrentHashMap() + val nonTransformedClasses = ConcurrentHashMap() private val transformedClassesCache get() = when (instrumentationMode) { @@ -310,27 +334,39 @@ internal object LincheckClassFileTransformer : ClassFileTransformer { } override fun transform( - loader: ClassLoader?, className: String, classBeingRedefined: Class<*>?, protectionDomain: ProtectionDomain?, classBytes: ByteArray + loader: ClassLoader?, + internalClassName: String, + classBeingRedefined: Class<*>?, + protectionDomain: ProtectionDomain?, + classBytes: ByteArray ): ByteArray? = runInIgnoredSection { - if (instrumentationMode == MODEL_CHECKING && !INSTRUMENT_ALL_CLASSES_IN_MODEL_CHECKING_MODE) { - // In the model checking mode, we transform classes lazily, - // once they are used in the testing code. - if (className.canonicalClassName !in instrumentedClassesInTheModelCheckingMode) return null - } else { - if (!shouldTransform(className.canonicalClassName, instrumentationMode)) return null + // If the class should not be transformed, return immediately. + if (!shouldTransform(internalClassName.canonicalClassName, instrumentationMode)) { + return null + } + // In the model checking mode, we transform classes lazily, + // once they are used in the testing code. + if (!INSTRUMENT_ALL_CLASSES && + instrumentationMode == MODEL_CHECKING && + internalClassName.canonicalClassName !in instrumentedClasses) { + return null } - return transformImpl(loader, className, classBytes) + return transformImpl(loader, internalClassName, classBytes) } - private fun transformImpl(loader: ClassLoader?, className: String, classBytes: ByteArray): ByteArray = transformedClassesCache.computeIfAbsent(className) { - nonTransformedClasses[className] = classBytes + private fun transformImpl( + loader: ClassLoader?, + internalClassName: String, + classBytes: ByteArray + ): ByteArray = transformedClassesCache.computeIfAbsent(internalClassName.canonicalClassName) { + nonTransformedClasses.putIfAbsent(internalClassName.canonicalClassName, classBytes) val reader = ClassReader(classBytes) val writer = SafeClassWriter(reader, loader, ClassWriter.COMPUTE_FRAMES) try { reader.accept(LincheckClassVisitor(instrumentationMode, writer), ClassReader.SKIP_FRAMES) writer.toByteArray() } catch (e: Throwable) { - System.err.println("Unable to transform $className") + System.err.println("Unable to transform $internalClassName") e.printStackTrace() classBytes } diff --git a/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/transformers/CoroutineSupportTransformers.kt b/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/transformers/CoroutineSupportTransformers.kt index 52b46f490..f7bef826c 100644 --- a/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/transformers/CoroutineSupportTransformers.kt +++ b/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/transformers/CoroutineSupportTransformers.kt @@ -13,6 +13,7 @@ package org.jetbrains.kotlinx.lincheck.transformation.transformers import org.objectweb.asm.MethodVisitor import org.objectweb.asm.commons.AdviceAdapter import org.jetbrains.kotlinx.lincheck.transformation.* +import org.jetbrains.kotlinx.lincheck.canonicalClassName import sun.nio.ch.lincheck.* /** @@ -22,22 +23,22 @@ import sun.nio.ch.lincheck.* internal class CoroutineCancellabilitySupportTransformer( mv: MethodVisitor, access: Int, + val className: String?, methodName: String?, - descriptor: String? -) : AdviceAdapter(ASM_API, mv, access, methodName, descriptor) { + desc: String? +) : AdviceAdapter(ASM_API, mv, access, methodName, desc) { override fun visitMethodInsn(opcode: Int, owner: String, name: String, desc: String, itf: Boolean) { - if (isCancellableContinuationGetResultMethod(owner, name)) { + val isGetResult = (name == "getResult") && ( + owner == "kotlinx/coroutines/CancellableContinuation" || + owner == "kotlinx/coroutines/CancellableContinuationImpl" + ) + if (isGetResult) { dup() invokeStatic(Injections::storeCancellableContinuation) + className?.canonicalClassName?.let { coroutineCallingClasses += it } } super.visitMethodInsn(opcode, owner, name, desc, itf) } - private fun isCancellableContinuationGetResultMethod(className: String, methodName: String): Boolean = - (methodName == "getResult") && ( - className == "kotlinx/coroutines/CancellableContinuation" || - className == "kotlinx/coroutines/CancellableContinuationImpl" - ) - } \ No newline at end of file diff --git a/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/transformers/MethodCallTransformer.kt b/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/transformers/MethodCallTransformer.kt index 8b56474ec..389973c69 100644 --- a/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/transformers/MethodCallTransformer.kt +++ b/src/jvm/main/org/jetbrains/kotlinx/lincheck/transformation/transformers/MethodCallTransformer.kt @@ -11,14 +11,10 @@ package org.jetbrains.kotlinx.lincheck.transformation.transformers import org.jetbrains.kotlinx.lincheck.transformation.* -import org.jetbrains.kotlinx.lincheck.transformation.ManagedStrategyMethodVisitor -import org.jetbrains.kotlinx.lincheck.transformation.invokeIfInTestingCode -import org.jetbrains.kotlinx.lincheck.transformation.invokeInIgnoredSection -import org.jetbrains.kotlinx.lincheck.transformation.storeArguments import org.objectweb.asm.Opcodes.* import org.objectweb.asm.Type -import org.objectweb.asm.Type.VOID_TYPE -import org.objectweb.asm.commons.GeneratorAdapter +import org.objectweb.asm.Type.* +import org.objectweb.asm.commons.* import sun.nio.ch.lincheck.* /** 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 0e703927a..7a34d9273 100644 --- a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/AbstractLincheckTest.kt +++ b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/AbstractLincheckTest.kt @@ -68,4 +68,4 @@ abstract class AbstractLincheckTest( } } -private const val TIMEOUT = 2 * 60_000L // 2 min \ No newline at end of file +private const val TIMEOUT = 3 * 60_000L // 3 min \ No newline at end of file diff --git a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/ClocksWithExceptionsInOutputTest.kt b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/ClocksWithExceptionsInOutputTest.kt index 659887b33..a6a490e70 100644 --- a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/ClocksWithExceptionsInOutputTest.kt +++ b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/ClocksWithExceptionsInOutputTest.kt @@ -38,7 +38,8 @@ class ClocksWithExceptionsInOutputTest { actorsPerThread(2) minimizeFailedScenario(false) } - .checkImpl(this::class.java) - .checkLincheckOutput("clocks_and_exceptions.txt") + .checkImpl(this::class.java) { failure -> + failure.checkLincheckOutput("clocks_and_exceptions.txt") + } } \ No newline at end of file diff --git a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/ExceptionsInOutputTest.kt b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/ExceptionsInOutputTest.kt index a8ce0eaf6..88f975a42 100644 --- a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/ExceptionsInOutputTest.kt +++ b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/ExceptionsInOutputTest.kt @@ -35,7 +35,7 @@ class ExceptionsInOutputTest { fun `should add stackTrace to output`() = ModelCheckingOptions().apply { actorsBefore(2) } - .checkImpl(this::class.java) - .checkLincheckOutput("exceptions_in_output.txt") - + .checkImpl(this::class.java) { failure -> + failure.checkLincheckOutput("exceptions_in_output.txt") + } } \ No newline at end of file diff --git a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/InterleavingAnalysisPresentInSpinCycleFirstIterationTest.kt b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/InterleavingAnalysisPresentInSpinCycleFirstIterationTest.kt index 08b113fd1..ff8740f42 100644 --- a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/InterleavingAnalysisPresentInSpinCycleFirstIterationTest.kt +++ b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/InterleavingAnalysisPresentInSpinCycleFirstIterationTest.kt @@ -64,6 +64,7 @@ class InterleavingAnalysisPresentInSpinCycleFirstIterationTest { thread { actor(InterleavingAnalysisPresentInSpinCycleFirstIterationTest::spinLock) } } } - .checkImpl(this::class.java) - .checkLincheckOutput("switch_in_the_middle_of_spin_cycle_causes_error.txt") + .checkImpl(this::class.java) { failure -> + failure.checkLincheckOutput("switch_in_the_middle_of_spin_cycle_causes_error.txt") + } } diff --git a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/InternalLincheckBugTest.kt b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/InternalLincheckBugTest.kt index 76a419f1c..d297dedb7 100644 --- a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/InternalLincheckBugTest.kt +++ b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/InternalLincheckBugTest.kt @@ -41,6 +41,7 @@ class InternalLincheckBugTest { @Test fun test() = ModelCheckingOptions() .actorsPerThread(2) - .checkImpl(this::class.java) - .checkLincheckOutput("internal_bug_report.txt") + .checkImpl(this::class.java) { failure -> + failure.checkLincheckOutput("internal_bug_report.txt") + } } diff --git a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/TraceReportingTest.kt b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/TraceReportingTest.kt index 271b38348..6d2d9d932 100644 --- a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/TraceReportingTest.kt +++ b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/TraceReportingTest.kt @@ -125,7 +125,7 @@ class TraceReportingTest { @Test fun testEmptyTrace() { - val failure = ModelCheckingOptions() + ModelCheckingOptions() .iterations(0) .addCustomScenario { parallel { @@ -135,8 +135,9 @@ class TraceReportingTest { } } .sequentialSpecification(EmptySequentialImplementation::class.java) - .checkImpl(this::class.java) - failure.checkLincheckOutput("trace_reporting_empty.txt") + .checkImpl(this::class.java) { failure -> + failure.checkLincheckOutput("trace_reporting_empty.txt") + } } class EmptySequentialImplementation { diff --git a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/ValidationFunctionTests.kt b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/ValidationFunctionTests.kt index 643200471..c66f01fdb 100644 --- a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/ValidationFunctionTests.kt +++ b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/representation/ValidationFunctionTests.kt @@ -64,8 +64,9 @@ class ValidationFunctionCallTest { } } } - .checkImpl(this::class.java) - .checkLincheckOutput("validation_function_failure.txt") + .checkImpl(this::class.java) { failure -> + failure.checkLincheckOutput("validation_function_failure.txt") + } } diff --git a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/verifier/linearizability/RendezvousChannelCustomTest.kt b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/verifier/linearizability/RendezvousChannelCustomTest.kt index aaa812b5e..4fd5ca546 100644 --- a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/verifier/linearizability/RendezvousChannelCustomTest.kt +++ b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/verifier/linearizability/RendezvousChannelCustomTest.kt @@ -41,7 +41,7 @@ class RendezvousChannelCustomTest : VerifierState() { private val pollFun = RendezvousChannelCustomTest::poll @Test - fun testCancellation_01() = withLincheckJavaAgent(InstrumentationMode.STRESS) { + fun testCancellation_01() { verify(RendezvousChannelCustomTest::class.java, LinearizabilityVerifier::class.java, { parallel { thread { @@ -55,7 +55,7 @@ class RendezvousChannelCustomTest : VerifierState() { } @Test - fun testCancellation_02() = withLincheckJavaAgent(InstrumentationMode.STRESS) { + fun testCancellation_02() { verify(RendezvousChannelCustomTest::class.java, LinearizabilityVerifier::class.java, { parallel { thread { @@ -69,7 +69,7 @@ class RendezvousChannelCustomTest : VerifierState() { } @Test - fun testCancellation_03() = withLincheckJavaAgent(InstrumentationMode.STRESS) { + fun testCancellation_03() { verify(RendezvousChannelCustomTest::class.java, LinearizabilityVerifier::class.java, { parallel { thread { @@ -83,7 +83,7 @@ class RendezvousChannelCustomTest : VerifierState() { } @Test - fun testCancellation_04() = withLincheckJavaAgent(InstrumentationMode.STRESS){ + fun testCancellation_04() { verify(RendezvousChannelCustomTest::class.java, LinearizabilityVerifier::class.java, { parallel { thread { @@ -97,7 +97,7 @@ class RendezvousChannelCustomTest : VerifierState() { } @Test - fun testCancellation_05() = withLincheckJavaAgent(InstrumentationMode.STRESS) { + fun testCancellation_05() { verify(RendezvousChannelCustomTest::class.java, LinearizabilityVerifier::class.java, { parallel { thread {