compose-multiplatform icon indicating copy to clipboard operation
compose-multiplatform copied to clipboard

[Test] `IllegalArgumentException` randomly throws from `performClick()`

Open sunny-chung opened this issue 2 months ago • 7 comments

Describe the bug While running test cases with runComposeUiTest, when performClick() is called, there is a low but unavoidable chance (about 5%) would throw an exception java.lang.IllegalArgumentException: Detected multithreaded access to SnapshotStateObserver ...

Affected platforms

  • Desktop (macOS)

Versions

  • Kotlin version*: 1.8.0
  • Compose Multiplatform version*: 1.6.0-rc02
  • OS version(s)* (required for Desktop and iOS issues): 14.4.1
  • OS architecture (x86 or arm64): arm64
  • Device (model or simulator for iOS issues):
  • JDK (for desktop issues): 17

To Reproduce I am sorry there is no simple reproducer. Lots of reactive stuffs like MutableSharedFlow were involved inside the app view in my test cases.

I am including a Window() inside runComposeUiTest { setContent { ... } }. Not sure if this is related.

The code throwing exceptions look like this:

runComposeUiTest {
    setContent {
        // ...
    }

    runBlocking {
        // ... // (there is no custom code calling suspending functions nor creating threads here)

        onNodeWithTag(TestTag.CreateRequestOrFolderButton.name)
            .assertIsDisplayed()
            .performClick()
        waitUntilExactlyOneExists(hasTextExactly("Request", includeEditableText = false))
        onNodeWithText("Request")
            .assertIsDisplayed()
            .performClick() // <-- randomly throws IllegalArgumentException

        // ...
    }
}

Expected behavior No exception is thrown.

Screenshots N/A

Additional context

  1. Full stacktrace:
