Skip to content

Commit

Permalink
fixes after rebase
Browse files Browse the repository at this point in the history
Signed-off-by: Evgenii Moiseenko <[email protected]>
  • Loading branch information
eupp committed Jul 17, 2023
1 parent dac4f89 commit 7c50db9
Show file tree
Hide file tree
Showing 37 changed files with 313 additions and 228 deletions.
60 changes: 30 additions & 30 deletions src/jvm/main/org/jetbrains/kotlinx/lincheck/LinChecker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@ class LinChecker(private val testClass: Class<*>, options: Options<*, *>?) {
reporter.logIteration(iteration = i + 1 + customScenarios.size, scenario = scenario)
val failure = scenario.run(this, verifier)
if (failure != null) {
val minimizedFailedIteration = if (minimizeFailedScenario)
failure.minimize(reporter) {
val minimizedFailedIteration = if (minimizeFailedScenario) {
reporter.logScenarioMinimization(scenario)
failure.minimize {
it.run(this, createVerifier())
}
else
} else
failure
reporter.logFailedIteration(minimizedFailedIteration)
return minimizedFailedIteration
Expand All @@ -92,33 +93,6 @@ class LinChecker(private val testClass: Class<*>, options: Options<*, *>?) {
return null
}

// Tries to minimize the specified failing scenario to make the error easier to understand.
// The algorithm is greedy: it tries to remove one actor from the scenario and checks
// whether a test with the modified one fails with error as well. If it fails,
// then the scenario has been successfully minimized, and the algorithm tries to minimize it again, recursively.
// Otherwise, if no actor can be removed so that the generated test fails, the minimization is completed.
// Thus, the algorithm works in the linear time of the total number of actors.
private fun LincheckFailure.minimize(testCfg: CTestConfiguration): LincheckFailure {
reporter.logScenarioMinimization(scenario)
var minimizedFailure = this
while (true) {
minimizedFailure = minimizedFailure.scenario.tryMinimize(testCfg) ?: break
}
return minimizedFailure
}

private fun ExecutionScenario.tryMinimize(testCfg: CTestConfiguration): LincheckFailure? {
// Reversed indices to avoid conflicts with in-loop removals
for (i in threads.indices.reversed()) {
for (j in threads[i].indices.reversed()) {
tryMinimize(i, j)
?.run(testCfg, testCfg.createVerifier())
?.let { return it }
}
}
return null
}

private fun ExecutionScenario.run(testCfg: CTestConfiguration, verifier: Verifier): LincheckFailure? =
testCfg.createStrategy(
testClass = testClass,
Expand Down Expand Up @@ -184,3 +158,29 @@ fun <O : Options<O, *>> O.check(testClass: KClass<*>) = this.check(testClass.jav

@Suppress("DEPRECATION_ERROR")
internal fun <O : Options<O, *>> O.checkImpl(testClass: Class<*>) = LinChecker(testClass, this).checkImpl()

// Tries to minimize the specified failing scenario to make the error easier to understand.
// The algorithm is greedy: it tries to remove one actor from the scenario and checks
// whether a test with the modified one fails with error as well. If it fails,
// then the scenario has been successfully minimized, and the algorithm tries to minimize it again, recursively.
// Otherwise, if no actor can be removed so that the generated test fails, the minimization is completed.
// Thus, the algorithm works in the linear time of the total number of actors.
internal fun LincheckFailure.minimize(checkScenario: (ExecutionScenario) -> LincheckFailure?): LincheckFailure {
var minimizedFailure = this
while (true) {
minimizedFailure = minimizedFailure.scenario.tryMinimize(checkScenario) ?: break
}
return minimizedFailure
}

private fun ExecutionScenario.tryMinimize(checkScenario: (ExecutionScenario) -> LincheckFailure?): LincheckFailure? {
// Reversed indices to avoid conflicts with in-loop removals
for (i in threads.indices.reversed()) {
for (j in threads[i].indices.reversed()) {
tryMinimize(i, j)
?.run(checkScenario)
?.let { return it }
}
}
return null
}
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ internal data class LincheckOptionsImpl(
} ?: return@trackRun (null to statisticsTracker)
// TODO: implement a minimization planner?
if (minimizeFailedScenario) {
failure = failure.minimize(reporterManager.reporter) {
reporterManager.reporter.logScenarioMinimization(failure.scenario)
failure = failure.minimize {
it.run(
mode, testClass, testStructure,
createVerifier(testClass),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import org.jetbrains.kotlinx.lincheck.runner.*
import org.jetbrains.kotlinx.lincheck.strategy.managed.*
import org.jetbrains.kotlinx.lincheck.verifier.*
import org.objectweb.asm.ClassVisitor
import java.io.Closeable

/**
* Implementation of this class describes how to run the generated execution.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ abstract class ManagedStrategy(
// Ihe number of entered but not left (yet) blocks that should be ignored by the strategy analysis for each thread.
private val ignoredSectionDepth = IntArray(nThreads) { 0 }
// Detector of loops or hangs (i.e. active locks).
protected val loopDetector: LoopDetector = LoopDetector(testCfg.hangingDetectionThreshold)
protected val loopDetector: LoopDetector = LoopDetector(hangingDetectionThreshold)

// Tracker of acquisitions and releases of monitors.
private lateinit var monitorTracker: MonitorTracker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,6 @@ internal class ModelCheckingStrategy(
return currentInterleaving.isSwitchPosition()
}

override fun initializeInvocation() {
currentInterleaving.initialize()
super.initializeInvocation()
}

override fun beforePart(part: ExecutionPart) {
val nextThread = when (part) {
ExecutionPart.INIT -> 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ package org.jetbrains.kotlinx.lincheck_test
import org.jetbrains.kotlinx.lincheck.LinChecker
import org.jetbrains.kotlinx.lincheck.LincheckAssertionError
import org.jetbrains.kotlinx.lincheck.annotations.Operation
import org.jetbrains.kotlinx.lincheck.strategy.stress.StressCTest
import org.jetbrains.kotlinx.lincheck.strategy.stress.*
import org.junit.Assert.*
import org.junit.Test
import java.util.concurrent.ThreadLocalRandom

@Suppress("DEPRECATION_ERROR")
@StressCTest(iterations = 1, requireStateEquivalenceImplCheck = false, actorsBefore = 1, actorsAfter = 1, threads = 3)
class AlmostEmptyScenarioTest {
@Operation(runOnce = true)
Expand Down
21 changes: 9 additions & 12 deletions src/jvm/test/org/jetbrains/kotlinx/lincheck_test/ExceptionTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,10 @@ class ExceptionInParallelPartTest : AbstractLincheckTest(IncorrectResultsFailure
}
}

override fun <O : Options<O, *>> O.customize() {
iterations(0)
override fun LincheckOptionsImpl.customize() {
addCustomScenario(scenario)
minimizeFailedScenario(false)
sequentialSpecification(ExceptionTestSequentialImplementation::class.java)
generateRandomScenarios = false
sequentialImplementation = ExceptionTestSequentialImplementation::class.java
}

}
Expand All @@ -62,11 +61,10 @@ class ExceptionInInitPartTest : AbstractLincheckTest(IncorrectResultsFailure::cl
}
}

override fun <O : Options<O, *>> O.customize() {
iterations(0)
override fun LincheckOptionsImpl.customize() {
addCustomScenario(scenario)
minimizeFailedScenario(false)
sequentialSpecification(ExceptionTestSequentialImplementation::class.java)
generateRandomScenarios = false
sequentialImplementation = ExceptionTestSequentialImplementation::class.java
}

}
Expand All @@ -92,11 +90,10 @@ class ExceptionInPostPartTest : AbstractLincheckTest(IncorrectResultsFailure::cl
}
}

override fun <O : Options<O, *>> O.customize() {
iterations(0)
override fun LincheckOptionsImpl.customize() {
addCustomScenario(scenario)
minimizeFailedScenario(false)
sequentialSpecification(ExceptionTestSequentialImplementation::class.java)
generateRandomScenarios = false
sequentialImplementation = ExceptionTestSequentialImplementation::class.java
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,18 @@ class FailedScenarioMinimizationTest: VerifierState() {

@Test
fun testWithoutMinimization() {
val options = StressOptions()
.actorsPerThread(10)
.invocationsPerIteration(1_000)
.minimizeFailedScenario(false)
val options = LincheckOptions {
this as LincheckOptionsImpl
mode = LincheckMode.Stress
minThreads = 10
maxThreads = 10
minOperationsInThread = 10
maxOperationsInThread = 10
minimizeFailedScenario = false
tryReproduceTrace = false
}
try {
LinChecker.check(FailedScenarioMinimizationTest::class.java, options)
options.check(FailedScenarioMinimizationTest::class.java)
fail("Should fail with LincheckAssertionError")
} catch (e: LincheckAssertionError) {
val failedScenario = e.failure.scenario
Expand All @@ -46,11 +52,17 @@ class FailedScenarioMinimizationTest: VerifierState() {

@Test
fun testWithMinimization() {
val options = StressOptions()
.actorsPerThread(10)
.invocationsPerIteration(1_000)
val options = LincheckOptions {
this as LincheckOptionsImpl
mode = LincheckMode.Stress
minThreads = 10
maxThreads = 10
minOperationsInThread = 10
maxOperationsInThread = 10
tryReproduceTrace = false
}
try {
LinChecker.check(FailedScenarioMinimizationTest::class.java, options)
options.check(FailedScenarioMinimizationTest::class.java)
fail("Should fail with LincheckAssertionError")
} catch (e: LincheckAssertionError) {
val failedScenario = e.failure.scenario
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,10 @@ class HangingInParallelPartTest : AbstractLincheckTest(DeadlockWithDumpFailure::
}
}

override fun <O : Options<O, *>> O.customize() {
override fun LincheckOptionsImpl.customize() {
addCustomScenario(scenario)
iterations(0)
minimizeFailedScenario(false)
invocationTimeout(100)
generateRandomScenarios = false
invocationTimeoutMs = 100
}

}
Expand All @@ -61,11 +60,10 @@ class HangingInInitPartTest : AbstractLincheckTest(DeadlockWithDumpFailure::clas
}
}

override fun <O : Options<O, *>> O.customize() {
override fun LincheckOptionsImpl.customize() {
addCustomScenario(scenario)
iterations(0)
minimizeFailedScenario(false)
invocationTimeout(100)
generateRandomScenarios = false
invocationTimeoutMs = 100
}

}
Expand All @@ -91,11 +89,10 @@ class HangingInPostPartTest : AbstractLincheckTest(DeadlockWithDumpFailure::clas
}
}

override fun <O : Options<O, *>> O.customize() {
override fun LincheckOptionsImpl.customize() {
addCustomScenario(scenario)
iterations(0)
minimizeFailedScenario(false)
invocationTimeout(100)
generateRandomScenarios = false
invocationTimeoutMs = 100
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@ import org.junit.*
import java.lang.AssertionError
import kotlin.random.*

@StressCTest(iterations = 1, minimizeFailedScenario = false, requireStateEquivalenceImplCheck = false)
class OperationsInAbstractClassTest : AbstractTestClass() {
@Operation
fun goodOperation() = 10

@Test(expected = AssertionError::class)
fun test(): Unit = LinChecker.check(this::class.java)
fun test(): Unit = LincheckOptions {
this as LincheckOptionsImpl
mode = LincheckMode.Stress
testingTimeInSeconds = 1
minimizeFailedScenario = false
tryReproduceTrace = false
}.check(this::class.java)
}

open class AbstractTestClass {
Expand Down
Loading

0 comments on commit 7c50db9

Please sign in to comment.