From ccb96a4377987dffaa72e170ec873e8460c875f6 Mon Sep 17 00:00:00 2001 From: Hanson Ho Date: Mon, 23 Sep 2024 08:31:34 -0700 Subject: [PATCH] Simplify session properties tests to not checked cached payload (#1412) ## Goal Getting the last saved session was flakey in the same way getting the last saved background activity was flakey. Fixed this by just not checking that, but instead checking when the session is done, which is not flakey because that save happens on the main test thread. At the same time, I made the non-flakey saved envelope payload validation function generic and usable for sessions, if we ever need it --- .../IntegrationTestRuleExtensions.kt | 83 +++++++++++-------- .../features/SessionPropertiesTest.kt | 67 +++++---------- .../embracesdk/fakes/FakeDeliveryService.kt | 34 ++++---- 3 files changed, 87 insertions(+), 97 deletions(-) diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/IntegrationTestRuleExtensions.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/IntegrationTestRuleExtensions.kt index 3117323832..83b8687546 100644 --- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/IntegrationTestRuleExtensions.kt +++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/IntegrationTestRuleExtensions.kt @@ -1,7 +1,6 @@ package io.embrace.android.embracesdk import android.app.Activity -import io.embrace.android.embracesdk.fakes.FakeDeliveryService import io.embrace.android.embracesdk.internal.payload.Envelope import io.embrace.android.embracesdk.internal.payload.EventMessage import io.embrace.android.embracesdk.internal.payload.Log @@ -91,11 +90,20 @@ internal fun IntegrationTestRule.Harness.getSentBackgroundActivities(): List? { - return overriddenDeliveryModule.deliveryService.getLastSavedSession() -} +internal fun IntegrationTestRule.Harness.checkNextSavedSession( + action: () -> Unit, + validationFn: (Envelope) -> Unit +): Envelope = + with(overriddenDeliveryModule.deliveryService) { + checkNextSavedSessionEnvelope( + dataProvider = ::getSavedSessions, + action = action, + validationFn = validationFn, + ) + } /** * Run some [action] and the validate the next saved background activity using [validationFn]. If no background activity is saved with @@ -104,36 +112,14 @@ internal fun IntegrationTestRule.Harness.getLastSavedSession(): Envelope Unit, validationFn: (Envelope) -> Unit -): Envelope { +): Envelope = with(overriddenDeliveryModule.deliveryService) { - val startingSize = getSavedBackgroundActivities().size - overriddenClock.tick(10_000L) - action() - return when (getSavedBackgroundActivities().size) { - startingSize -> { - returnIfConditionMet( - desiredValueSupplier = { - getNthBackgroundActivity(startingSize) - }, - condition = { data -> - data.size > startingSize - }, - dataProvider = ::getSavedBackgroundActivities - ) - } - else -> { - getNthBackgroundActivity(startingSize) - } - }.apply { - validationFn(this) - } + checkNextSavedSessionEnvelope( + dataProvider = ::getSavedBackgroundActivities, + action = action, + validationFn = validationFn, + ) } -} - -private fun FakeDeliveryService.getNthBackgroundActivity(n: Int) = - getSavedBackgroundActivities().filterIndexed { index, _ -> - index == n - }.single() /** * Returns the last session that was sent by the SDK. @@ -235,4 +221,35 @@ internal fun returnIfConditionMet( throw TimeoutException("Timeout period elapsed before condition met") } +private fun IntegrationTestRule.Harness.checkNextSavedSessionEnvelope( + dataProvider: () -> List>, + action: () -> Unit, + validationFn: (Envelope) -> Unit +): Envelope { + val startingSize = dataProvider().size + overriddenClock.tick(10_000L) + action() + return when (dataProvider().size) { + startingSize -> { + returnIfConditionMet( + desiredValueSupplier = { + dataProvider().getNth(startingSize) + }, + condition = { data -> + data.size > startingSize + }, + dataProvider = dataProvider + ) + } + + else -> { + dataProvider().getNth(startingSize) + } + }.apply { + validationFn(this) + } +} + +private fun List.getNth(n: Int) = filterIndexed { index, _ -> index == n }.single() + private const val CHECK_INTERVAL_MS: Int = 10 diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/features/SessionPropertiesTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/features/SessionPropertiesTest.kt index e0aa749b1c..87a8064ab5 100644 --- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/features/SessionPropertiesTest.kt +++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/features/SessionPropertiesTest.kt @@ -4,7 +4,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import io.embrace.android.embracesdk.IntegrationTestRule import io.embrace.android.embracesdk.checkNextSavedBackgroundActivity import io.embrace.android.embracesdk.findSessionSpan -import io.embrace.android.embracesdk.getLastSavedSession import io.embrace.android.embracesdk.getLastSentBackgroundActivity import io.embrace.android.embracesdk.getSentBackgroundActivities import io.embrace.android.embracesdk.getSessionId @@ -168,19 +167,12 @@ internal class SessionPropertiesTest { } ) - harness.recordSession { - with(checkNotNull(harness.getLastSavedSession()?.getSessionSpan())) { - assertNotEquals(lastSessionId, embrace.currentSessionId) - assertPropertyExistence( - exist = listOf("perm") - ) - lastSessionId = checkNotNull(embrace.currentSessionId) - } + val session = checkNotNull(harness.recordSession { embrace.addSessionProperty("perm2", "value", true) - checkNotNull(harness.getLastSavedSession()?.getSessionSpan()).assertPropertyExistence( - exist = listOf("perm", "perm2") - ) - } + }) + checkNotNull(session.getSessionSpan()).assertPropertyExistence( + exist = listOf("perm", "perm2") + ) harness.checkNextSavedBackgroundActivity( action = { @@ -197,15 +189,10 @@ internal class SessionPropertiesTest { } ) - harness.recordSession { - with(checkNotNull(harness.getLastSavedSession()?.getSessionSpan())) { - assertNotEquals(lastSessionId, embrace.currentSessionId) - assertPropertyExistence( - exist = listOf("perm", "perm2", "perm3") - ) - lastSessionId = checkNotNull(embrace.currentSessionId) - } - } + val session2 = checkNotNull(harness.recordSession()) + checkNotNull(session2.getSessionSpan()).assertPropertyExistence( + exist = listOf("perm", "perm2", "perm3") + ) } } @@ -215,33 +202,19 @@ internal class SessionPropertiesTest { harness.overriddenConfigService.backgroundActivityCaptureEnabled = false startSdk() embrace.addSessionProperty("perm", "value", true) - var lastSessionId = checkNotNull(harness.recordSession()).getSessionId() - harness.recordSession { - with(checkNotNull(harness.getLastSavedSession()?.getSessionSpan())) { - assertNotEquals(lastSessionId, embrace.currentSessionId) - assertPropertyExistence( - exist = listOf("perm") - ) - lastSessionId = checkNotNull(embrace.currentSessionId) - } + val session = checkNotNull(harness.recordSession { embrace.addSessionProperty("perm2", "value", true) - checkNotNull(harness.getLastSavedSession()?.getSessionSpan()).assertPropertyExistence( - exist = listOf("perm", "perm2") - ) - } - harness.recordSession { - with(checkNotNull(harness.getLastSavedSession()?.getSessionSpan())) { - assertNotEquals(lastSessionId, embrace.currentSessionId) - assertPropertyExistence( - exist = listOf("perm", "perm2") - ) - lastSessionId = checkNotNull(embrace.currentSessionId) - } + }) + checkNotNull(session.getSessionSpan()).assertPropertyExistence( + exist = listOf("perm", "perm2") + ) + + val session2 = checkNotNull(harness.recordSession { embrace.addSessionProperty("perm3", "value", true) - checkNotNull(harness.getLastSavedSession()?.getSessionSpan()).assertPropertyExistence( - exist = listOf("perm", "perm2", "perm3") - ) - } + }) + checkNotNull(session2.getSessionSpan()).assertPropertyExistence( + exist = listOf("perm", "perm2", "perm3") + ) } } diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeDeliveryService.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeDeliveryService.kt index df14522121..6f96b8faec 100644 --- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeDeliveryService.kt +++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeDeliveryService.kt @@ -61,30 +61,30 @@ open class FakeDeliveryService : DeliveryService { lastSavedLogPayloads.add(logEnvelope) } - fun getSentSessions(): List> { - return sentSessionEnvelopes.filter { it.first.findAppState() == ApplicationState.FOREGROUND }.map { it.first } - } + fun getSentSessions(): List> = + sentSessionEnvelopes.filterSessionEnvelopes(appState = ApplicationState.FOREGROUND) - fun getSentBackgroundActivities(): List> { - return sentSessionEnvelopes.filter { it.first.findAppState() == ApplicationState.BACKGROUND }.map { it.first } - } + fun getSentBackgroundActivities(): List> = + sentSessionEnvelopes.filterSessionEnvelopes(appState = ApplicationState.BACKGROUND) - fun getSavedBackgroundActivities(): List> { - return savedSessionEnvelopes.filter { it.first.findAppState() == ApplicationState.BACKGROUND }.map { it.first } - } + fun getSavedSessions(): List> = + savedSessionEnvelopes.filterSessionEnvelopes(appState = ApplicationState.FOREGROUND) - private fun Envelope.findAppState(): ApplicationState { - val value = findSessionSpan().attributes?.findAttributeValue(embState.name)?.uppercase(Locale.ENGLISH) - return ApplicationState.valueOf(checkNotNull(value)) - } + fun getSavedBackgroundActivities(): List> = + savedSessionEnvelopes.filterSessionEnvelopes(appState = ApplicationState.BACKGROUND) fun getLastSentSession(): Envelope? { return getSentSessions().lastOrNull() } - fun getLastSavedSession(): Envelope? { - return savedSessionEnvelopes.map { it.first }.lastOrNull { - it.findAppState() == ApplicationState.FOREGROUND - } + private fun Queue, SessionSnapshotType>>.filterSessionEnvelopes( + appState: ApplicationState + ): List> { + return filter { it.first.findAppState() == appState }.map { it.first } + } + + private fun Envelope.findAppState(): ApplicationState { + val value = findSessionSpan().attributes?.findAttributeValue(embState.name)?.uppercase(Locale.ENGLISH) + return ApplicationState.valueOf(checkNotNull(value)) } }