java.lang.IllegalArgumentException: Detected multithreaded access to SnapshotStateObserver: previousThreadId=28), currentThread={id=1, name=Test worker @coroutine#110}. Note that observation on multiple threads in layout/draw is not supported. Make sure your measure/layout/draw for each Owner (AndroidComposeView) is executed on the same thread.
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:245)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeSemanticsReads$ui(OwnerSnapshotObserver.kt:121)
	at androidx.compose.ui.node.LayoutNode.getCollapsedSemantics$ui(LayoutNode.kt:421)
	at androidx.compose.ui.semantics.SemanticsNode$parent$1.invoke(SemanticsNode.kt:343)
	at androidx.compose.ui.semantics.SemanticsNode$parent$1.invoke(SemanticsNode.kt:342)
	at androidx.compose.ui.semantics.SemanticsNodeKt.findClosestParentNode(SemanticsNode.kt:462)
	at androidx.compose.ui.semantics.SemanticsNode.getParent(SemanticsNode.kt:342)
	at androidx.compose.ui.test.OutputKt.printToStringInner(Output.kt:181)
	at androidx.compose.ui.test.OutputKt.printToString(Output.kt:138)
	at androidx.compose.ui.test.OutputKt.printToString$default(Output.kt:136)
	at androidx.compose.ui.test.SemanticsNodeInteraction.fetchOneOrDie(SemanticsNodeInteraction.kt:189)
	at androidx.compose.ui.test.SemanticsNodeInteraction.fetchOneOrDie$default(SemanticsNodeInteraction.kt:150)
	at androidx.compose.ui.test.SemanticsNodeInteraction.fetchSemanticsNode(SemanticsNodeInteraction.kt:84)
	at androidx.compose.ui.test.ActionsKt.performMouseInput(Actions.kt:420)
	at androidx.compose.ui.test.Actions_desktopKt.performClickImpl(Actions.desktop.kt:21)
	at androidx.compose.ui.test.ActionsKt.performClick(Actions.kt:52)
	at com.sunnychung.application.multiplatform.hellohttp.test.RequestResponseTestKt.createAndSendHttpRequest(RequestResponseTest.kt:417)
	at com.sunnychung.application.multiplatform.hellohttp.test.RequestResponseTestKt.createAndSendHttpRequest$default(RequestResponseTest.kt:407)
	at com.sunnychung.application.multiplatform.hellohttp.test.RequestResponseTestKt.createAndSendRestEchoRequestAndAssertResponse(RequestResponseTest.kt:552)
	at com.sunnychung.application.multiplatform.hellohttp.test.RequestResponseTest$echoGet$1.invokeSuspend(RequestResponseTest.kt:79)
	at com.sunnychung.application.multiplatform.hellohttp.test.RequestResponseTest$echoGet$1.invoke(RequestResponseTest.kt)
	at com.sunnychung.application.multiplatform.hellohttp.test.RequestResponseTest$echoGet$1.invoke(RequestResponseTest.kt)
	at com.sunnychung.application.multiplatform.hellohttp.test.RequestResponseTestKt$runTest$1$1.invokeSuspend(RequestResponseTest.kt:375)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:280)
	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
	at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
	at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
	at com.sunnychung.application.multiplatform.hellohttp.test.RequestResponseTestKt$runTest$1.invoke(RequestResponseTest.kt:374)
	at com.sunnychung.application.multiplatform.hellohttp.test.RequestResponseTestKt$runTest$1.invoke(RequestResponseTest.kt:357)
	at androidx.compose.ui.test.SkikoComposeUiTest$runTest$1$1.invoke(ComposeUiTest.skikoMain.kt:146)
	at androidx.compose.ui.test.SkikoComposeUiTest.withScene(ComposeUiTest.skikoMain.kt:154)
	at androidx.compose.ui.test.SkikoComposeUiTest.access$withScene(ComposeUiTest.skikoMain.kt:88)
	at androidx.compose.ui.test.SkikoComposeUiTest$runTest$1.invoke(ComposeUiTest.skikoMain.kt:145)
	at androidx.compose.ui.test.ComposeRootRegistry.withRegistry(ComposeRootRegistry.skiko.kt:83)
	at androidx.compose.ui.test.SkikoComposeUiTest.runTest(ComposeUiTest.skikoMain.kt:144)
	at androidx.compose.ui.test.ComposeUiTest_skikoMainKt.runComposeUiTest(ComposeUiTest.skikoMain.kt:59)
	at androidx.compose.ui.test.ComposeUiTest_skikoMainKt.runComposeUiTest$default(ComposeUiTest.skikoMain.kt:58)
	at com.sunnychung.application.multiplatform.hellohttp.test.RequestResponseTestKt.runTest(RequestResponseTest.kt:357)
	at com.sunnychung.application.multiplatform.hellohttp.test.RequestResponseTest.echoGet(RequestResponseTest.kt:78)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at jdk.proxy1/jdk.proxy1.$Proxy2.stop(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
	at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
  1. It can be worked around by:
fun SemanticsNodeInteraction.performClickWithRetry(host: ComposeUiTest): SemanticsNodeInteraction {
    while (true) {
        try {
            performClick()
            return this
        } catch (e: IllegalArgumentException) {
            host.waitForIdle()
        }
    }
}

and then replacing all performClick() calls to performClickWithRetry(this). Not sure if there is any unwanted side effect.

sunny-chung avatar Apr 30 '24 13:04 sunny-chung

I'll look into it, but why do you need runBlocking in your test?

m-sasha avatar Apr 30 '24 15:04 m-sasha

Also, you shouldn't open real windows inside tests. We may support it in the future by opening mock windows instead, but right now it's not a good idea.

m-sasha avatar Apr 30 '24 15:04 m-sasha

Because a delay() or Thread.sleep() must be introduced in order to make performClick() works after a performTextInput(), even if there is a mainClock.advanceTimeBy() or waitForIdle(). Perhaps it is another bug, or perhaps it is due to the reactive chains I have written.

However, if Thread.sleep() is used instead, regardless of following a waitForIdle() call or not, the frequency of throwing this exception would be > 50%. So I stick with delay().

But it is surprising that the exception also throws before the first delay().

I will try to remove Window() later. I just want to make the tests as realistic as possible, and I thought Window() inside setContent would not create real windows.

sunny-chung avatar Apr 30 '24 15:04 sunny-chung

Please submit a bug report, with a reproducer, where performClick doesn't work after performTextInput.

m-sasha avatar Apr 30 '24 16:04 m-sasha

I tried to take away Window(), but the test never proceeds.

Besides, I encountered the same exception (but different error message) in two more scenarios while running tests. The second one has no workaround.

  1. Throws from assertIsDisplayed().

  2. At the beginning of a test, which is the middle one of a test suite, after a real Window is rendered, an alert dialog with different error message is prompted. Full stacktrace:

Exception in thread "AWT-EventQueue-0 @coroutine#14150" java.lang.IllegalArgumentException: performMeasureAndLayout called during measure layout
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:694)
	at androidx.compose.ui.node.RootNodeOwner$OwnerImpl.measureAndLayout(RootNodeOwner.skiko.kt:290)
	at androidx.compose.ui.node.RootNodeOwner.measureAndLayout(RootNodeOwner.skiko.kt:187)
	at androidx.compose.ui.scene.MultiLayerComposeSceneImpl.measureAndLayout(MultiLayerComposeScene.skiko.kt:247)
	at androidx.compose.ui.scene.BaseComposeScene.doLayout(BaseComposeScene.skiko.kt:225)
	at androidx.compose.ui.scene.BaseComposeScene.access$doLayout(BaseComposeScene.skiko.kt:51)
	at androidx.compose.ui.scene.BaseComposeScene.render(BaseComposeScene.skiko.kt:164)
	at androidx.compose.ui.scene.ComposeSceneMediator$DesktopSkikoView.onRender(ComposeSceneMediator.desktop.kt:490)
	at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:548)
	at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
	at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invokeSuspend(MetalRedrawer.kt:82)
	at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
	at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
	at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [CoroutineId(14150), "coroutine#14150":StandaloneCoroutine{Cancelling}@7828e9db, SwingDispatcher@2efd5058]

