Skip to content

Commit

Permalink
Allow UI Load to be enabled remotely
Browse files Browse the repository at this point in the history
  • Loading branch information
bidetofevil committed Jan 22, 2025
1 parent f29e9ef commit d5d4cd0
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class AutoDataCaptureBehaviorImpl(
const val THERMAL_STATUS_ENABLED_DEFAULT = true
const val V2_STORAGE_ENABLED_DEFAULT = true
const val USE_OKHTTP_DEFAULT = true
const val UI_LOAD_REMOTE_ENABLED_DEFAULT = false
}

override val local = local.enabledFeatures
Expand All @@ -43,8 +44,11 @@ class AutoDataCaptureBehaviorImpl(

override fun isNativeCrashCaptureEnabled(): Boolean = local.isNativeCrashCaptureEnabled()
override fun isDiskUsageCaptureEnabled(): Boolean = local.isDiskUsageCaptureEnabled()
override fun isUiLoadTracingEnabled(): Boolean = local.isUiLoadTracingEnabled()
override fun isUiLoadTracingTraceAll(): Boolean = local.isUiLoadTracingTraceAll()
override fun isUiLoadTracingEnabled(): Boolean = local.isUiLoadTracingEnabled() && uiLoadEnabledRemotely()
override fun isUiLoadTracingTraceAll(): Boolean = local.isUiLoadTracingTraceAll() && uiLoadEnabledRemotely()

private fun uiLoadEnabledRemotely(): Boolean =
remote?.uiLoadInstrumentationEnabled ?: UI_LOAD_REMOTE_ENABLED_DEFAULT

private val v2StorageImpl by lazy {
thresholdCheck.isBehaviorEnabled(remote?.killSwitchConfig?.v2StoragePct) ?: V2_STORAGE_ENABLED_DEFAULT
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package io.embrace.android.embracesdk.internal.config.behavior

import io.embrace.android.embracesdk.fakes.config.FakeEnabledFeatureConfig
import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.fakes.createAutoDataCaptureBehavior
import io.embrace.android.embracesdk.internal.config.remote.DataRemoteConfig
import io.embrace.android.embracesdk.internal.config.remote.KillSwitchRemoteConfig
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.utils.Uuid
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
Expand All @@ -17,7 +20,8 @@ internal class AutoDataCaptureBehaviorImplTest {
v2StoragePct = 100f,
useOkHttpPct = 100f
),
dataConfig = DataRemoteConfig(pctThermalStatusEnabled = 0.0f)
dataConfig = DataRemoteConfig(pctThermalStatusEnabled = 0.0f),
uiLoadInstrumentationEnabled = false,
)

@Test
Expand All @@ -33,8 +37,8 @@ internal class AutoDataCaptureBehaviorImplTest {
assertFalse(isNativeCrashCaptureEnabled())
assertTrue(isDiskUsageCaptureEnabled())
assertTrue(isThermalStatusCaptureEnabled())
assertTrue(isUiLoadTracingEnabled())
assertTrue(isUiLoadTracingTraceAll())
assertFalse(isUiLoadTracingEnabled())
assertFalse(isUiLoadTracingTraceAll())
assertTrue(isThermalStatusCaptureEnabled())
assertTrue(isV2StorageEnabled())
}
Expand Down Expand Up @@ -77,4 +81,55 @@ internal class AutoDataCaptureBehaviorImplTest {
assertTrue(isComposeClickCaptureEnabled())
}
}

@Test
fun `disable ui load remotely`() {
val behavior = createBehavior(
localUiLoadTracingEnabled = true,
localUiLoadTracingTraceAllEnabled = true,
remote = remote.copy(uiLoadInstrumentationEnabled = false)
)

assertFalse(behavior.isUiLoadTracingEnabled())
assertFalse(behavior.isUiLoadTracingTraceAll())
}

@Test
fun `disable ui load locally`() {
val behavior = createBehavior(
localUiLoadTracingEnabled = false,
localUiLoadTracingTraceAllEnabled = false,
remote = remote.copy(uiLoadInstrumentationEnabled = true)
)

assertFalse(behavior.isUiLoadTracingEnabled())
assertFalse(behavior.isUiLoadTracingTraceAll())
}

@Test
fun `disable ui load trace all locally`() {
val behavior = createBehavior(
localUiLoadTracingEnabled = true,
localUiLoadTracingTraceAllEnabled = false,
remote = remote.copy(uiLoadInstrumentationEnabled = true)
)

assertTrue(behavior.isUiLoadTracingEnabled())
assertFalse(behavior.isUiLoadTracingTraceAll())
}

