Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add simple GPMC tests #558

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,18 @@ internal fun StringBuilder.appendTrace(
val startTraceGraphNode = constructTraceGraph(nThreads, failure, results, trace, exceptionStackTraces)
if (isGeneralPurposeModelCheckingScenario(failure.scenario)) {
val (callNode, actorResultNode) = extractLambdaCallOfGeneralPurposeModelChecking(startTraceGraphNode)
// do not print the method result if it is not expanded
if (!callNode.shouldBeExpanded(verboseTrace = false) && actorResultNode.resultRepresentation != null) {
callNode.lastInternalEvent.next = null
// TODO: This work-around is weird
if (callNode == null) {
appendShortTrace(nThreads, threadNames, listOf(actorResultNode), failure)
} else {
// do not print the method result if it is not expanded
if (!callNode.shouldBeExpanded(verboseTrace = false) && actorResultNode.resultRepresentation != null) {
callNode.lastInternalEvent.next = null
}
appendShortTrace(nThreads, threadNames, listOf(callNode), failure)
callNode.lastInternalEvent.next = actorResultNode
appendDetailedTrace(nThreads, threadNames, listOf(callNode), failure)
}
appendShortTrace(nThreads, threadNames, listOf(callNode), failure)
callNode.lastInternalEvent.next = actorResultNode
appendDetailedTrace(nThreads, threadNames, listOf(callNode), failure)
} else {
appendShortTrace(nThreads, threadNames, startTraceGraphNode, failure)
appendExceptionsStackTracesBlock(exceptionStackTraces)
Expand All @@ -50,14 +55,12 @@ internal fun StringBuilder.appendTrace(
// TODO: please refactor me and trace representation API!
private fun extractLambdaCallOfGeneralPurposeModelChecking(
startTraceGraphNode: List<TraceNode>
): Pair<CallNode, ActorResultNode> {
): Pair<CallNode?, ActorResultNode> {
val actorNode = startTraceGraphNode.firstOrNull() as? ActorNode
val callNode = actorNode?.internalEvents?.firstOrNull() as? CallNode
val actorResultNode = callNode?.lastInternalEvent?.next as? ActorResultNode
val actorResultNode = actorNode?.lastInternalEvent as? ActorResultNode
check(actorNode != null)
check(actorNode.actorRepresentation.startsWith("run"))
check(actorNode.internalEvents.size == 2)
check(callNode != null)
check(actorResultNode != null)
return callNode to actorResultNode
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,52 @@ abstract class BaseRunConcurrentRepresentationTest<R>(private val outputFileName
check(error is LincheckAssertionError) {
"""
|The test should throw LincheckAssertionError, but instead it failed with:
|$error
|${error.stackTraceToString()}
"""
.trimMargin()
}
error.failure.checkLincheckOutput(outputFileName)
}
}

class NoEventsRunConcurrentRepresentationTest : BaseRunConcurrentRepresentationTest<Unit>(
"run_concurrent_test/no_events"
) {
override fun block() {
check(false)
}
}

class IncrementAndFailConcurrentRepresentationTest : BaseRunConcurrentRepresentationTest<Unit>(
"run_concurrent_test/increment_and_fail"
) {
var x = 0

override fun block() {
x++
check(false)
}
}


@Ignore // TODO: does not provide a thread dump
class InfiniteLoopRunConcurrentRepresentationTest : BaseRunConcurrentRepresentationTest<Unit>(
"run_concurrent_test/infinite_loop"
) {
override fun block() {
while (true) {}
}
}

class MainThreadParkRunConcurrentRepresentationTest : BaseRunConcurrentRepresentationTest<Unit>(
"run_concurrent_test/main_thread_park"
) {
override fun block() {
val q = ArrayBlockingQueue<Int>(1)
q.take() // should suspend
}
}

class ArrayReadWriteRunConcurrentRepresentationTest : BaseRunConcurrentRepresentationTest<Unit>(
"run_concurrent_test/array_rw"
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
= Concurrent test failed =

java.lang.IllegalStateException: Check failed.
at org.jetbrains.kotlinx.lincheck_test.representation.IncrementAndFailConcurrentRepresentationTest.block(RunConcurrentRepresentationTests.kt:77)
at org.jetbrains.kotlinx.lincheck_test.representation.IncrementAndFailConcurrentRepresentationTest.block(RunConcurrentRepresentationTests.kt:70)
at org.jetbrains.kotlinx.lincheck_test.representation.BaseRunConcurrentRepresentationTest$testRunWithModelChecker$result$1$1.invoke(RunConcurrentRepresentationTests.kt:42)
at java.base/java.lang.Thread.run(Thread.java:833)

The following interleaving leads to the error:
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Thread 1 |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| IncrementAndFailConcurrentRepresentationTest#1.block(): threw IllegalStateException at BaseRunConcurrentRepresentationTest$testRunWithModelChecker$result$1$1.invoke(RunConcurrentRepresentationTests.kt:42) |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |

Detailed trace:
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Thread 1 |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| IncrementAndFailConcurrentRepresentationTest#1.block(): threw IllegalStateException at BaseRunConcurrentRepresentationTest$testRunWithModelChecker$result$1$1.invoke(RunConcurrentRepresentationTests.kt:42) |
| block(): threw IllegalStateException at IncrementAndFailConcurrentRepresentationTest.block(RunConcurrentRepresentationTests.kt:70) |
| x ➜ 1 at IncrementAndFailConcurrentRepresentationTest.block(RunConcurrentRepresentationTests.kt:76) |
| x = 2 at IncrementAndFailConcurrentRepresentationTest.block(RunConcurrentRepresentationTests.kt:76) |
| result: IllegalStateException #1 |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
= Concurrent test has hung =

The following interleaving leads to the error:
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Thread 1 |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| MainThreadParkRunConcurrentRepresentationTest#1.block() at BaseRunConcurrentRepresentationTest$testRunWithModelChecker$result$1$1.invoke(RunConcurrentRepresentationTests.kt:43) |
| block() at MainThreadParkRunConcurrentRepresentationTest.block(RunConcurrentRepresentationTests.kt:73) |
| ArrayBlockingQueue#1.take() at MainThreadParkRunConcurrentRepresentationTest.block(RunConcurrentRepresentationTests.kt:76) |
| ReentrantLock#1.lockInterruptibly() at ArrayBlockingQueue.take(ArrayBlockingQueue.java:417) |
| ConditionObject#1.await() at ArrayBlockingQueue.take(ArrayBlockingQueue.java:420) |
| enableWait(ConditionNode#1): 1 at AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1611) |
| LockSupport.setCurrentBlocker(ConditionObject#1) at AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1612) |
| canReacquire(ConditionNode#1): false at AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1614) |
| ConditionNode#1.status ➜ 3 at AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1618) |
| ForkJoinPool.managedBlock(ConditionNode#1) at AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1623) |
| ForkJoinPool.unmanagedBlock(ConditionNode#1) at ForkJoinPool.managedBlock(ForkJoinPool.java:3434) |
| ConditionNode#1.isReleasable(): false at ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3463) |
| ConditionNode#1.block() at ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3463) |
| /* The following events repeat infinitely: */ |
| ┌╶> isReleasable(): false at AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) |
| | LockSupport.park() at AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) |
| └╶╶ switch (reason: active lock detected) |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
All unfinished threads are in deadlock

Detailed trace:
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Thread 1 |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| MainThreadParkRunConcurrentRepresentationTest#1.block() at BaseRunConcurrentRepresentationTest$testRunWithModelChecker$result$1$1.invoke(RunConcurrentRepresentationTests.kt:43) |
| block() at MainThreadParkRunConcurrentRepresentationTest.block(RunConcurrentRepresentationTests.kt:73) |
| ArrayBlockingQueue#1.take() at MainThreadParkRunConcurrentRepresentationTest.block(RunConcurrentRepresentationTests.kt:76) |
| ReentrantLock#1.lockInterruptibly() at ArrayBlockingQueue.take(ArrayBlockingQueue.java:417) |
| NonfairSync#1.lockInterruptibly() at ReentrantLock.lockInterruptibly(ReentrantLock.java:372) |
| initialTryLock(): true at ReentrantLock$Sync.lockInterruptibly(ReentrantLock.java:160) |
| compareAndSetState(0, 1): true at ReentrantLock$NonfairSync.initialTryLock(ReentrantLock.java:225) |
| Unsafe#1.compareAndSetInt(NonfairSync#1, 16, 0, 1): true at AbstractQueuedSynchronizer.compareAndSetState(AbstractQueuedSynchronizer.java:556) |
| ConditionObject#1.await() at ArrayBlockingQueue.take(ArrayBlockingQueue.java:420) |
| enableWait(ConditionNode#1): 1 at AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1611) |
| ConditionNode#1.setStatusRelaxed(3) at AbstractQueuedSynchronizer$ConditionObject.enableWait(AbstractQueuedSynchronizer.java:1504) |
| Unsafe#1.putInt(ConditionNode#1, 12, 3) at AbstractQueuedSynchronizer$Node.setStatusRelaxed(AbstractQueuedSynchronizer.java:474) |
| LockSupport.setCurrentBlocker(ConditionObject#1) at AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1612) |
| Unsafe#1.putReferenceOpaque(Thread#1, 76, ConditionObject#1) at LockSupport.setCurrentBlocker(LockSupport.java:161) |
| canReacquire(ConditionNode#1): false at AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1614) |
| ConditionNode#1.prev ➜ null at AbstractQueuedSynchronizer$ConditionObject.canReacquire(AbstractQueuedSynchronizer.java:1527) |
| ConditionNode#1.status ➜ 3 at AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1618) |
| ForkJoinPool.managedBlock(ConditionNode#1) at AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1623) |
| ForkJoinPool.unmanagedBlock(ConditionNode#1) at ForkJoinPool.managedBlock(ForkJoinPool.java:3434) |
| ConditionNode#1.isReleasable(): false at ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3463) |
| status ➜ 3 at AbstractQueuedSynchronizer$ConditionNode.isReleasable(AbstractQueuedSynchronizer.java:502) |
| ConditionNode#1.block() at ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3463) |
| /* The following events repeat infinitely: */ |
| ┌╶> isReleasable(): false at AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) |
| | status ➜ 3 at AbstractQueuedSynchronizer$ConditionNode.isReleasable(AbstractQueuedSynchronizer.java:502) |
| | LockSupport.park() at AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) |
| | PARK at LockSupport.park(LockSupport.java:341) |
| └╶╶ switch (reason: active lock detected) |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
All unfinished threads are in deadlock
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
= Concurrent test failed =

java.lang.IllegalStateException: Check failed.
at org.jetbrains.kotlinx.lincheck_test.representation.NoEventsRunConcurrentRepresentationTest.block(RunConcurrentRepresentationTests.kt:66)
at org.jetbrains.kotlinx.lincheck_test.representation.NoEventsRunConcurrentRepresentationTest.block(RunConcurrentRepresentationTests.kt:62)
at org.jetbrains.kotlinx.lincheck_test.representation.BaseRunConcurrentRepresentationTest$testRunWithModelChecker$result$1$1.invoke(RunConcurrentRepresentationTests.kt:43)
at java.base/java.lang.Thread.run(Thread.java:833)

The following interleaving leads to the error:
| ---------------------------------- |
| Thread 1 |
| ---------------------------------- |
| result: IllegalStateException #1 |
| ---------------------------------- |