kotlinx.coroutines.test.UncaughtExceptionsBeforeTest: There were uncaught exceptions before the test started. Please avoid this, as such exceptions are also reported in a platform-dependent manner so that they are not lost.
	at app//kotlinx.coroutines.test.TestScopeImpl.enter(TestScope.kt:242)
	at app//kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:307)
	at app//kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0(Unknown Source)
	at app//kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0$default(TestBuilders.kt:303)
	at app//kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0$default(Unknown Source)
	at app//androidx.compose.ui.test.SkikoComposeUiTest.withScene(ComposeUiTest.skikoMain.kt:157)
	at app//androidx.compose.ui.test.SkikoComposeUiTest.access$withScene(ComposeUiTest.skikoMain.kt:88)
	at app//androidx.compose.ui.test.SkikoComposeUiTest$runTest$1.invoke(ComposeUiTest.skikoMain.kt:145)
	at app//androidx.compose.ui.test.ComposeRootRegistry.withRegistry(ComposeRootRegistry.skiko.kt:83)
	at app//androidx.compose.ui.test.SkikoComposeUiTest.runTest(ComposeUiTest.skikoMain.kt:144)
	at app//androidx.compose.ui.test.ComposeUiTest_skikoMainKt.runComposeUiTest(ComposeUiTest.skikoMain.kt:59)
	at app//androidx.compose.ui.test.ComposeUiTest_skikoMainKt.runComposeUiTest$default(ComposeUiTest.skikoMain.kt:58)
	at app//com.sunnychung.application.multiplatform.hellohttp.test.RequestResponseTestKt.runTest(RequestResponseTest.kt:465)
	at app//com.sunnychung.application.multiplatform.hellohttp.test.RequestResponseTest.echoPostWithRawBodyAndHeaderAndQueryParameters(RequestResponseTest.kt:214)
	at [email protected]/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at [email protected]/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at [email protected]/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at [email protected]/java.lang.reflect.Method.invoke(Method.java:568)
	at app//org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728)
	at app//org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at app//org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
	at app//org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
	at app//org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
	at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
	at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
	at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
	at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
	at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218)
	at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214)
	at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139)
	at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at [email protected]/java.util.ArrayList.forEach(ArrayList.java:1511)
	at app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at [email protected]/java.util.ArrayList.forEach(ArrayList.java:1511)
	at app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at app//org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at app//org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
	at [email protected]/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at [email protected]/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at [email protected]/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at [email protected]/java.lang.reflect.Method.invoke(Method.java:568)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at jdk.proxy1/jdk.proxy1.$Proxy2.stop(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
	at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
	at app//worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
	at app//worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
	Suppressed: java.lang.IllegalArgumentException: performMeasureAndLayout called during measure layout
		at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:694)
		at androidx.compose.ui.node.RootNodeOwner$OwnerImpl.measureAndLayout(RootNodeOwner.skiko.kt:290)
		at androidx.compose.ui.node.RootNodeOwner.measureAndLayout(RootNodeOwner.skiko.kt:187)
		at androidx.compose.ui.scene.MultiLayerComposeSceneImpl.measureAndLayout(MultiLayerComposeScene.skiko.kt:247)
		at androidx.compose.ui.scene.BaseComposeScene.doLayout(BaseComposeScene.skiko.kt:225)
		at androidx.compose.ui.scene.BaseComposeScene.access$doLayout(BaseComposeScene.skiko.kt:51)
		at androidx.compose.ui.scene.BaseComposeScene.render(BaseComposeScene.skiko.kt:164)
		at androidx.compose.ui.scene.ComposeSceneMediator$DesktopSkikoView.onRender(ComposeSceneMediator.desktop.kt:490)
		at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:548)
		at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
		at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invokeSuspend(MetalRedrawer.kt:82)
		at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
		at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
		at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
		at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
		at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
		at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
		at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
		at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
		at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
		at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
		at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
		at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
		at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
		at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
		at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
		at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
		at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
		at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
		Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [CoroutineId(14150), "coroutine#14150":StandaloneCoroutine{Cancelled}@7828e9db, SwingDispatcher@2efd5058]

