cashapp / paparazzi

Render your Android screens without a physical device or emulator
https://cashapp.github.io/paparazzi/
Apache License 2.0
2.25k stars 213 forks source link

Caused by: java.lang.UnsatisfiedLinkError: 'long android.os.Trace.nativeGetEnabledTags()' #1149

Open MedetZhakupov opened 10 months ago

MedetZhakupov commented 10 months ago

Description We use molecule library in our project. And unitests for Composable presenter functions we have are failing when adding paparazzi as dependency. The stacktrace is:

Exception in thread "Test worker @coroutine#2" kotlinx.coroutines.CompletionHandlerException: Exception in completion handler InvokeOnCompletion@26723525[job@80b70fd] for "coroutine#4":StandaloneCoroutine{Cancelled}@80b70fd
    at kotlinx.coroutines.JobSupport.notifyCompletion(JobSupport.kt:1502)
    at kotlinx.coroutines.JobSupport.completeStateFinalization(JobSupport.kt:325)
    at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:242)
    at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:910)
    at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:867)
    at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:832)
    at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:100)
    at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:169)
    at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:112)
    at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
    at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
    at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
    at app.cash.molecule.MoleculeKt$immediateClockFlow$1$1.invokeSuspend(molecule.kt:63)
    at app.cash.molecule.MoleculeKt$immediateClockFlow$1$1.invoke(molecule.kt)
    at app.cash.molecule.MoleculeKt$immediateClockFlow$1$1.invoke(molecule.kt)
    at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:78)
    at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264)
    at app.cash.molecule.MoleculeKt$immediateClockFlow$1.invokeSuspend(molecule.kt:59)
    at app.cash.molecule.MoleculeKt$immediateClockFlow$1.invoke(molecule.kt)
    at app.cash.molecule.MoleculeKt$immediateClockFlow$1.invoke(molecule.kt)
    at kotlinx.coroutines.flow.SafeFlow.collectSafely(Builders.kt:61)
    at kotlinx.coroutines.flow.AbstractFlow.collect(Flow.kt:230)
    at app.cash.turbine.FlowTurbineKt$test$2$collectJob$1.invokeSuspend(FlowTurbine.kt:309)
    at app.cash.turbine.FlowTurbineKt$test$2$collectJob$1.invoke(FlowTurbine.kt)
    at app.cash.turbine.FlowTurbineKt$test$2$collectJob$1.invoke(FlowTurbine.kt)
    at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:44)
    at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:112)
    at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
    at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
    at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
    at app.cash.turbine.FlowTurbineKt$test$2.invokeSuspend(FlowTurbine.kt:58)
    at app.cash.turbine.FlowTurbineKt$test$2.invoke(FlowTurbine.kt)
    at app.cash.turbine.FlowTurbineKt$test$2.invoke(FlowTurbine.kt)
    at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:78)
    at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264)
    at app.cash.turbine.FlowTurbineKt.test-dWUq8MI(FlowTurbine.kt:55)
    at app.cash.turbine.FlowTurbineKt.test-dWUq8MI$default(FlowTurbine.kt:51)
    at com.privatebanking.feature.buysellopinion.ui.details.DetailsPresenterTest$test opinion details successful load$1.invokeSuspend(DetailsPresenterTest.kt:40)
    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.privatebanking.feature.buysellopinion.ui.details.DetailsPresenterTest.test opinion details successful load(DetailsPresenterTest.kt:34)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.base/java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:108)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:40)
    at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:60)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:52)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.base/java.lang.reflect.Method.invoke(Unknown Source)
    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.proxy2/jdk.proxy2.$Proxy5.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176)
    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:113)
    at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
    Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [app.cash.molecule.GatedFrameClock@28effa3f, CoroutineId(4), "coroutine#4":StandaloneCoroutine{Cancelled}@80b70fd, Dispatchers.Unconfined]
