Skip to content

Commit c074deb

Browse files
committed
Add the model checking mode to Lincheck tests and use a newer and faster version of it
1 parent 9587590 commit c074deb

11 files changed

+91
-84
lines changed

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ junit_version=4.12
1212
atomicfu_version=0.14.4
1313
knit_version=0.2.2
1414
html_version=0.6.8
15-
lincheck_version=2.7.1
15+
lincheck_version=2.9
1616
dokka_version=0.9.16-rdev-2-mpp-hacks
1717
byte_buddy_version=1.10.9
1818
reactor_version=3.2.5.RELEASE

kotlinx-coroutines-core/build.gradle

+17-2
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ jvmTest {
180180
systemProperty 'java.security.manager', 'kotlinx.coroutines.TestSecurityManager'
181181
// 'stress' is required to be able to run all subpackage tests like ":jvmTests --tests "*channels*" -Pstress=true"
182182
if (!Idea.active && rootProject.properties['stress'] == null) {
183+
exclude '**/*LincheckTest.*'
183184
exclude '**/*StressTest.*'
184185
}
185186
systemProperty 'kotlinx.coroutines.scheduler.keep.alive.sec', '100000' // any unpark problem hangs test
@@ -205,12 +206,26 @@ task jvmStressTest(type: Test, dependsOn: compileTestKotlinJvm) {
205206
systemProperty 'kotlinx.coroutines.semaphore.maxSpinCycles', '10'
206207
}
207208

209+
task jvmLincheckTest(type: Test, dependsOn: compileTestKotlinJvm) {
210+
classpath = files { jvmTest.classpath }
211+
testClassesDirs = files { jvmTest.testClassesDirs }
212+
minHeapSize = '1g'
213+
maxHeapSize = '10g' // we may need more space for building an interleaving tree in the model checking mode
214+
include '**/*LincheckTest.*'
215+
enableAssertions = true
216+
testLogging.showStandardStreams = true
217+
jvmArgs = ['--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED', // required for transformation
218+
'--add-exports', 'java.base/jdk.internal.util=ALL-UNNAMED'] // in the model checking mode
219+
systemProperty 'kotlinx.coroutines.semaphore.segmentSize', '2'
220+
systemProperty 'kotlinx.coroutines.semaphore.maxSpinCycles', '1' // better for the model checking mode
221+
}
222+
208223
task jdk16Test(type: Test, dependsOn: [compileTestKotlinJvm, checkJdk16]) {
209224
classpath = files { jvmTest.classpath }
210225
testClassesDirs = files { jvmTest.testClassesDirs }
211226
executable = "$System.env.JDK_16/bin/java"
212227
exclude '**/*LFStressTest.*' // lock-freedom tests use LockFreedomTestEnvironment which needs JDK8
213-
exclude '**/*LCStressTest.*' // lin-check tests use LinChecker which needs JDK8
228+
exclude '**/*LincheckTest.*' // Lincheck tests use LinChecker which needs JDK8
214229
exclude '**/exceptions/**' // exceptions tests check suppressed exception which needs JDK8
215230
exclude '**/ExceptionsGuideTest.*'
216231
exclude '**/RunInterruptibleStressTest.*' // fails on JDK 1.6 due to JDK bug
@@ -220,7 +235,7 @@ task jdk16Test(type: Test, dependsOn: [compileTestKotlinJvm, checkJdk16]) {
220235
jdk16Test.onlyIf { project.properties['stressTest'] != null }
221236

222237
// Always run those tests
223-
task moreTest(dependsOn: [jvmStressTest, jdk16Test])
238+
task moreTest(dependsOn: [jvmStressTest, jvmLincheckTest, jdk16Test])
224239
build.dependsOn moreTest
225240

226241
task testsJar(type: Jar, dependsOn: jvmTestClasses) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
package kotlinx.coroutines
5+
6+
import org.jetbrains.kotlinx.lincheck.*
7+
import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.*
8+
import org.jetbrains.kotlinx.lincheck.strategy.stress.*
9+
import org.jetbrains.kotlinx.lincheck.verifier.*
10+
import org.junit.*
11+
12+
abstract class AbstractLincheckTest : VerifierState() {
13+
open fun <O: Options<O, *>> O.customize(isStressTest: Boolean): O = this
14+
15+
@Test
16+
fun modelCheckingTest() = ModelCheckingOptions()
17+
.iterations(if (isStressTest) 100 else 20)
18+
.invocationsPerIteration(if (isStressTest) 10_000 else 1_000)
19+
.commonConfiguration()
20+
.check(this::class)
21+
22+
@Test
23+
fun stressTest() = StressOptions()
24+
.iterations(if (isStressTest) 100 else 20)
25+
.invocationsPerIteration(if (isStressTest) 10_000 else 1_000)
26+
.commonConfiguration()
27+
.check(this::class)
28+
29+
private fun <O : Options<O, *>> O.commonConfiguration(): O = this
30+
.actorsBefore(if (isStressTest) 3 else 1)
31+
.threads(3)
32+
.actorsPerThread(if (isStressTest) 4 else 2)
33+
.actorsAfter(if (isStressTest) 3 else 0)
34+
.customize(isStressTest)
35+
36+
override fun extractState(): Any = error("Not implemented")
37+
}

kotlinx-coroutines-core/jvm/test/LCStressOptionsDefault.kt

-20
This file was deleted.

kotlinx-coroutines-core/jvm/test/linearizability/ChannelsLCStressTest.kt

+12-12
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,37 @@ import kotlinx.coroutines.channels.Channel.Factory.CONFLATED
1111
import kotlinx.coroutines.channels.Channel.Factory.RENDEZVOUS
1212
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
1313
import kotlinx.coroutines.selects.*
14+
import org.jetbrains.kotlinx.lincheck.*
1415
import org.jetbrains.kotlinx.lincheck.annotations.*
1516
import org.jetbrains.kotlinx.lincheck.annotations.Operation
1617
import org.jetbrains.kotlinx.lincheck.paramgen.*
1718
import org.jetbrains.kotlinx.lincheck.verifier.*
18-
import org.junit.*
1919

20-
class RendezvousChannelLCStressTest : ChannelLCStressTestBase(
20+
class RendezvousChannelLincheckTest : ChannelLincheckTestBase(
2121
c = Channel(RENDEZVOUS),
2222
sequentialSpecification = SequentialRendezvousChannel::class.java
2323
)
2424
class SequentialRendezvousChannel : SequentialIntChannelBase(RENDEZVOUS)
2525

26-
class Array1ChannelLCStressTest : ChannelLCStressTestBase(
26+
class Array1ChannelLincheckTest : ChannelLincheckTestBase(
2727
c = Channel(1),
2828
sequentialSpecification = SequentialArray1RendezvousChannel::class.java
2929
)
3030
class SequentialArray1RendezvousChannel : SequentialIntChannelBase(1)
3131

32-
class Array2ChannelLCStressTest : ChannelLCStressTestBase(
32+
class Array2ChannelLincheckTest : ChannelLincheckTestBase(
3333
c = Channel(2),
3434
sequentialSpecification = SequentialArray2RendezvousChannel::class.java
3535
)
3636
class SequentialArray2RendezvousChannel : SequentialIntChannelBase(2)
3737

38-
class UnlimitedChannelLCStressTest : ChannelLCStressTestBase(
38+
class UnlimitedChannelLincheckTest : ChannelLincheckTestBase(
3939
c = Channel(UNLIMITED),
4040
sequentialSpecification = SequentialUnlimitedChannel::class.java
4141
)
4242
class SequentialUnlimitedChannel : SequentialIntChannelBase(UNLIMITED)
4343

44-
class ConflatedChannelLCStressTest : ChannelLCStressTestBase(
44+
class ConflatedChannelLincheckTest : ChannelLincheckTestBase(
4545
c = Channel(CONFLATED),
4646
sequentialSpecification = SequentialConflatedChannel::class.java
4747
)
@@ -51,7 +51,10 @@ class SequentialConflatedChannel : SequentialIntChannelBase(CONFLATED)
5151
Param(name = "value", gen = IntGen::class, conf = "1:5"),
5252
Param(name = "closeToken", gen = IntGen::class, conf = "1:3")
5353
)
54-
abstract class ChannelLCStressTestBase(private val c: Channel<Int>, private val sequentialSpecification: Class<*>) {
54+
abstract class ChannelLincheckTestBase(
55+
private val c: Channel<Int>,
56+
private val sequentialSpecification: Class<*>
57+
) : AbstractLincheckTest() {
5558
@Operation
5659
suspend fun send(@Param(name = "value") value: Int): Any = try {
5760
c.send(value)
@@ -113,11 +116,8 @@ abstract class ChannelLCStressTestBase(private val c: Channel<Int>, private val
113116
// @Operation
114117
fun isEmpty() = c.isEmpty
115118

116-
@Test
117-
fun test() = LCStressOptionsDefault()
118-
.actorsBefore(0)
119-
.sequentialSpecification(sequentialSpecification)
120-
.check(this::class)
119+
override fun <O : Options<O, *>> O.customize(isStressTest: Boolean): O =
120+
actorsBefore(0).sequentialSpecification(sequentialSpecification)
121121
}
122122

123123
private class NumberedCancellationException(number: Int) : CancellationException() {

kotlinx-coroutines-core/jvm/test/linearizability/LockFreeListLCStressTest.kt

+1-6
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@ import kotlinx.coroutines.internal.*
1010
import org.jetbrains.kotlinx.lincheck.annotations.*
1111
import org.jetbrains.kotlinx.lincheck.annotations.Operation
1212
import org.jetbrains.kotlinx.lincheck.paramgen.*
13-
import org.jetbrains.kotlinx.lincheck.verifier.*
14-
import kotlin.test.*
1513

1614
@Param(name = "value", gen = IntGen::class, conf = "1:5")
17-
class LockFreeListLCStressTest : VerifierState() {
15+
class LockFreeListLincheckTest : AbstractLincheckTest() {
1816
class Node(val value: Int): LockFreeLinkedListNode()
1917

2018
private val q: LockFreeLinkedListHead = LockFreeLinkedListHead()
@@ -43,9 +41,6 @@ class LockFreeListLCStressTest : VerifierState() {
4341

4442
private fun Any.isSame(value: Int) = this is Node && this.value == value
4543

46-
@Test
47-
fun testAddRemoveLinearizability() = LCStressOptionsDefault().check(this::class)
48-
4944
override fun extractState(): Any {
5045
val elements = ArrayList<Int>()
5146
q.forEach<Node> { elements.add(it.value) }

kotlinx-coroutines-core/jvm/test/linearizability/LockFreeTaskQueueLCStressTest.kt

+7-10
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@ package kotlinx.coroutines.linearizability
77

88
import kotlinx.coroutines.*
99
import kotlinx.coroutines.internal.*
10+
import org.jetbrains.kotlinx.lincheck.*
1011
import org.jetbrains.kotlinx.lincheck.annotations.*
1112
import org.jetbrains.kotlinx.lincheck.annotations.Operation
1213
import org.jetbrains.kotlinx.lincheck.paramgen.*
13-
import org.jetbrains.kotlinx.lincheck.verifier.*
1414
import org.jetbrains.kotlinx.lincheck.verifier.quiescent.*
15-
import kotlin.test.*
1615

1716
@Param(name = "value", gen = IntGen::class, conf = "1:3")
18-
internal abstract class AbstractLockFreeTaskQueueWithoutRemoveLCStressTest protected constructor(singleConsumer: Boolean) : VerifierState() {
17+
internal abstract class AbstractLockFreeTaskQueueWithoutRemoveLincheckTest protected constructor(singleConsumer: Boolean) : AbstractLincheckTest() {
1918
@JvmField
2019
protected val q = LockFreeTaskQueue<Int>(singleConsumer = singleConsumer)
2120

@@ -29,16 +28,14 @@ internal abstract class AbstractLockFreeTaskQueueWithoutRemoveLCStressTest prote
2928
@Operation(group = "consumer")
3029
fun removeFirstOrNull() = q.removeFirstOrNull()
3130

32-
override fun extractState() = q.map { it } to q.isClosed()
31+
override fun <O : Options<O, *>> O.customize(isStressTest: Boolean): O =
32+
verifier(QuiescentConsistencyVerifier::class.java)
3333

34-
@Test
35-
fun testWithRemoveForQuiescentConsistency() = LCStressOptionsDefault()
36-
.verifier(QuiescentConsistencyVerifier::class.java)
37-
.check(this::class)
34+
override fun extractState() = q.map { it } to q.isClosed()
3835
}
3936

4037
@OpGroupConfig(name = "consumer", nonParallel = false)
41-
internal class MCLockFreeTaskQueueWithRemoveLCStressTest : AbstractLockFreeTaskQueueWithoutRemoveLCStressTest(singleConsumer = false)
38+
internal class MCLockFreeTaskQueueWithRemoveLincheckTest : AbstractLockFreeTaskQueueWithoutRemoveLincheckTest(singleConsumer = false)
4239

4340
@OpGroupConfig(name = "consumer", nonParallel = true)
44-
internal class SCLockFreeTaskQueueWithRemoveLCStressTest : AbstractLockFreeTaskQueueWithoutRemoveLCStressTest(singleConsumer = true)
41+
internal class SCLockFreeTaskQueueWithRemoveLincheckTest : AbstractLockFreeTaskQueueWithoutRemoveLincheckTest(singleConsumer = true)

kotlinx-coroutines-core/jvm/test/linearizability/MutexLCStressTest.kt

+4-7
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@ package kotlinx.coroutines.linearizability
66

77
import kotlinx.coroutines.*
88
import kotlinx.coroutines.sync.*
9+
import org.jetbrains.kotlinx.lincheck.*
910
import org.jetbrains.kotlinx.lincheck.annotations.Operation
10-
import org.jetbrains.kotlinx.lincheck.verifier.*
11-
import org.junit.*
1211

13-
class MutexLCStressTest : VerifierState() {
12+
class MutexLincheckTest : AbstractLincheckTest() {
1413
private val mutex = Mutex()
1514

1615
@Operation
@@ -22,10 +21,8 @@ class MutexLCStressTest : VerifierState() {
2221
@Operation(handleExceptionsAsResult = [IllegalStateException::class])
2322
fun unlock() = mutex.unlock()
2423

25-
@Test
26-
fun test() = LCStressOptionsDefault()
27-
.actorsBefore(0)
28-
.check(this::class)
24+
override fun <O : Options<O, *>> O.customize(isStressTest: Boolean): O =
25+
actorsBefore(0)
2926

3027
override fun extractState() = mutex.isLocked
3128
}

kotlinx-coroutines-core/jvm/test/linearizability/SegmentListRemoveLCStressTest.kt

+5-11
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,11 @@ package kotlinx.coroutines.linearizability
88

99
import kotlinx.coroutines.*
1010
import kotlinx.coroutines.internal.*
11+
import org.jetbrains.kotlinx.lincheck.*
1112
import org.jetbrains.kotlinx.lincheck.annotations.*
12-
import org.jetbrains.kotlinx.lincheck.annotations.Operation
1313
import org.jetbrains.kotlinx.lincheck.paramgen.*
14-
import org.jetbrains.kotlinx.lincheck.verifier.*
15-
import org.junit.*
1614

17-
18-
class SegmentListRemoveLCStressTest : VerifierState() {
15+
class SegmentListRemoveLincheckTest : AbstractLincheckTest() {
1916
private val q = SegmentBasedQueue<Int>()
2017
private val segments: Array<OneElementSegment<Int>>
2118

@@ -29,17 +26,14 @@ class SegmentListRemoveLCStressTest : VerifierState() {
2926
segments[index].removeSegment()
3027
}
3128

29+
override fun <O : Options<O, *>> O.customize(isStressTest: Boolean): O = this
30+
.actorsBefore(0).actorsAfter(0)
31+
3232
override fun extractState() = segments.map { it.logicallyRemoved }
3333

3434
@Validate
3535
fun checkAllRemoved() {
3636
q.checkHeadPrevIsCleaned()
3737
q.checkAllSegmentsAreNotLogicallyRemoved()
3838
}
39-
40-
@Test
41-
fun test() = LCStressOptionsDefault()
42-
.actorsBefore(0)
43-
.actorsAfter(0)
44-
.check(this::class)
4539
}

kotlinx-coroutines-core/jvm/test/linearizability/SegmentQueueLCStressTest.kt

+1-6
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@ import kotlinx.coroutines.internal.SegmentBasedQueue
1010
import org.jetbrains.kotlinx.lincheck.annotations.*
1111
import org.jetbrains.kotlinx.lincheck.annotations.Operation
1212
import org.jetbrains.kotlinx.lincheck.paramgen.*
13-
import org.jetbrains.kotlinx.lincheck.verifier.*
14-
import org.junit.*
1513

1614
@Param(name = "value", gen = IntGen::class, conf = "1:5")
17-
class SegmentQueueLCStressTest : VerifierState() {
15+
class SegmentQueueLincheckTest : AbstractLincheckTest() {
1816
private val q = SegmentBasedQueue<Int>()
1917

2018
@Operation
@@ -39,7 +37,4 @@ class SegmentQueueLCStressTest : VerifierState() {
3937
val closed = q.enqueue(0) === null
4038
return elements to closed
4139
}
42-
43-
@Test
44-
fun test() = LCStressOptionsDefault().check(this::class)
4540
}

kotlinx-coroutines-core/jvm/test/linearizability/SemaphoreLCStressTest.kt

+6-9
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@ package kotlinx.coroutines.linearizability
66

77
import kotlinx.coroutines.*
88
import kotlinx.coroutines.sync.*
9+
import org.jetbrains.kotlinx.lincheck.*
910
import org.jetbrains.kotlinx.lincheck.annotations.Operation
10-
import org.jetbrains.kotlinx.lincheck.verifier.*
11-
import org.junit.*
1211

13-
abstract class SemaphoreLCStressTestBase(permits: Int) : VerifierState() {
12+
abstract class SemaphoreLincheckTestBase(permits: Int) : AbstractLincheckTest() {
1413
private val semaphore = Semaphore(permits)
1514

1615
@Operation
@@ -22,13 +21,11 @@ abstract class SemaphoreLCStressTestBase(permits: Int) : VerifierState() {
2221
@Operation(handleExceptionsAsResult = [IllegalStateException::class])
2322
fun release() = semaphore.release()
2423

25-
@Test
26-
fun test() = LCStressOptionsDefault()
27-
.actorsBefore(0)
28-
.check(this::class)
24+
override fun <O : Options<O, *>> O.customize(isStressTest: Boolean): O =
25+
actorsBefore(0)
2926

3027
override fun extractState() = semaphore.availablePermits
3128
}
3229

33-
class Semaphore1LCStressTest : SemaphoreLCStressTestBase(1)
34-
class Semaphore2LCStressTest : SemaphoreLCStressTestBase(2)
30+
class Semaphore1LincheckTest : SemaphoreLincheckTestBase(1)
31+
class Semaphore2LincheckTest : SemaphoreLincheckTestBase(2)

0 commit comments

Comments
 (0)