sunny-chung avatar May 01 '24 04:05 sunny-chung

Please provide a reproducer. The exception itself is not as useful.

m-sasha avatar May 01 '24 08:05 m-sasha

I tried to create a minified reproducer but could not, so I could only provide a big one.

Git Repository: [email protected]:sunny-chung/hello-http.git Commit: a0572edfcc4fea119d68e5cd52c43e9124224cfb

  1. Run ./gradlew :test-server:bootRun. Wait until Started TestServerApplicationKt in message appears in the stdout log.
  2. Run ./gradlew :ux-and-transport-test:check in another terminal.

It can be observed that some tests fail with the reported exceptions. If the tests are ran repeatedly, the set of failed tests and exceptions can be different.

As I have applied workarounds, most exceptions are UncaughtExceptionsBeforeTest (the last reported one). If you comment out the while loops in SemanticsNodeInteraction.performClickWithRetry and SemanticsNodeInteraction.assertIsDisplayedWithRetry in the file ux-and-transport-test/src/test/kotlin/com/sunnychung/application/multiplatform/hellohttp/test/RequestResponseTestUtil.kt, IllegalArgumentException can be observed.

If you try earlier commits (e.g. 0beaef4de7fed3a5fe7f2eef1ad797fac2258829), the success rate may be higher.

sunny-chung avatar May 02 '24 03:05 sunny-chung