Caused by: java.lang.UnsatisfiedLinkError: 'long android.os.Trace.nativeGetEnabledTags()'
    at android.os.Trace.nativeGetEnabledTags(Native Method)
    at android.os.Trace.isTagEnabled(Trace.java:163)
    at android.os.Trace.beginSection(Trace.java:382)
    at androidx.compose.runtime.Trace.beginSection(ActualAndroid.android.kt:31)
    at androidx.compose.runtime.ComposerImpl.dispose$runtime_release(Composer.kt:4573)
    at androidx.compose.runtime.CompositionImpl.dispose(Composition.kt:631)
    at app.cash.molecule.MoleculeKt$launchMolecule$2$2.invoke(molecule.kt:159)
    at app.cash.molecule.MoleculeKt$launchMolecule$2$2.invoke(molecule.kt:158)
    at kotlinx.coroutines.InvokeOnCompletion.invoke(JobSupport.kt:1385)
    at kotlinx.coroutines.JobSupport.notifyCompletion(JobSupport.kt:1497)
    ... 89 more

Expected item but found Error(UnsatisfiedLinkError)
app.cash.turbine.AssertionError: Expected item but found Error(UnsatisfiedLinkError)

Steps to Reproduce

@Test
fun `test functions`() = runBlocking {
            moleculeFlow(mode = RecompositionMode.Immediate) {
                        flowOf("Text")
                    }.test {
                        assertEquals(
                            "Text",
                            expectItem()
                        )
                    }
}

Expected behavior Expectation is to unit test not to fail when adding paparazzi as dependency

Additional information:

Screenshots If applicable, add screenshots to help explain your problem.

MedetZhakupov commented 10 months ago

I have checkout out other similar issues here and noticed that if I put paparazzi rule inside unit test class, as shown below, tests pass as normal.

@get:Rule
    val paparazzi = Paparazzi(
        renderingMode = SessionParams.RenderingMode.SHRINK,
        showSystemUi = false
    )
epool commented 9 months ago

I'm facing exactly the same issue, but I'm only using plain JUnit + Mockito in my unit tests. Adding the Paparazzi test rule fixed it also. Maybe the Paparazzi gradle plugging is doing/missing something under the hood?

the unique place where I'm facing this issue is because my SUT is using a Log.e internally, removing it solved the issue.

jrodbx commented 3 months ago

@epool @MedetZhakupov can one of you provide a repro sample?

jrodbx commented 2 months ago

@epool @MedetZhakupov a repro sample would help get eyes on this.

tordjon commented 2 months ago

@jrodbx https://github.com/tordjon/moleculepaparazzirepro

app.cash.turbine.TurbineAssertionError: Expected item but found Error(UnsatisfiedLinkError) ... at app.cash.turbine.FlowKt$collectIntoChannel$job$1.invokeSuspend(flow.kt:228) Caused by: java.lang.UnsatisfiedLinkError: 'long android.os.Trace.nativeGetEnabledTags()' at android.os.Trace.nativeGetEnabledTags(Native Method) at android.os.Trace.isTagEnabled(Trace.java:163)

Hopefully you'll have a chance to look at it, let me know if you need anything else

    repositories {
        mavenCentral()
        google()
    }
    dependencies {
        classpath 'com.google.gms:google-services:4.4.0'
//        classpath 'app.cash.paparazzi:paparazzi-gradle-plugin:1.3.3' <------
    }
}

plugins {
    id 'com.android.application'
    id 'kotlin-android'
//    id 'app.cash.paparazzi' version '1.3.3'.   <-------
}

Adding back these two lines the test will fail, commenting them out, the test wil pass

geoff-powell commented 1 month ago

hmm, looking at your repro project it seems like adding this to your test file

@get:Rule
val paparazzi = Paparazzi()

Fixes the issue, so there is something layoutlib does that messes up long android.os.Trace.nativeGetEnabledTags() call. Will do some more digging

(related to https://github.com/cashapp/molecule/issues/321)