private fun createBehavior(
localUiLoadTracingEnabled: Boolean,
localUiLoadTracingTraceAllEnabled: Boolean,
remote: RemoteConfig,
) = AutoDataCaptureBehaviorImpl(
thresholdCheck = BehaviorThresholdCheck(Uuid::getEmbUuid),
local = FakeInstrumentedConfig(
enabledFeatures = FakeEnabledFeatureConfig(
uiLoadTracingTraceAll = localUiLoadTracingTraceAllEnabled,
uiLoadTracingEnabled = localUiLoadTracingEnabled
)
),
remote = remote
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ internal class DataCaptureServiceModuleImplTest {
assertNotNull(module.appStartupDataCollector)
assertNotNull(module.pushNotificationService)
assertNotNull(module.startupService)
assertNotNull(module.activityLoadEventEmitter)
assertNotNull(module.uiLoadDataListener)
assertNull(module.activityLoadEventEmitter)
assertNull(module.uiLoadDataListener)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,7 @@ data class RemoteConfig(
*/
@Json(name = "webview_vitals_beta")
val webViewVitals: WebViewVitals? = null,

@Json(name = "ui_load_instrumentation_enabled")
val uiLoadInstrumentationEnabled: Boolean? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import io.embrace.android.embracesdk.fakes.config.FakeEnabledFeatureConfig
import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
import io.embrace.android.embracesdk.internal.capture.activity.LifecycleStage
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.payload.ApplicationState
import io.embrace.android.embracesdk.internal.payload.Span
import io.embrace.android.embracesdk.spans.ErrorCode
Expand All @@ -39,11 +40,29 @@ internal class UiLoadTest {

@Config(sdk = [Build.VERSION_CODES.LOLLIPOP])
@Test
fun `activity open creates a trace by default`() {
fun `activity open does not create a trace by default`() {
testRule.runTest(
instrumentedConfig = FakeInstrumentedConfig(
enabledFeatures = FakeEnabledFeatureConfig(bgActivityCapture = true)
enabledFeatures = FakeEnabledFeatureConfig(bgActivityCapture = true),
),
persistedRemoteConfig = RemoteConfig(),
testCaseAction = {
simulateOpeningActivities()
},
assertAction = {
assertTrue(getSingleSessionEnvelope().findSpansOfType(EmbType.Performance.UiLoad).isEmpty())
}
)
}

@Config(sdk = [Build.VERSION_CODES.LOLLIPOP])
@Test
fun `activity open creates a trace by default if remote config is enabled`() {
testRule.runTest(
instrumentedConfig = FakeInstrumentedConfig(
enabledFeatures = FakeEnabledFeatureConfig(bgActivityCapture = true),
),
persistedRemoteConfig = RemoteConfig(uiLoadInstrumentationEnabled = true),
testCaseAction = {
simulateOpeningActivities()
},
Expand All @@ -60,6 +79,7 @@ internal class UiLoadTest {
instrumentedConfig = FakeInstrumentedConfig(
enabledFeatures = FakeEnabledFeatureConfig(uiLoadTracingEnabled = false, bgActivityCapture = true)
),
persistedRemoteConfig = RemoteConfig(uiLoadInstrumentationEnabled = true),
testCaseAction = {
simulateOpeningActivities()
},
Expand All @@ -80,6 +100,7 @@ internal class UiLoadTest {
bgActivityCapture = true
)
),
persistedRemoteConfig = RemoteConfig(uiLoadInstrumentationEnabled = true),
testCaseAction = {
simulateOpeningActivities()
},
Expand All @@ -101,6 +122,7 @@ internal class UiLoadTest {
bgActivityCapture = true
)
),
persistedRemoteConfig = RemoteConfig(uiLoadInstrumentationEnabled = true),
setupAction = {
preLaunchTimeMs = overriddenClock.now()
},
Expand Down Expand Up @@ -150,6 +172,7 @@ internal class UiLoadTest {
bgActivityCapture = true
)
),
persistedRemoteConfig = RemoteConfig(uiLoadInstrumentationEnabled = true),
setupAction = {
preLaunchTimeMs = overriddenClock.now()
},
Expand All @@ -169,7 +192,10 @@ internal class UiLoadTest {
assertEmbraceSpanData(
span = trace,
expectedStartTimeMs = expectedTraceStartTime,
expectedEndTimeMs = expectedTraceStartTime + calculateTotalTime(lifecycleStages = 3, activitiesFullyLoaded = 1),
expectedEndTimeMs = expectedTraceStartTime + calculateTotalTime(
lifecycleStages = 3,
activitiesFullyLoaded = 1
),
expectedParentId = SpanId.getInvalid(),
expectedStatus = Span.Status.ERROR,
expectedErrorCode = ErrorCode.USER_ABANDON,
Expand All @@ -190,6 +216,7 @@ internal class UiLoadTest {
bgActivityCapture = true
)
),
persistedRemoteConfig = RemoteConfig(uiLoadInstrumentationEnabled = true),
testCaseAction = {
simulateOpeningActivities(
activitiesAndActions = listOf(
Expand All @@ -211,6 +238,7 @@ internal class UiLoadTest {
instrumentedConfig = FakeInstrumentedConfig(
enabledFeatures = FakeEnabledFeatureConfig(uiLoadTracingEnabled = true, bgActivityCapture = true)
),
persistedRemoteConfig = RemoteConfig(uiLoadInstrumentationEnabled = true),
setupAction = {
preLaunchTimeMs = overriddenClock.now()
},
Expand Down Expand Up @@ -265,6 +293,7 @@ internal class UiLoadTest {
instrumentedConfig = FakeInstrumentedConfig(
enabledFeatures = FakeEnabledFeatureConfig(uiLoadTracingEnabled = true, bgActivityCapture = true)
),
persistedRemoteConfig = RemoteConfig(uiLoadInstrumentationEnabled = true),
setupAction = {
preLaunchTimeMs = overriddenClock.now()
},
Expand Down Expand Up @@ -320,6 +349,7 @@ internal class UiLoadTest {
instrumentedConfig = FakeInstrumentedConfig(
enabledFeatures = FakeEnabledFeatureConfig(uiLoadTracingEnabled = true, bgActivityCapture = true)
),
persistedRemoteConfig = RemoteConfig(uiLoadInstrumentationEnabled = true),
setupAction = {
preLaunchTimeMs = overriddenClock.now()
},
Expand Down

0 comments on commit d5d4cd0

Please sign in to comment.