Loading tracinglib/src/fakeTest/kotlin/com/android/app/tracing/coroutines/CoroutineTracingTest.kt +103 −107 Original line number Diff line number Diff line Loading @@ -19,9 +19,11 @@ package com.android.app.tracing.coroutines import com.android.app.tracing.TraceState.openSectionsOnCurrentThread import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.newSingleThreadContext import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertEquals Loading @@ -40,11 +42,18 @@ private fun assertTraceEquals(vararg openTraceSections: String) { /** Helper util for asserting that there are no open trace sections on the current thread. */ private fun assertTraceIsEmpty() = assertEquals(0, openSectionsOnCurrentThread().size) /** * Helper util for calling [runTest] with a [TraceContextElement]. This is useful for formatting * purposes. Passing an arg to `runTest {}` directly, as in `fun testStuff() = * runTest(TraceContextElement()) {}` would require more indentations according to our style guide. */ private fun runTestWithTraceContext(testBody: suspend TestScope.() -> Unit) = runTest(context = TraceContextElement(), testBody = testBody) @RunWith(BlockJUnit4ClassRunner::class) class CoroutineTracingTest { @Test fun nestedTraceSectionsOnSingleThread() { runTest(TraceContextElement()) { fun nestedTraceSectionsOnSingleThread() = runTestWithTraceContext { val fetchData: suspend () -> String = { delay(1L) traceCoroutine("span-for-fetchData") { Loading @@ -58,14 +67,11 @@ class CoroutineTracingTest { } assertTraceIsEmpty() } } private fun testTraceSectionsMultiThreaded( testContext: CoroutineContext, private fun CoroutineScope.testTraceSectionsMultiThreaded( thread1Context: CoroutineContext, thread2Context: CoroutineContext ) { runTest(testContext) { val fetchData1: suspend () -> String = { assertTraceEquals("span-for-launch-1") delay(1L) Loading @@ -83,11 +89,7 @@ class CoroutineTracingTest { ) delay(1L) traceCoroutine("span-for-fetchData-2") { assertTraceEquals( "span-for-launch-1", "span-for-launch-2", "span-for-fetchData-2" ) assertTraceEquals("span-for-launch-1", "span-for-launch-2", "span-for-fetchData-2") } assertTraceEquals( "span-for-launch-1", Loading @@ -114,56 +116,51 @@ class CoroutineTracingTest { launch(thread1) { assertTraceIsEmpty() } launch(thread2) { assertTraceIsEmpty() } } } @Test fun nestedTraceSectionsMultiThreaded1() { // Thread-#1 and Thread-#2 inherit TraceContextElement from the test context: fun nestedTraceSectionsMultiThreaded1() = runTestWithTraceContext { // Thread-#1 and Thread-#2 inherit TraceContextElement from the test's CoroutineContext. testTraceSectionsMultiThreaded( testContext = TraceContextElement(), thread1Context = EmptyCoroutineContext, thread2Context = EmptyCoroutineContext ) } @Test fun nestedTraceSectionsMultiThreaded2() { // Thread-#2 inherits the TraceContextElement from Thread-#1. The test context does not need // the trace context fun nestedTraceSectionsMultiThreaded2() = runTest { // Thread-#2 inherits the TraceContextElement from Thread-#1. The test's CoroutineContext // does not need a TraceContextElement because it does not do any tracing. testTraceSectionsMultiThreaded( testContext = EmptyCoroutineContext, thread1Context = TraceContextElement(), thread2Context = EmptyCoroutineContext ) } @Test fun nestedTraceSectionsMultiThreaded3() { // Thread-#2 overrides the TraceContextElement from Thread-#1 - but the merging context // should be a no-op. The test context does not need the trace context. fun nestedTraceSectionsMultiThreaded3() = runTest { // Thread-#2 overrides the TraceContextElement from Thread-#1, but the merging context // should be fine; it is essentially a no-op. The test's CoroutineContext does not need the // trace context because it does not do any tracing. testTraceSectionsMultiThreaded( testContext = EmptyCoroutineContext, thread1Context = TraceContextElement(), thread2Context = TraceContextElement() ) } @Test fun nestedTraceSectionsMultiThreaded4() { fun nestedTraceSectionsMultiThreaded4() = runTestWithTraceContext { // TraceContextElement is merged on each context switch, which should have no effect on the // trace results. testTraceSectionsMultiThreaded( testContext = TraceContextElement(), thread1Context = TraceContextElement(), thread2Context = TraceContextElement() ) } @Test fun missingTraceContextObjects() { fun missingTraceContextObjects() = runTest { // Thread-#1 is missing a TraceContextElement, so some of the trace sections get dropped. // The resulting trace sections will be different than the 4 tests above. runTest { val fetchData1: suspend () -> String = { assertTraceIsEmpty() delay(1L) Loading Loading @@ -205,4 +202,3 @@ class CoroutineTracingTest { launch(thread2) { assertTraceIsEmpty() } } } } Loading
tracinglib/src/fakeTest/kotlin/com/android/app/tracing/coroutines/CoroutineTracingTest.kt +103 −107 Original line number Diff line number Diff line Loading @@ -19,9 +19,11 @@ package com.android.app.tracing.coroutines import com.android.app.tracing.TraceState.openSectionsOnCurrentThread import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.newSingleThreadContext import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertEquals Loading @@ -40,11 +42,18 @@ private fun assertTraceEquals(vararg openTraceSections: String) { /** Helper util for asserting that there are no open trace sections on the current thread. */ private fun assertTraceIsEmpty() = assertEquals(0, openSectionsOnCurrentThread().size) /** * Helper util for calling [runTest] with a [TraceContextElement]. This is useful for formatting * purposes. Passing an arg to `runTest {}` directly, as in `fun testStuff() = * runTest(TraceContextElement()) {}` would require more indentations according to our style guide. */ private fun runTestWithTraceContext(testBody: suspend TestScope.() -> Unit) = runTest(context = TraceContextElement(), testBody = testBody) @RunWith(BlockJUnit4ClassRunner::class) class CoroutineTracingTest { @Test fun nestedTraceSectionsOnSingleThread() { runTest(TraceContextElement()) { fun nestedTraceSectionsOnSingleThread() = runTestWithTraceContext { val fetchData: suspend () -> String = { delay(1L) traceCoroutine("span-for-fetchData") { Loading @@ -58,14 +67,11 @@ class CoroutineTracingTest { } assertTraceIsEmpty() } } private fun testTraceSectionsMultiThreaded( testContext: CoroutineContext, private fun CoroutineScope.testTraceSectionsMultiThreaded( thread1Context: CoroutineContext, thread2Context: CoroutineContext ) { runTest(testContext) { val fetchData1: suspend () -> String = { assertTraceEquals("span-for-launch-1") delay(1L) Loading @@ -83,11 +89,7 @@ class CoroutineTracingTest { ) delay(1L) traceCoroutine("span-for-fetchData-2") { assertTraceEquals( "span-for-launch-1", "span-for-launch-2", "span-for-fetchData-2" ) assertTraceEquals("span-for-launch-1", "span-for-launch-2", "span-for-fetchData-2") } assertTraceEquals( "span-for-launch-1", Loading @@ -114,56 +116,51 @@ class CoroutineTracingTest { launch(thread1) { assertTraceIsEmpty() } launch(thread2) { assertTraceIsEmpty() } } } @Test fun nestedTraceSectionsMultiThreaded1() { // Thread-#1 and Thread-#2 inherit TraceContextElement from the test context: fun nestedTraceSectionsMultiThreaded1() = runTestWithTraceContext { // Thread-#1 and Thread-#2 inherit TraceContextElement from the test's CoroutineContext. testTraceSectionsMultiThreaded( testContext = TraceContextElement(), thread1Context = EmptyCoroutineContext, thread2Context = EmptyCoroutineContext ) } @Test fun nestedTraceSectionsMultiThreaded2() { // Thread-#2 inherits the TraceContextElement from Thread-#1. The test context does not need // the trace context fun nestedTraceSectionsMultiThreaded2() = runTest { // Thread-#2 inherits the TraceContextElement from Thread-#1. The test's CoroutineContext // does not need a TraceContextElement because it does not do any tracing. testTraceSectionsMultiThreaded( testContext = EmptyCoroutineContext, thread1Context = TraceContextElement(), thread2Context = EmptyCoroutineContext ) } @Test fun nestedTraceSectionsMultiThreaded3() { // Thread-#2 overrides the TraceContextElement from Thread-#1 - but the merging context // should be a no-op. The test context does not need the trace context. fun nestedTraceSectionsMultiThreaded3() = runTest { // Thread-#2 overrides the TraceContextElement from Thread-#1, but the merging context // should be fine; it is essentially a no-op. The test's CoroutineContext does not need the // trace context because it does not do any tracing. testTraceSectionsMultiThreaded( testContext = EmptyCoroutineContext, thread1Context = TraceContextElement(), thread2Context = TraceContextElement() ) } @Test fun nestedTraceSectionsMultiThreaded4() { fun nestedTraceSectionsMultiThreaded4() = runTestWithTraceContext { // TraceContextElement is merged on each context switch, which should have no effect on the // trace results. testTraceSectionsMultiThreaded( testContext = TraceContextElement(), thread1Context = TraceContextElement(), thread2Context = TraceContextElement() ) } @Test fun missingTraceContextObjects() { fun missingTraceContextObjects() = runTest { // Thread-#1 is missing a TraceContextElement, so some of the trace sections get dropped. // The resulting trace sections will be different than the 4 tests above. runTest { val fetchData1: suspend () -> String = { assertTraceIsEmpty() delay(1L) Loading Loading @@ -205,4 +202,3 @@ class CoroutineTracingTest { launch(thread2) { assertTraceIsEmpty() } } } }