From 1de23304fef4ad017b105e3c89466eebf606b383 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner <markus.hintersteiner@sentry.io> Date: Mon, 27 Nov 2023 13:30:17 +0100 Subject: [PATCH 1/2] Extract Activity Breadcrumbs into own integration --- .../api/sentry-android-core.api | 13 ++ .../core/ActivityBreadcrumbsIntegration.java | 124 +++++++++++++ .../core/ActivityLifecycleIntegration.java | 37 +--- .../core/AndroidOptionsInitializer.java | 1 + .../ActivityBreadcrumbsIntegrationTest.kt | 157 ++++++++++++++++ .../core/ActivityLifecycleIntegrationTest.kt | 173 +----------------- .../core/AndroidOptionsInitializerTest.kt | 9 + .../sentry/android/core/SentryAndroidTest.kt | 3 +- 8 files changed, 312 insertions(+), 205 deletions(-) create mode 100644 sentry-android-core/src/main/java/io/sentry/android/core/ActivityBreadcrumbsIntegration.java create mode 100644 sentry-android-core/src/test/java/io/sentry/android/core/ActivityBreadcrumbsIntegrationTest.kt diff --git a/sentry-android-core/api/sentry-android-core.api b/sentry-android-core/api/sentry-android-core.api index f5511b996c7..8e5ea2abab0 100644 --- a/sentry-android-core/api/sentry-android-core.api +++ b/sentry-android-core/api/sentry-android-core.api @@ -1,3 +1,16 @@ +public final class io/sentry/android/core/ActivityBreadcrumbsIntegration : android/app/Application$ActivityLifecycleCallbacks, io/sentry/Integration, java/io/Closeable { + public fun <init> (Landroid/app/Application;)V + public fun close ()V + public fun onActivityCreated (Landroid/app/Activity;Landroid/os/Bundle;)V + public fun onActivityDestroyed (Landroid/app/Activity;)V + public fun onActivityPaused (Landroid/app/Activity;)V + public fun onActivityResumed (Landroid/app/Activity;)V + public fun onActivitySaveInstanceState (Landroid/app/Activity;Landroid/os/Bundle;)V + public fun onActivityStarted (Landroid/app/Activity;)V + public fun onActivityStopped (Landroid/app/Activity;)V + public fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V +} + public final class io/sentry/android/core/ActivityFramesTracker { public fun <init> (Lio/sentry/android/core/LoadClass;Lio/sentry/android/core/SentryAndroidOptions;)V public fun <init> (Lio/sentry/android/core/LoadClass;Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/android/core/MainLooperHandler;)V diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityBreadcrumbsIntegration.java new file mode 100644 index 00000000000..86cffc153e8 --- /dev/null +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityBreadcrumbsIntegration.java @@ -0,0 +1,124 @@ +package io.sentry.android.core; + +import static io.sentry.TypeCheckHint.ANDROID_ACTIVITY; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.Application; +import android.os.Bundle; +import io.sentry.Breadcrumb; +import io.sentry.Hint; +import io.sentry.IHub; +import io.sentry.Integration; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.util.Objects; +import java.io.Closeable; +import java.io.IOException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** Automatically adds breadcrumbs for Activity Lifecycle Events. */ +public final class ActivityBreadcrumbsIntegration + implements Integration, Closeable, Application.ActivityLifecycleCallbacks { + + private final @NotNull Application application; + private @Nullable IHub hub; + private boolean enabled; + + public ActivityBreadcrumbsIntegration(final @NotNull Application application) { + this.application = Objects.requireNonNull(application, "Application is required"); + } + + @Override + public void register(final @NotNull IHub hub, final @NotNull SentryOptions options) { + final SentryAndroidOptions androidOptions = + Objects.requireNonNull( + (options instanceof SentryAndroidOptions) ? (SentryAndroidOptions) options : null, + "SentryAndroidOptions is required"); + + this.hub = Objects.requireNonNull(hub, "Hub is required"); + this.enabled = androidOptions.isEnableActivityLifecycleBreadcrumbs(); + options + .getLogger() + .log(SentryLevel.DEBUG, "ActivityBreadcrumbsIntegration enabled: %s", enabled); + + if (enabled) { + application.registerActivityLifecycleCallbacks(this); + options.getLogger().log(SentryLevel.DEBUG, "ActivityBreadcrumbIntegration installed."); + addIntegrationToSdkVersion(); + } + } + + @Override + public void close() throws IOException { + if (enabled) { + application.unregisterActivityLifecycleCallbacks(this); + if (hub != null) { + hub.getOptions() + .getLogger() + .log(SentryLevel.DEBUG, "ActivityBreadcrumbsIntegration removed."); + } + } + } + + @Override + public synchronized void onActivityCreated( + final @NotNull Activity activity, final @Nullable Bundle savedInstanceState) { + addBreadcrumb(activity, "created"); + } + + @Override + public synchronized void onActivityStarted(final @NotNull Activity activity) { + addBreadcrumb(activity, "started"); + } + + @SuppressLint("NewApi") + @Override + public synchronized void onActivityResumed(final @NotNull Activity activity) { + addBreadcrumb(activity, "resumed"); + } + + @Override + public synchronized void onActivityPaused(final @NotNull Activity activity) { + addBreadcrumb(activity, "paused"); + } + + @Override + public synchronized void onActivityStopped(final @NotNull Activity activity) { + addBreadcrumb(activity, "stopped"); + } + + @Override + public synchronized void onActivitySaveInstanceState( + final @NotNull Activity activity, final @NotNull Bundle outState) { + addBreadcrumb(activity, "saveInstanceState"); + } + + @Override + public synchronized void onActivityDestroyed(final @NotNull Activity activity) { + addBreadcrumb(activity, "destroyed"); + } + + private void addBreadcrumb(final @NotNull Activity activity, final @NotNull String state) { + if (hub == null) { + return; + } + + final Breadcrumb breadcrumb = new Breadcrumb(); + breadcrumb.setType("navigation"); + breadcrumb.setData("state", state); + breadcrumb.setData("screen", getActivityName(activity)); + breadcrumb.setCategory("ui.lifecycle"); + breadcrumb.setLevel(SentryLevel.INFO); + + final Hint hint = new Hint(); + hint.set(ANDROID_ACTIVITY, activity); + + hub.addBreadcrumb(breadcrumb, hint); + } + + private @NotNull String getActivityName(final @NotNull Activity activity) { + return activity.getClass().getSimpleName(); + } +} diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java index c7ed4ee9b75..429bcdd5527 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java @@ -1,7 +1,6 @@ package io.sentry.android.core; import static io.sentry.MeasurementUnit.Duration.MILLISECOND; -import static io.sentry.TypeCheckHint.ANDROID_ACTIVITY; import android.annotation.SuppressLint; import android.app.Activity; @@ -12,9 +11,7 @@ import android.os.Looper; import android.view.View; import androidx.annotation.NonNull; -import io.sentry.Breadcrumb; import io.sentry.FullyDisplayedReporter; -import io.sentry.Hint; import io.sentry.IHub; import io.sentry.ISpan; import io.sentry.ITransaction; @@ -112,13 +109,6 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio this.hub = Objects.requireNonNull(hub, "Hub is required"); - this.options - .getLogger() - .log( - SentryLevel.DEBUG, - "ActivityLifecycleIntegration enabled: %s", - this.options.isEnableActivityLifecycleBreadcrumbs()); - performanceEnabled = isPerformanceEnabled(this.options); fullyDisplayedReporter = this.options.getFullyDisplayedReporter(); timeToFullDisplaySpanEnabled = this.options.isEnableTimeToFullDisplayTracing(); @@ -143,22 +133,6 @@ public void close() throws IOException { activityFramesTracker.stop(); } - private void addBreadcrumb(final @NotNull Activity activity, final @NotNull String state) { - if (options != null && hub != null && options.isEnableActivityLifecycleBreadcrumbs()) { - final Breadcrumb breadcrumb = new Breadcrumb(); - breadcrumb.setType("navigation"); - breadcrumb.setData("state", state); - breadcrumb.setData("screen", getActivityName(activity)); - breadcrumb.setCategory("ui.lifecycle"); - breadcrumb.setLevel(SentryLevel.INFO); - - final Hint hint = new Hint(); - hint.set(ANDROID_ACTIVITY, activity); - - hub.addBreadcrumb(breadcrumb, hint); - } - } - private @NotNull String getActivityName(final @NotNull Activity activity) { return activity.getClass().getSimpleName(); } @@ -381,7 +355,6 @@ private void finishTransaction( public synchronized void onActivityCreated( final @NotNull Activity activity, final @Nullable Bundle savedInstanceState) { setColdStart(savedInstanceState); - addBreadcrumb(activity, "created"); if (hub != null) { final @Nullable String activityClassName = ClassUtil.getClassName(activity); hub.configureScope(scope -> scope.setScreen(activityClassName)); @@ -407,7 +380,6 @@ public synchronized void onActivityStarted(final @NotNull Activity activity) { // working. Moving this to onActivityStarted fixes the problem. activityFramesTracker.addActivity(activity); } - addBreadcrumb(activity, "started"); } @SuppressLint("NewApi") @@ -438,7 +410,6 @@ public synchronized void onActivityResumed(final @NotNull Activity activity) { mainHandler.post(() -> onFirstFrameDrawn(ttfdSpan, ttidSpan)); } } - addBreadcrumb(activity, "resumed"); } @Override @@ -468,24 +439,22 @@ public synchronized void onActivityPaused(final @NotNull Activity activity) { lastPausedTime = hub.getOptions().getDateProvider().now(); } } - addBreadcrumb(activity, "paused"); } @Override public synchronized void onActivityStopped(final @NotNull Activity activity) { - addBreadcrumb(activity, "stopped"); + // no-op } @Override public synchronized void onActivitySaveInstanceState( final @NotNull Activity activity, final @NotNull Bundle outState) { - addBreadcrumb(activity, "saveInstanceState"); + // no-op } @Override public synchronized void onActivityDestroyed(final @NotNull Activity activity) { - if (performanceEnabled || options.isEnableActivityLifecycleBreadcrumbs()) { - addBreadcrumb(activity, "destroyed"); + if (performanceEnabled) { // in case the appStartSpan isn't completed yet, we finish it as cancelled to avoid // memory leak diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java index 5a0fbef9b24..1b13e39cb47 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java @@ -236,6 +236,7 @@ static void installDefaultIntegrations( options.addIntegration( new ActivityLifecycleIntegration( (Application) context, buildInfoProvider, activityFramesTracker)); + options.addIntegration(new ActivityBreadcrumbsIntegration((Application) context)); options.addIntegration(new CurrentActivityIntegration((Application) context)); options.addIntegration(new UserInteractionIntegration((Application) context, loadClass)); if (isFragmentAvailable) { diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityBreadcrumbsIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityBreadcrumbsIntegrationTest.kt new file mode 100644 index 00000000000..f104acebfac --- /dev/null +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityBreadcrumbsIntegrationTest.kt @@ -0,0 +1,157 @@ +package io.sentry.android.core + +import android.app.Activity +import android.app.Application +import android.os.Bundle +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.sentry.Breadcrumb +import io.sentry.Hub +import io.sentry.SentryLevel +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.check +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import kotlin.test.Test +import kotlin.test.assertEquals + +@RunWith(AndroidJUnit4::class) +class ActivityBreadcrumbsIntegrationTest { + + private class Fixture { + val application = mock<Application>() + val hub = mock<Hub>() + val options = SentryAndroidOptions().apply { + dsn = "https://key@sentry.io/proj" + } + val bundle = mock<Bundle>() + + fun getSut(enabled: Boolean = true): ActivityBreadcrumbsIntegration { + options.isEnableActivityLifecycleBreadcrumbs = enabled + whenever(hub.options).thenReturn(options) + return ActivityBreadcrumbsIntegration( + application + ) + } + } + + private val fixture = Fixture() + + @Test + fun `When ActivityBreadcrumbsIntegration is disabled, it should not register the activity callback`() { + val sut = fixture.getSut(false) + sut.register(fixture.hub, fixture.options) + + verify(fixture.application, never()).registerActivityLifecycleCallbacks(any()) + } + + @Test + fun `When ActivityBreadcrumbsIntegration is enabled, it should register the activity callback`() { + val sut = fixture.getSut() + sut.register(fixture.hub, fixture.options) + + verify(fixture.application).registerActivityLifecycleCallbacks(any()) + + sut.close() + verify(fixture.application).unregisterActivityLifecycleCallbacks(any()) + } + + @Test + fun `When breadcrumb is added, type and category should be set`() { + val sut = fixture.getSut() + sut.register(fixture.hub, fixture.options) + + val activity = mock<Activity>() + sut.onActivityCreated(activity, fixture.bundle) + + verify(fixture.hub).addBreadcrumb( + check<Breadcrumb> { + assertEquals("ui.lifecycle", it.category) + assertEquals("navigation", it.type) + assertEquals(SentryLevel.INFO, it.level) + // cant assert data, its not a public API + }, + anyOrNull() + ) + } + + @Test + fun `When activity is created, it should add a breadcrumb`() { + val sut = fixture.getSut() + sut.register(fixture.hub, fixture.options) + + val activity = mock<Activity>() + sut.onActivityCreated(activity, fixture.bundle) + + verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) + } + + @Test + fun `When activity is started, it should add a breadcrumb`() { + val sut = fixture.getSut() + sut.register(fixture.hub, fixture.options) + + val activity = mock<Activity>() + sut.onActivityStarted(activity) + + verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) + } + + @Test + fun `When activity is resumed, it should add a breadcrumb`() { + val sut = fixture.getSut() + sut.register(fixture.hub, fixture.options) + + val activity = mock<Activity>() + sut.onActivityResumed(activity) + + verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) + } + + @Test + fun `When activity is paused, it should add a breadcrumb`() { + val sut = fixture.getSut() + sut.register(fixture.hub, fixture.options) + + val activity = mock<Activity>() + sut.onActivityPaused(activity) + + verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) + } + + @Test + fun `When activity is stopped, it should add a breadcrumb`() { + val sut = fixture.getSut() + sut.register(fixture.hub, fixture.options) + + val activity = mock<Activity>() + sut.onActivityStopped(activity) + + verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) + } + + @Test + fun `When activity is save instance, it should add a breadcrumb`() { + val sut = fixture.getSut() + sut.register(fixture.hub, fixture.options) + + val activity = mock<Activity>() + sut.onActivitySaveInstanceState(activity, fixture.bundle) + + verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) + } + + @Test + fun `When activity is destroyed, it should add a breadcrumb`() { + val sut = fixture.getSut() + sut.register(fixture.hub, fixture.options) + + val activity = mock<Activity>() + sut.onActivityDestroyed(activity) + + verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) + } +} diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt index 69113a85b80..73b85fc2ccd 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt @@ -10,7 +10,6 @@ import android.view.View import android.view.ViewTreeObserver import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.sentry.Breadcrumb import io.sentry.DateUtils import io.sentry.FullyDisplayedReporter import io.sentry.Hub @@ -19,9 +18,7 @@ import io.sentry.Scope import io.sentry.ScopeCallback import io.sentry.Sentry import io.sentry.SentryDate -import io.sentry.SentryLevel import io.sentry.SentryNanotimeDate -import io.sentry.SentryOptions import io.sentry.SentryTracer import io.sentry.Span import io.sentry.SpanStatus @@ -140,7 +137,7 @@ class ActivityLifecycleIntegrationTest { } @Test - fun `When activity lifecycle breadcrumb is enabled, it registers callback`() { + fun `When ActivityLifecycleIntegration is registered, it registers activity callback`() { val sut = fixture.getSut() sut.register(fixture.hub, fixture.options) @@ -148,75 +145,7 @@ class ActivityLifecycleIntegrationTest { } @Test - fun `When activity lifecycle breadcrumb and tracing are disabled, it still registers callback`() { - val sut = fixture.getSut() - fixture.options.isEnableActivityLifecycleBreadcrumbs = false - - sut.register(fixture.hub, fixture.options) - - verify(fixture.application).registerActivityLifecycleCallbacks(any()) - } - - @Test - fun `When activity lifecycle breadcrumb is disabled but tracing is enabled, it registers callback`() { - val sut = fixture.getSut() - fixture.options.isEnableActivityLifecycleBreadcrumbs = false - fixture.options.enableTracing = true - - sut.register(fixture.hub, fixture.options) - - verify(fixture.application).registerActivityLifecycleCallbacks(any()) - } - - @Test - fun `When activity lifecycle breadcrumb is disabled and tracesSampleRate is set but tracing is disabled, it still registers callback`() { - val sut = fixture.getSut() - fixture.options.isEnableActivityLifecycleBreadcrumbs = false - fixture.options.tracesSampleRate = 1.0 - fixture.options.enableTracing = false - - sut.register(fixture.hub, fixture.options) - - verify(fixture.application).registerActivityLifecycleCallbacks(any()) - } - - @Test - fun `When activity lifecycle breadcrumb is disabled but tracing sample rate is enabled, it registers callback`() { - val sut = fixture.getSut() - fixture.options.isEnableActivityLifecycleBreadcrumbs = false - fixture.options.tracesSampleRate = 1.0 - - sut.register(fixture.hub, fixture.options) - - verify(fixture.application).registerActivityLifecycleCallbacks(any()) - } - - @Test - fun `When activity lifecycle breadcrumb is disabled but tracing sample callback is enabled, it registers callback`() { - val sut = fixture.getSut() - fixture.options.isEnableActivityLifecycleBreadcrumbs = false - fixture.options.tracesSampler = SentryOptions.TracesSamplerCallback { 1.0 } - - sut.register(fixture.hub, fixture.options) - - verify(fixture.application).registerActivityLifecycleCallbacks(any()) - } - - @Test - fun `When activity lifecycle breadcrumb and tracing activity flag are disabled, its still registers callback`() { - val sut = fixture.getSut() - fixture.options.isEnableActivityLifecycleBreadcrumbs = false - fixture.options.tracesSampleRate = 1.0 - fixture.options.tracesSampler = SentryOptions.TracesSamplerCallback { 1.0 } - fixture.options.isEnableAutoActivityLifecycleTracing = false - - sut.register(fixture.hub, fixture.options) - - verify(fixture.application).registerActivityLifecycleCallbacks(any()) - } - - @Test - fun `When ActivityBreadcrumbsIntegration is closed, it should unregister the callback`() { + fun `When ActivityLifecycleIntegration is closed, it should unregister the callback`() { val sut = fixture.getSut() sut.register(fixture.hub, fixture.options) @@ -226,7 +155,7 @@ class ActivityLifecycleIntegrationTest { } @Test - fun `When ActivityBreadcrumbsIntegration is closed, it should close the ActivityFramesTracker`() { + fun `When ActivityLifecycleIntegration is closed, it should close the ActivityFramesTracker`() { val sut = fixture.getSut() sut.register(fixture.hub, fixture.options) @@ -235,102 +164,6 @@ class ActivityLifecycleIntegrationTest { verify(fixture.activityFramesTracker).stop() } - @Test - fun `When breadcrumb is added, type and category should be set`() { - val sut = fixture.getSut() - sut.register(fixture.hub, fixture.options) - - val activity = mock<Activity>() - sut.onActivityCreated(activity, fixture.bundle) - - verify(fixture.hub).addBreadcrumb( - check<Breadcrumb> { - assertEquals("ui.lifecycle", it.category) - assertEquals("navigation", it.type) - assertEquals(SentryLevel.INFO, it.level) - // cant assert data, its not a public API - }, - anyOrNull() - ) - } - - @Test - fun `When activity is created, it should add a breadcrumb`() { - val sut = fixture.getSut() - sut.register(fixture.hub, fixture.options) - - val activity = mock<Activity>() - sut.onActivityCreated(activity, fixture.bundle) - - verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) - } - - @Test - fun `When activity is started, it should add a breadcrumb`() { - val sut = fixture.getSut() - sut.register(fixture.hub, fixture.options) - - val activity = mock<Activity>() - sut.onActivityStarted(activity) - - verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) - } - - @Test - fun `When activity is resumed, it should add a breadcrumb`() { - val sut = fixture.getSut() - sut.register(fixture.hub, fixture.options) - - val activity = mock<Activity>() - sut.onActivityResumed(activity) - - verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) - } - - @Test - fun `When activity is paused, it should add a breadcrumb`() { - val sut = fixture.getSut() - sut.register(fixture.hub, fixture.options) - - val activity = mock<Activity>() - sut.onActivityPaused(activity) - - verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) - } - - @Test - fun `When activity is stopped, it should add a breadcrumb`() { - val sut = fixture.getSut() - sut.register(fixture.hub, fixture.options) - - val activity = mock<Activity>() - sut.onActivityStopped(activity) - - verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) - } - - @Test - fun `When activity is save instance, it should add a breadcrumb`() { - val sut = fixture.getSut() - sut.register(fixture.hub, fixture.options) - - val activity = mock<Activity>() - sut.onActivitySaveInstanceState(activity, fixture.bundle) - - verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) - } - - @Test - fun `When activity is destroyed, it should add a breadcrumb`() { - val sut = fixture.getSut() - sut.register(fixture.hub, fixture.options) - - val activity = mock<Activity>() - sut.onActivityDestroyed(activity) - - verify(fixture.hub).addBreadcrumb(any<Breadcrumb>(), anyOrNull()) - } - @Test fun `When tracing is disabled, do not start tracing`() { val sut = fixture.getSut() diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt index 7f48dcd7ef8..940501af3a4 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt @@ -411,6 +411,15 @@ class AndroidOptionsInitializerTest { assertNull(actual) } + @Test + fun `When given Context is not an Application class, do not add ActivityBreadcrumbsIntegration`() { + fixture.initSut(hasAppContext = false) + + val actual = fixture.sentryOptions.integrations + .firstOrNull { it is ActivityBreadcrumbsIntegration } + assertNull(actual) + } + @Test fun `When given Context is not an Application class, do not add UserInteractionIntegration`() { fixture.initSut(hasAppContext = false) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt index 2a9e20be299..74dca29d113 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt @@ -405,7 +405,7 @@ class SentryAndroidTest { fixture.initSut(context = mock<Application>()) { options -> optionsRef = options options.dsn = "https://key@sentry.io/123" - assertEquals(18, options.integrations.size) + assertEquals(19, options.integrations.size) options.integrations.removeAll { it is UncaughtExceptionHandlerIntegration || it is ShutdownHookIntegration || @@ -415,6 +415,7 @@ class SentryAndroidTest { it is AppLifecycleIntegration || it is AnrIntegration || it is ActivityLifecycleIntegration || + it is ActivityBreadcrumbsIntegration || it is CurrentActivityIntegration || it is UserInteractionIntegration || it is FragmentLifecycleIntegration || From 0c2d3d3897919f2e8baadfa46459c50dda661563 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner <markus.hintersteiner@sentry.io> Date: Mon, 27 Nov 2023 15:06:55 +0100 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6250561b51..6012350cc32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Features - (Internal, Experimental) Attach spans for Application, ContentProvider, and Activities to app-start ([#3057](https://github.com/getsentry/sentry-java/pull/3057)) +- (Internal) Extract Activity Breadcrumbs generation into own Integration ([#3064](https://github.com/getsentry/sentry-java/pull/3064)) ## 6.34.0