From 73a69699001d08a3d40802dbde1524b16e684f2e Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 1 Dec 2023 23:45:06 +0100 Subject: [PATCH 01/31] Bump AGP versions and try to make it green --- .github/workflows/agp-matrix.yml | 21 +++---- .../io/sentry/uitest/android/EnvelopeTests.kt | 58 +++++++++++++++---- 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/.github/workflows/agp-matrix.yml b/.github/workflows/agp-matrix.yml index a8cfa74a7b..14f449d74d 100644 --- a/.github/workflows/agp-matrix.yml +++ b/.github/workflows/agp-matrix.yml @@ -7,22 +7,18 @@ on: - release/** pull_request: -jobs: - cancel-previous-workflow: - runs-on: ubuntu-latest - steps: - - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 - with: - access_token: ${{ github.token }} +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: agp-matrix-compatibility: timeout-minutes: 30 runs-on: ubuntu-latest strategy: fail-fast: false matrix: - agp: [ '8.0.0','8.1.0-alpha11' ] + agp: [ '8.0.0','8.1.4','8.2.0','8.3.0-alpha16' ] integrations: [ true, false ] name: AGP Matrix Release - AGP ${{ matrix.agp }} - Integrations ${{ matrix.integrations }} @@ -34,15 +30,15 @@ jobs: - name: Checkout Repo uses: actions/checkout@v4 - - name: Setup Gradle - uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # pin@v2 - - name: Setup Java Version uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '17' + - name: Setup Gradle + uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # pin@v2 + - name: Setup KVM shell: bash run: | @@ -73,6 +69,7 @@ jobs: disable-animations: true disable-spellchecker: true target: 'aosp_atd' + arch: x86 channel: canary # Necessary for ATDs script: ./gradlew sentry-android-integration-tests:sentry-uitest-android:connectedReleaseAndroidTest -DtestBuildType=release --daemon diff --git a/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt b/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt index fddd0680d1..925853d499 100644 --- a/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt +++ b/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt @@ -9,16 +9,20 @@ import androidx.test.espresso.IdlingRegistry import androidx.test.espresso.action.ViewActions import androidx.test.espresso.matcher.ViewMatchers import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.sentry.NoOpLogger import io.sentry.ProfilingTraceData import io.sentry.Sentry import io.sentry.SentryEvent import io.sentry.android.core.AndroidLogger +import io.sentry.android.core.BuildInfoProvider import io.sentry.android.core.SentryAndroidOptions import io.sentry.assertEnvelopeProfile import io.sentry.assertEnvelopeTransaction import io.sentry.profilemeasurements.ProfileMeasurement import io.sentry.protocol.SentryTransaction +import org.junit.Assume.assumeFalse import org.junit.Assume.assumeNotNull +import org.junit.Assume.assumeThat import org.junit.runner.RunWith import java.util.concurrent.TimeUnit import kotlin.test.Test @@ -66,7 +70,10 @@ class EnvelopeTests : BaseUiTest() { transaction.finish() relay.assert { findEnvelope { - assertEnvelopeTransaction(it.items.toList(), AndroidLogger()).transaction == "ProfilingSampleActivity" + assertEnvelopeTransaction( + it.items.toList(), + AndroidLogger() + ).transaction == "ProfilingSampleActivity" }.assert { val transactionItem: SentryTransaction = it.assertTransaction() it.assertNoOtherItems() @@ -81,11 +88,16 @@ class EnvelopeTests : BaseUiTest() { it.assertNoOtherItems() // We check the measurements have been collected with expected units - val slowFrames = profilingTraceData.measurementsMap[ProfileMeasurement.ID_SLOW_FRAME_RENDERS] - val frozenFrames = profilingTraceData.measurementsMap[ProfileMeasurement.ID_FROZEN_FRAME_RENDERS] - val frameRates = profilingTraceData.measurementsMap[ProfileMeasurement.ID_SCREEN_FRAME_RATES] - val memoryStats = profilingTraceData.measurementsMap[ProfileMeasurement.ID_MEMORY_FOOTPRINT] - val memoryNativeStats = profilingTraceData.measurementsMap[ProfileMeasurement.ID_MEMORY_NATIVE_FOOTPRINT] + val slowFrames = + profilingTraceData.measurementsMap[ProfileMeasurement.ID_SLOW_FRAME_RENDERS] + val frozenFrames = + profilingTraceData.measurementsMap[ProfileMeasurement.ID_FROZEN_FRAME_RENDERS] + val frameRates = + profilingTraceData.measurementsMap[ProfileMeasurement.ID_SCREEN_FRAME_RATES] + val memoryStats = + profilingTraceData.measurementsMap[ProfileMeasurement.ID_MEMORY_FOOTPRINT] + val memoryNativeStats = + profilingTraceData.measurementsMap[ProfileMeasurement.ID_MEMORY_NATIVE_FOOTPRINT] val cpuStats = profilingTraceData.measurementsMap[ProfileMeasurement.ID_CPU_USAGE] // Frame rate could be null in headless emulator tests (agp-matrix workflow) @@ -144,7 +156,12 @@ class EnvelopeTests : BaseUiTest() { // since when the transaction finishes, the frame callback is removed from the activity, // but internally it is already cached and will be called anyway in the next frame. // Also, they are not completely accurate, so they could be flaky. - if (entry.key !in listOf(ProfileMeasurement.ID_FROZEN_FRAME_RENDERS, ProfileMeasurement.ID_SLOW_FRAME_RENDERS, ProfileMeasurement.ID_SCREEN_FRAME_RATES)) { + if (entry.key !in listOf( + ProfileMeasurement.ID_FROZEN_FRAME_RENDERS, + ProfileMeasurement.ID_SLOW_FRAME_RENDERS, + ProfileMeasurement.ID_SCREEN_FRAME_RATES + ) + ) { // There should be no measurement after the profile ends // Due to the nature of frozen frames, they could be measured after the transaction finishes assertTrue( @@ -176,6 +193,12 @@ class EnvelopeTests : BaseUiTest() { @Test fun checkTimedOutProfile() { + assumeFalse( + "Sometimes traceFile does not exist for profiles on emulators and it fails." + + " Although, Android Runtime is the one that manages the file, so something" + + " must be wrong with Debug.startMethodTracing", + BuildInfoProvider(NoOpLogger.getInstance()).isEmulator ?: true + ) // We increase the IdlingResources timeout to exceed the profiling timeout IdlingPolicies.setIdlingResourceTimeout(1, TimeUnit.MINUTES) initSentry(true) { options: SentryAndroidOptions -> @@ -193,7 +216,10 @@ class EnvelopeTests : BaseUiTest() { relay.assert { findEnvelope { Log.e("ITEMS", it.items.joinToString { item -> item.header.type.itemType }) - assertEnvelopeTransaction(it.items.toList(), AndroidLogger()).transaction == "timedOutProfile" + assertEnvelopeTransaction( + it.items.toList(), + AndroidLogger() + ).transaction == "timedOutProfile" }.assert { val transactionItem: SentryTransaction = it.assertTransaction() val profilingTraceData: ProfilingTraceData = it.assertProfile() @@ -201,8 +227,14 @@ class EnvelopeTests : BaseUiTest() { assertEquals("timedOutProfile", transactionItem.transaction) assertEquals("timedOutProfile", profilingTraceData.transactionName) // The profile should timeout after 30 seconds - assertTrue(profilingTraceData.durationNs.toLong() < TimeUnit.SECONDS.toNanos(31), "Profile duration expected to be less than 31 seconds. It was ${profilingTraceData.durationNs.toLong()} ns") - assertEquals(ProfilingTraceData.TRUNCATION_REASON_TIMEOUT, profilingTraceData.truncationReason) + assertTrue( + profilingTraceData.durationNs.toLong() < TimeUnit.SECONDS.toNanos(31), + "Profile duration expected to be less than 31 seconds. It was ${profilingTraceData.durationNs.toLong()} ns" + ) + assertEquals( + ProfilingTraceData.TRUNCATION_REASON_TIMEOUT, + profilingTraceData.truncationReason + ) } assertNoOtherEnvelopes() assertNoOtherRequests() @@ -214,7 +246,8 @@ class EnvelopeTests : BaseUiTest() { // This is a dogfooding test IdlingRegistry.getInstance().register(ProfilingSampleActivity.scrollingIdlingResource) initSentry(false) { options: SentryAndroidOptions -> - options.dsn = "https://640fae2f19ac4ba78ad740175f50195f@o1137848.ingest.sentry.io/6191083" + options.dsn = + "https://640fae2f19ac4ba78ad740175f50195f@o1137848.ingest.sentry.io/6191083" options.tracesSampleRate = 1.0 options.profilesSampleRate = 1.0 } @@ -232,7 +265,8 @@ class EnvelopeTests : BaseUiTest() { private fun swipeList(times: Int) { repeat(times) { Thread.sleep(100) - Espresso.onView(ViewMatchers.withId(R.id.profiling_sample_list)).perform(ViewActions.swipeUp()) + Espresso.onView(ViewMatchers.withId(R.id.profiling_sample_list)) + .perform(ViewActions.swipeUp()) Espresso.onIdle() } } From da6d6fa4d95fe898753072d8643d41efa86f35d9 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 1 Dec 2023 23:56:07 +0100 Subject: [PATCH 02/31] spotless --- .../io/sentry/uitest/android/EnvelopeTests.kt | 49 +++++-------------- 1 file changed, 12 insertions(+), 37 deletions(-) diff --git a/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt b/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt index 925853d499..08f79ee086 100644 --- a/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt +++ b/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt @@ -22,7 +22,6 @@ import io.sentry.profilemeasurements.ProfileMeasurement import io.sentry.protocol.SentryTransaction import org.junit.Assume.assumeFalse import org.junit.Assume.assumeNotNull -import org.junit.Assume.assumeThat import org.junit.runner.RunWith import java.util.concurrent.TimeUnit import kotlin.test.Test @@ -70,10 +69,7 @@ class EnvelopeTests : BaseUiTest() { transaction.finish() relay.assert { findEnvelope { - assertEnvelopeTransaction( - it.items.toList(), - AndroidLogger() - ).transaction == "ProfilingSampleActivity" + assertEnvelopeTransaction(it.items.toList(), AndroidLogger()).transaction == "ProfilingSampleActivity" }.assert { val transactionItem: SentryTransaction = it.assertTransaction() it.assertNoOtherItems() @@ -88,16 +84,11 @@ class EnvelopeTests : BaseUiTest() { it.assertNoOtherItems() // We check the measurements have been collected with expected units - val slowFrames = - profilingTraceData.measurementsMap[ProfileMeasurement.ID_SLOW_FRAME_RENDERS] - val frozenFrames = - profilingTraceData.measurementsMap[ProfileMeasurement.ID_FROZEN_FRAME_RENDERS] - val frameRates = - profilingTraceData.measurementsMap[ProfileMeasurement.ID_SCREEN_FRAME_RATES] - val memoryStats = - profilingTraceData.measurementsMap[ProfileMeasurement.ID_MEMORY_FOOTPRINT] - val memoryNativeStats = - profilingTraceData.measurementsMap[ProfileMeasurement.ID_MEMORY_NATIVE_FOOTPRINT] + val slowFrames = profilingTraceData.measurementsMap[ProfileMeasurement.ID_SLOW_FRAME_RENDERS] + val frozenFrames = profilingTraceData.measurementsMap[ProfileMeasurement.ID_FROZEN_FRAME_RENDERS] + val frameRates = profilingTraceData.measurementsMap[ProfileMeasurement.ID_SCREEN_FRAME_RATES] + val memoryStats = profilingTraceData.measurementsMap[ProfileMeasurement.ID_MEMORY_FOOTPRINT] + val memoryNativeStats = profilingTraceData.measurementsMap[ProfileMeasurement.ID_MEMORY_NATIVE_FOOTPRINT] val cpuStats = profilingTraceData.measurementsMap[ProfileMeasurement.ID_CPU_USAGE] // Frame rate could be null in headless emulator tests (agp-matrix workflow) @@ -156,12 +147,7 @@ class EnvelopeTests : BaseUiTest() { // since when the transaction finishes, the frame callback is removed from the activity, // but internally it is already cached and will be called anyway in the next frame. // Also, they are not completely accurate, so they could be flaky. - if (entry.key !in listOf( - ProfileMeasurement.ID_FROZEN_FRAME_RENDERS, - ProfileMeasurement.ID_SLOW_FRAME_RENDERS, - ProfileMeasurement.ID_SCREEN_FRAME_RATES - ) - ) { + if (entry.key !in listOf(ProfileMeasurement.ID_FROZEN_FRAME_RENDERS, ProfileMeasurement.ID_SLOW_FRAME_RENDERS, ProfileMeasurement.ID_SCREEN_FRAME_RATES)) { // There should be no measurement after the profile ends // Due to the nature of frozen frames, they could be measured after the transaction finishes assertTrue( @@ -216,10 +202,7 @@ class EnvelopeTests : BaseUiTest() { relay.assert { findEnvelope { Log.e("ITEMS", it.items.joinToString { item -> item.header.type.itemType }) - assertEnvelopeTransaction( - it.items.toList(), - AndroidLogger() - ).transaction == "timedOutProfile" + assertEnvelopeTransaction(it.items.toList(), AndroidLogger()).transaction == "timedOutProfile" }.assert { val transactionItem: SentryTransaction = it.assertTransaction() val profilingTraceData: ProfilingTraceData = it.assertProfile() @@ -227,14 +210,8 @@ class EnvelopeTests : BaseUiTest() { assertEquals("timedOutProfile", transactionItem.transaction) assertEquals("timedOutProfile", profilingTraceData.transactionName) // The profile should timeout after 30 seconds - assertTrue( - profilingTraceData.durationNs.toLong() < TimeUnit.SECONDS.toNanos(31), - "Profile duration expected to be less than 31 seconds. It was ${profilingTraceData.durationNs.toLong()} ns" - ) - assertEquals( - ProfilingTraceData.TRUNCATION_REASON_TIMEOUT, - profilingTraceData.truncationReason - ) + assertTrue(profilingTraceData.durationNs.toLong() < TimeUnit.SECONDS.toNanos(31), "Profile duration expected to be less than 31 seconds. It was ${profilingTraceData.durationNs.toLong()} ns") + assertEquals(ProfilingTraceData.TRUNCATION_REASON_TIMEOUT, profilingTraceData.truncationReason) } assertNoOtherEnvelopes() assertNoOtherRequests() @@ -246,8 +223,7 @@ class EnvelopeTests : BaseUiTest() { // This is a dogfooding test IdlingRegistry.getInstance().register(ProfilingSampleActivity.scrollingIdlingResource) initSentry(false) { options: SentryAndroidOptions -> - options.dsn = - "https://640fae2f19ac4ba78ad740175f50195f@o1137848.ingest.sentry.io/6191083" + options.dsn = "https://640fae2f19ac4ba78ad740175f50195f@o1137848.ingest.sentry.io/6191083" options.tracesSampleRate = 1.0 options.profilesSampleRate = 1.0 } @@ -265,8 +241,7 @@ class EnvelopeTests : BaseUiTest() { private fun swipeList(times: Int) { repeat(times) { Thread.sleep(100) - Espresso.onView(ViewMatchers.withId(R.id.profiling_sample_list)) - .perform(ViewActions.swipeUp()) + Espresso.onView(ViewMatchers.withId(R.id.profiling_sample_list)).perform(ViewActions.swipeUp()) Espresso.onIdle() } } From f894244af22bdc5f54c56e5c93365de21b6a89a2 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 27 Dec 2023 23:51:25 +0100 Subject: [PATCH 03/31] Latest 8.3.0 --- .github/workflows/agp-matrix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/agp-matrix.yml b/.github/workflows/agp-matrix.yml index 0719eeb9cb..15827e2b43 100644 --- a/.github/workflows/agp-matrix.yml +++ b/.github/workflows/agp-matrix.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - agp: [ '8.0.0','8.1.4','8.2.0','8.3.0-alpha16' ] + agp: [ '8.0.0','8.1.4','8.2.0','8.3.0-beta01' ] integrations: [ true, false ] name: AGP Matrix Release - AGP ${{ matrix.agp }} - Integrations ${{ matrix.integrations }} From 09d3b4b2fa7ffed170e7c5b910c4d6491e2ba4b9 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 27 Dec 2023 23:51:42 +0100 Subject: [PATCH 04/31] Add more logs to flaky test --- .../src/test/java/io/sentry/android/core/SentryAndroidTest.kt | 3 +++ 1 file changed, 3 insertions(+) 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 4c431e8bc9..bd5b3695fb 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 @@ -21,6 +21,7 @@ import io.sentry.SentryOptions import io.sentry.SentryOptions.BeforeSendCallback import io.sentry.Session import io.sentry.ShutdownHookIntegration +import io.sentry.SystemOutLogger import io.sentry.UncaughtExceptionHandlerIntegration import io.sentry.android.core.cache.AndroidEnvelopeCache import io.sentry.android.core.performance.AppStartMetrics @@ -356,6 +357,8 @@ class SentryAndroidTest { fixture.initSut(context) { it.dsn = "https://key@sentry.io/123" it.cacheDirPath = cacheDir + it.isDebug = true + it.setLogger(SystemOutLogger()) // beforeSend is called after event processors are applied, so we can assert here // against the enriched ANR event it.beforeSend = BeforeSendCallback { event, hint -> From 0674c8088a162116bcf46b7a856cccaf8916dd67 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 27 Dec 2023 23:52:35 +0100 Subject: [PATCH 05/31] Remove assumeThat --- .../java/io/sentry/uitest/android/EnvelopeTests.kt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt b/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt index 08f79ee086..fddd0680d1 100644 --- a/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt +++ b/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt @@ -9,18 +9,15 @@ import androidx.test.espresso.IdlingRegistry import androidx.test.espresso.action.ViewActions import androidx.test.espresso.matcher.ViewMatchers import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.sentry.NoOpLogger import io.sentry.ProfilingTraceData import io.sentry.Sentry import io.sentry.SentryEvent import io.sentry.android.core.AndroidLogger -import io.sentry.android.core.BuildInfoProvider import io.sentry.android.core.SentryAndroidOptions import io.sentry.assertEnvelopeProfile import io.sentry.assertEnvelopeTransaction import io.sentry.profilemeasurements.ProfileMeasurement import io.sentry.protocol.SentryTransaction -import org.junit.Assume.assumeFalse import org.junit.Assume.assumeNotNull import org.junit.runner.RunWith import java.util.concurrent.TimeUnit @@ -179,12 +176,6 @@ class EnvelopeTests : BaseUiTest() { @Test fun checkTimedOutProfile() { - assumeFalse( - "Sometimes traceFile does not exist for profiles on emulators and it fails." + - " Although, Android Runtime is the one that manages the file, so something" + - " must be wrong with Debug.startMethodTracing", - BuildInfoProvider(NoOpLogger.getInstance()).isEmulator ?: true - ) // We increase the IdlingResources timeout to exceed the profiling timeout IdlingPolicies.setIdlingResourceTimeout(1, TimeUnit.MINUTES) initSentry(true) { options: SentryAndroidOptions -> From bfb42ce7bbdf8dbe4c706589c07209629105074a Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 28 Dec 2023 00:30:22 +0100 Subject: [PATCH 06/31] Clean up CI jobs --- .github/workflows/agp-matrix.yml | 5 --- .github/workflows/build.yml | 41 +++++-------------- .github/workflows/codeql-analysis.yml | 25 +++++------ .../integration-tests-benchmarks.yml | 15 ++++--- .github/workflows/integration-tests-ui.yml | 20 ++++----- 5 files changed, 39 insertions(+), 67 deletions(-) diff --git a/.github/workflows/agp-matrix.yml b/.github/workflows/agp-matrix.yml index 15827e2b43..75eb566444 100644 --- a/.github/workflows/agp-matrix.yml +++ b/.github/workflows/agp-matrix.yml @@ -54,11 +54,6 @@ jobs: - name: Make assembleUiTests run: make assembleUiTests - # We stop gradle at the end to make sure the cache folders - # don't contain any lock files and are free to be cached. - - name: Make stop - run: make stop - # We tried to use the cache action to cache gradle stuff, but it made tests slower and timeout - name: Run instrumentation tests uses: reactivecircus/android-emulator-runner@99a4aac18b4df9b3af66c4a1f04c1f23fa10c270 # pin@v2 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2157ccba80..76ad40ff6d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,50 +6,33 @@ on: - release/** pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: - name: Build Job ${{ matrix.os }} - Java ${{ matrix.java }} - runs-on: ${{ matrix.os }} - strategy: - # we want that the matrix keeps running, default is to cancel them if it fails. - fail-fast: false - matrix: - os: [ubuntu-latest] - # Zulu Community distribution of OpenJDK - java: ['17'] + name: Build Job ubuntu-latest - Java 17 + runs-on: ubuntu-latest steps: - - name: Git checkout + - name: Checkout Repo uses: actions/checkout@v4 - - name: 'Set up Java: ${{ matrix.java }}' + - name: Setup Java Version uses: actions/setup-java@v4 with: - java-version: ${{ matrix.java }} distribution: 'temurin' + java-version: '17' - - name: Cache Gradle packages - uses: actions/cache@v3 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- + - name: Setup Gradle + uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # pin@v2 # Clean, check formatting, build and do a dry release - name: Make all run: make all - # We stop gradle at the end to make sure the cache folders - # don't contain any lock files and are free to be cached. - - name: Make stop - run: make stop - - name: Archive packages - # We need artifacts from only one the builds - if: runner.os == 'Linux' && matrix.java == '17' uses: actions/upload-artifact@v4 with: name: ${{ github.sha }} @@ -60,8 +43,6 @@ jobs: ./sentry-android-ndk/build/intermediates/merged_native_libs/release/out/lib/* - name: Upload coverage to Codecov - # We need coverage data from only one the builds - if: runner.os == 'Linux' && matrix.java == '17' uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # pin@v3 with: name: sentry-java diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b139b002a4..59158a4384 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -9,6 +9,10 @@ on: schedule: - cron: '17 23 * * 3' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: analyze: name: Analyze @@ -20,32 +24,25 @@ jobs: language: ['cpp', 'java'] steps: - - name: Checkout repository + - name: Checkout Repo uses: actions/checkout@v4 - - name: 'Set up Java: ${{ matrix.java }}' + - name: Setup Java Version uses: actions/setup-java@v4 with: - java-version: 17 distribution: 'temurin' + java-version: '17' - - name: Cache Gradle packages - uses: actions/cache@v3 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- + - name: Setup Gradle + uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # pin@v2 - name: Initialize CodeQL uses: github/codeql-action/init@cdcdbb579706841c47f7063dda365e292e5cad7a # pin@v2 with: languages: ${{ matrix.language }} - - run: | - ./gradlew assemble + - name: Autobuild + uses: github/codeql-action/autobuild@cdcdbb579706841c47f7063dda365e292e5cad7a # pin@v2 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@cdcdbb579706841c47f7063dda365e292e5cad7a # pin@v2 diff --git a/.github/workflows/integration-tests-benchmarks.yml b/.github/workflows/integration-tests-benchmarks.yml index 4b1e312bb3..c946337c9f 100644 --- a/.github/workflows/integration-tests-benchmarks.yml +++ b/.github/workflows/integration-tests-benchmarks.yml @@ -11,6 +11,10 @@ on: - '**/sentry-android-integration-tests/**' - '**/.github/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: test: name: Benchmarks @@ -30,16 +34,14 @@ jobs: java-version: '17' distribution: 'temurin' + - name: Setup Gradle + uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # pin@v2 + # Clean, build and release a test apk, but only if we will run the benchmark - name: Make assembleBenchmarks if: env.SAUCE_USERNAME != null run: make assembleBenchmarks - # We stop gradle at the end to make sure the cache folders - # don't contain any lock files and are free to be cached. - - name: Make stop - run: make stop - - name: Run All Tests in SauceLab uses: saucelabs/saucectl-run-action@7fe025ef1fdc6f211add3751a6c7d8bba27ba9b1 # pin@v3 if: github.event_name != 'pull_request' && env.SAUCE_USERNAME != null @@ -77,6 +79,9 @@ jobs: java-version: '17' distribution: 'temurin' + - name: Setup Gradle + uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # pin@v2 + - uses: actions/cache@v3 id: app-plain-cache with: diff --git a/.github/workflows/integration-tests-ui.yml b/.github/workflows/integration-tests-ui.yml index 9af4185bff..4071835bc8 100644 --- a/.github/workflows/integration-tests-ui.yml +++ b/.github/workflows/integration-tests-ui.yml @@ -6,15 +6,11 @@ on: - release/** pull_request: -jobs: - cancel-previous-workflow: - runs-on: ubuntu-latest - steps: - - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 - with: - access_token: ${{ github.token }} +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: test: name: Ui tests runs-on: ubuntu-latest @@ -33,16 +29,14 @@ jobs: java-version: '17' distribution: 'temurin' + - name: Setup Gradle + uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # pin@v2 + # Clean, build and release a test apk, but only if we will run the benchmark - name: Make assembleUiTests if: env.SAUCE_USERNAME != null run: make assembleUiTests - # We stop gradle at the end to make sure the cache folders - # don't contain any lock files and are free to be cached. - - name: Make stop - run: make stop - - name: Run Tests in SauceLab uses: saucelabs/saucectl-run-action@7fe025ef1fdc6f211add3751a6c7d8bba27ba9b1 # pin@v3 env: From ba7d60d10ff9804f924779b4577af94981818c1e Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 28 Dec 2023 12:52:12 +0100 Subject: [PATCH 07/31] Enable gradle cache --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 74dc833b22..b867d8ad3e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ -# Daemon’s heap size +# Daemons heap size org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1536m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC - +org.gradle.caching=true org.gradle.parallel=true # AndroidX required by AGP >= 3.6.x From f3b77c4f152a215d6468a6484128d66c01c416f2 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 28 Dec 2023 15:12:05 +0100 Subject: [PATCH 08/31] Upload test results --- .github/workflows/build.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 76ad40ff6d..f8d692413b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,3 +47,11 @@ jobs: with: name: sentry-java fail_ci_if_error: false + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-${{ github.ref }} + path: | + **/build/reports/* From a24c3657f94fd6d7bdb7c9c7136dc31df73854a8 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 28 Dec 2023 16:22:03 +0100 Subject: [PATCH 09/31] Speed up CodeQL builds --- .github/workflows/codeql-analysis.yml | 10 ++++++++-- build.gradle.kts | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 59158a4384..2d9a50c0df 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -41,8 +41,14 @@ jobs: with: languages: ${{ matrix.language }} - - name: Autobuild - uses: github/codeql-action/autobuild@cdcdbb579706841c47f7063dda365e292e5cad7a # pin@v2 + - if: matrix.language == 'cpp' + name: Build Cpp + run: | + ./gradlew sentry-android-ndk:buildCMakeRelWithDebInfo + - if: matrix.language == 'java' + name: Build Java + run: | + ./gradlew buildForCodeQL - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@cdcdbb579706841c47f7063dda365e292e5cad7a # pin@v2 diff --git a/build.gradle.kts b/build.gradle.kts index c3e6eb98eb..0251e3c718 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -266,6 +266,23 @@ gradle.projectsEvaluated { } } } + + tasks.create("buildForCodeQL") { + subprojects + .filter { + !it.displayName.contains("sample") && + !it.displayName.contains("integration-tests") && + !it.displayName.contains("bom") && + it.name != "sentry-opentelemetry" + } + .forEach { proj -> + if (proj.plugins.hasPlugin("com.android.library")) { + this.dependsOn(proj.tasks.findByName("compileReleaseUnitTestSources")) + } else { + this.dependsOn(proj.tasks.findByName("testClasses")) + } + } + } } // Workaround for https://youtrack.jetbrains.com/issue/IDEA-316081/Gradle-8-toolchain-error-Toolchain-from-executable-property-does-not-match-toolchain-from-javaLauncher-property-when-different From 400e26096a3419d7c5ba2e2081e282612908efe1 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 28 Dec 2023 18:50:23 +0100 Subject: [PATCH 10/31] Fix test results upload --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f8d692413b..76570015aa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,6 +52,6 @@ jobs: if: always() uses: actions/upload-artifact@v4 with: - name: test-results-${{ github.ref }} + name: test-results path: | **/build/reports/* From c8515bde0fb7dfbedb6278571233722ba5d9358b Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 28 Dec 2023 20:03:27 +0100 Subject: [PATCH 11/31] Run tests and lint for PRs --- .github/workflows/build.yml | 20 ++++---------------- .github/workflows/generate-javadocs.yml | 11 ++--------- Makefile | 6 +++++- 3 files changed, 11 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 76570015aa..d7db88cbd6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,6 @@ on: push: branches: - main - - release/** pull_request: concurrency: @@ -11,8 +10,8 @@ concurrency: cancel-in-progress: true jobs: - build: - name: Build Job ubuntu-latest - Java 17 + tests-and-lint: + name: Run Tests&Lint runs-on: ubuntu-latest steps: @@ -28,19 +27,8 @@ jobs: - name: Setup Gradle uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # pin@v2 - # Clean, check formatting, build and do a dry release - - name: Make all - run: make all - - - name: Archive packages - uses: actions/upload-artifact@v4 - with: - name: ${{ github.sha }} - if-no-files-found: error - path: | - ./*/build/distributions/*.zip - ./sentry-opentelemetry/*/build/distributions/*.zip - ./sentry-android-ndk/build/intermediates/merged_native_libs/release/out/lib/* + - name: Run Tests with coverage and Lint + run: make preMerge - name: Upload coverage to Codecov uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # pin@v3 diff --git a/.github/workflows/generate-javadocs.yml b/.github/workflows/generate-javadocs.yml index 9bf273b24e..bdf21a67ec 100644 --- a/.github/workflows/generate-javadocs.yml +++ b/.github/workflows/generate-javadocs.yml @@ -16,15 +16,8 @@ jobs: distribution: 'temurin' java-version: '17' - - name: Cache Gradle packages - uses: actions/cache@v3 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- + - name: Setup Gradle + uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # pin@v2 - name: Generate Aggregate Javadocs run: | diff --git a/Makefile b/Makefile index 4ed3732751..c17f6f17e6 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,9 @@ -.PHONY: all clean compile javadocs dryRelease update stop checkFormat format api assembleBenchmarkTestRelease assembleUiTestRelease createCoverageReports +.PHONY: all clean compile javadocs dryRelease update stop checkFormat format api assembleBenchmarkTestRelease assembleUiTestRelease createCoverageReports check preMerge all: stop clean javadocs compile createCoverageReports assembleBenchmarks: stop clean assembleBenchmarkTestRelease assembleUiTests: stop clean assembleUiTestRelease +preMerge: check createCoverageReports # deep clean clean: @@ -57,3 +58,6 @@ assembleUiTestRelease: createCoverageReports: ./gradlew jacocoTestReport ./gradlew koverXmlReportRelease + +check: + ./gradlew check From 894431d076154904e752dcb39dc42d3abf862c42 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 28 Dec 2023 20:04:56 +0100 Subject: [PATCH 12/31] Fix makefile --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index c17f6f17e6..20776222c5 100644 --- a/Makefile +++ b/Makefile @@ -59,5 +59,6 @@ createCoverageReports: ./gradlew jacocoTestReport ./gradlew koverXmlReportRelease +# Run tests and lint check: ./gradlew check From 3acfda234c602deb58f4cc2e9ff2090981e7aff1 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 28 Dec 2023 20:07:33 +0100 Subject: [PATCH 13/31] Fix makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 20776222c5..3d2227a171 100644 --- a/Makefile +++ b/Makefile @@ -61,4 +61,4 @@ createCoverageReports: # Run tests and lint check: - ./gradlew check + ./gradlew check From e84195c558ca661d44c88b3b1c42e49bb9d49a08 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 28 Dec 2023 22:37:27 +0100 Subject: [PATCH 14/31] Only run release-build workflow on release/ branches --- .github/workflows/agp-matrix.yml | 1 - .github/workflows/build.yml | 4 +-- .github/workflows/integration-tests-ui.yml | 1 - .github/workflows/release-build.yml | 40 ++++++++++++++++++++++ Makefile | 5 +-- 5 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/release-build.yml diff --git a/.github/workflows/agp-matrix.yml b/.github/workflows/agp-matrix.yml index 75eb566444..6bf9db20d5 100644 --- a/.github/workflows/agp-matrix.yml +++ b/.github/workflows/agp-matrix.yml @@ -4,7 +4,6 @@ on: push: branches: - main - - release/** pull_request: concurrency: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d7db88cbd6..041d6353a6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,8 +10,8 @@ concurrency: cancel-in-progress: true jobs: - tests-and-lint: - name: Run Tests&Lint + build: + name: Build Job ubuntu-latest - Java 17 runs-on: ubuntu-latest steps: diff --git a/.github/workflows/integration-tests-ui.yml b/.github/workflows/integration-tests-ui.yml index 4071835bc8..2143d0a7bf 100644 --- a/.github/workflows/integration-tests-ui.yml +++ b/.github/workflows/integration-tests-ui.yml @@ -3,7 +3,6 @@ on: push: branches: - main - - release/** pull_request: concurrency: diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml new file mode 100644 index 0000000000..85aa94c583 --- /dev/null +++ b/.github/workflows/release-build.yml @@ -0,0 +1,40 @@ +name: 'Release' +on: + push: + branches: + - release/** + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + release: + name: Build release artifacts + runs-on: ubuntu-latest + + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + + - name: Setup Java Version + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + + - name: Setup Gradle + uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # pin@v2 + + - name: Build artifacts + run: make publish + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ github.sha }} + if-no-files-found: error + path: | + ./*/build/distributions/*.zip + ./sentry-opentelemetry/*/build/distributions/*.zip + ./sentry-android-ndk/build/intermediates/merged_native_libs/release/out/lib/* diff --git a/Makefile b/Makefile index 3d2227a171..0d987996b6 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,10 @@ -.PHONY: all clean compile javadocs dryRelease update stop checkFormat format api assembleBenchmarkTestRelease assembleUiTestRelease createCoverageReports check preMerge +.PHONY: all clean compile javadocs dryRelease update stop checkFormat format api assembleBenchmarkTestRelease assembleUiTestRelease createCoverageReports check preMerge publish all: stop clean javadocs compile createCoverageReports assembleBenchmarks: stop clean assembleBenchmarkTestRelease assembleUiTests: stop clean assembleUiTestRelease preMerge: check createCoverageReports +publish: clean dryRelease # deep clean clean: @@ -19,7 +20,7 @@ javadocs: # do a dry release (like a local deploy) dryRelease: - ./gradlew aggregateJavadocs publishToMavenLocal --no-daemon --no-parallel + ./gradlew aggregateJavadocs distZip # check for dependencies update update: From c8b72b3be0d3684066b756975bd516c050c30a1a Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 28 Dec 2023 22:46:42 +0100 Subject: [PATCH 15/31] Remove unnecessary clean and stop for ui tests --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 0d987996b6..9a23391aa5 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ .PHONY: all clean compile javadocs dryRelease update stop checkFormat format api assembleBenchmarkTestRelease assembleUiTestRelease createCoverageReports check preMerge publish all: stop clean javadocs compile createCoverageReports -assembleBenchmarks: stop clean assembleBenchmarkTestRelease -assembleUiTests: stop clean assembleUiTestRelease +assembleBenchmarks: assembleBenchmarkTestRelease +assembleUiTests: assembleUiTestRelease preMerge: check createCoverageReports publish: clean dryRelease From 3e4913c8b0c7000d1be1c12f54269fefebf0f1ee Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 29 Dec 2023 00:26:10 +0100 Subject: [PATCH 16/31] Parallelize tests --- build.gradle.kts | 5 +++++ .../src/test/java/io/sentry/JsonSerializerTest.kt | 7 +++++++ .../sentry/protocol/SdkVersionSerializationTest.kt | 8 +++++++- .../protocol/SentryBaseEventSerializationTest.kt | 13 +++++++++++++ .../SentryEnvelopeHeaderSerializationTest.kt | 13 +++++++++++++ .../sentry/protocol/SentryEventSerializationTest.kt | 13 +++++++++++++ .../protocol/SentryTransactionSerializationTest.kt | 13 +++++++++++++ 7 files changed, 71 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 0251e3c718..dd566028f4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -91,6 +91,11 @@ allprojects { TestLogEvent.PASSED, TestLogEvent.FAILED ) + maxParallelForks = Runtime.getRuntime().availableProcessors() / 2 + + // Cap JVM args per test + minHeapSize = "128m" + maxHeapSize = "1g" dependsOn("cleanTest") } withType { diff --git a/sentry/src/test/java/io/sentry/JsonSerializerTest.kt b/sentry/src/test/java/io/sentry/JsonSerializerTest.kt index 93fb64c5b0..572319e2f0 100644 --- a/sentry/src/test/java/io/sentry/JsonSerializerTest.kt +++ b/sentry/src/test/java/io/sentry/JsonSerializerTest.kt @@ -8,6 +8,7 @@ import io.sentry.protocol.SdkVersion import io.sentry.protocol.SentryId import io.sentry.protocol.SentrySpan import io.sentry.protocol.SentryTransaction +import org.junit.After import org.mockito.kotlin.any import org.mockito.kotlin.check import org.mockito.kotlin.eq @@ -62,6 +63,12 @@ class JsonSerializerTest { @BeforeTest fun before() { fixture = Fixture() + SentryIntegrationPackageStorage.getInstance().clearStorage() + } + + @After + fun teardown() { + SentryIntegrationPackageStorage.getInstance().clearStorage() } private fun serializeToString(ev: T): String { diff --git a/sentry/src/test/java/io/sentry/protocol/SdkVersionSerializationTest.kt b/sentry/src/test/java/io/sentry/protocol/SdkVersionSerializationTest.kt index ee3d72add9..44d15eca66 100644 --- a/sentry/src/test/java/io/sentry/protocol/SdkVersionSerializationTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/SdkVersionSerializationTest.kt @@ -6,6 +6,7 @@ import io.sentry.JsonObjectReader import io.sentry.JsonObjectWriter import io.sentry.JsonSerializable import io.sentry.SentryIntegrationPackageStorage +import org.junit.After import org.junit.Before import org.junit.Test import org.mockito.kotlin.mock @@ -35,7 +36,12 @@ class SdkVersionSerializationTest { private val fixture = Fixture() @Before - fun clearIntegrationPackageStorage() { + fun setup() { + SentryIntegrationPackageStorage.getInstance().clearStorage() + } + + @After + fun teardown() { SentryIntegrationPackageStorage.getInstance().clearStorage() } diff --git a/sentry/src/test/java/io/sentry/protocol/SentryBaseEventSerializationTest.kt b/sentry/src/test/java/io/sentry/protocol/SentryBaseEventSerializationTest.kt index 49608a8664..4bc13559da 100644 --- a/sentry/src/test/java/io/sentry/protocol/SentryBaseEventSerializationTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/SentryBaseEventSerializationTest.kt @@ -6,7 +6,10 @@ import io.sentry.JsonObjectReader import io.sentry.JsonSerializable import io.sentry.ObjectWriter import io.sentry.SentryBaseEvent +import io.sentry.SentryIntegrationPackageStorage import io.sentry.vendor.gson.stream.JsonToken +import org.junit.After +import org.junit.Before import org.junit.Test import org.mockito.kotlin.mock import kotlin.test.assertEquals @@ -76,6 +79,16 @@ class SentryBaseEventSerializationTest { } private val fixture = Fixture() + @Before + fun setup() { + SentryIntegrationPackageStorage.getInstance().clearStorage() + } + + @After + fun teardown() { + SentryIntegrationPackageStorage.getInstance().clearStorage() + } + @Test fun serialize() { val expected = SerializationUtils.sanitizedFile("json/sentry_base_event.json") diff --git a/sentry/src/test/java/io/sentry/protocol/SentryEnvelopeHeaderSerializationTest.kt b/sentry/src/test/java/io/sentry/protocol/SentryEnvelopeHeaderSerializationTest.kt index 8261161095..5b9edd7299 100644 --- a/sentry/src/test/java/io/sentry/protocol/SentryEnvelopeHeaderSerializationTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/SentryEnvelopeHeaderSerializationTest.kt @@ -7,7 +7,10 @@ import io.sentry.JsonObjectReader import io.sentry.JsonObjectWriter import io.sentry.JsonSerializable import io.sentry.SentryEnvelopeHeader +import io.sentry.SentryIntegrationPackageStorage import io.sentry.TraceContextSerializationTest +import org.junit.After +import org.junit.Before import org.junit.Test import org.mockito.kotlin.mock import java.io.StringReader @@ -29,6 +32,16 @@ class SentryEnvelopeHeaderSerializationTest { } private val fixture = Fixture() + @Before + fun setup() { + SentryIntegrationPackageStorage.getInstance().clearStorage() + } + + @After + fun teardown() { + SentryIntegrationPackageStorage.getInstance().clearStorage() + } + @Test fun serialize() { val expected = sanitizedFile("json/sentry_envelope_header.json") diff --git a/sentry/src/test/java/io/sentry/protocol/SentryEventSerializationTest.kt b/sentry/src/test/java/io/sentry/protocol/SentryEventSerializationTest.kt index 83a60d555b..d51ac1dc13 100644 --- a/sentry/src/test/java/io/sentry/protocol/SentryEventSerializationTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/SentryEventSerializationTest.kt @@ -7,7 +7,10 @@ import io.sentry.JsonObjectReader import io.sentry.JsonObjectWriter import io.sentry.JsonSerializable import io.sentry.SentryEvent +import io.sentry.SentryIntegrationPackageStorage import io.sentry.SentryLevel +import org.junit.After +import org.junit.Before import org.junit.Test import org.mockito.kotlin.mock import java.io.StringReader @@ -42,6 +45,16 @@ class SentryEventSerializationTest { } private val fixture = Fixture() + @Before + fun setup() { + SentryIntegrationPackageStorage.getInstance().clearStorage() + } + + @After + fun teardown() { + SentryIntegrationPackageStorage.getInstance().clearStorage() + } + @Test fun serialize() { val expected = sanitizedFile("json/sentry_event.json") diff --git a/sentry/src/test/java/io/sentry/protocol/SentryTransactionSerializationTest.kt b/sentry/src/test/java/io/sentry/protocol/SentryTransactionSerializationTest.kt index bfe6a1a2e7..ed21426a57 100644 --- a/sentry/src/test/java/io/sentry/protocol/SentryTransactionSerializationTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/SentryTransactionSerializationTest.kt @@ -6,6 +6,9 @@ import io.sentry.ILogger import io.sentry.JsonObjectReader import io.sentry.JsonObjectWriter import io.sentry.JsonSerializable +import io.sentry.SentryIntegrationPackageStorage +import org.junit.After +import org.junit.Before import org.junit.Test import org.mockito.kotlin.mock import java.io.StringReader @@ -35,6 +38,16 @@ class SentryTransactionSerializationTest { } private val fixture = Fixture() + @Before + fun setup() { + SentryIntegrationPackageStorage.getInstance().clearStorage() + } + + @After + fun teardown() { + SentryIntegrationPackageStorage.getInstance().clearStorage() + } + @Test fun serialize() { val expected = sanitizedFile("json/sentry_transaction.json") From 77093aee9a113fb81f1d48b1fb0581e3ba93f1d4 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 29 Dec 2023 11:58:15 +0100 Subject: [PATCH 17/31] Speed up tests depending on session finalizer --- .../sentry/android/core/AnrV2IntegrationTest.kt | 16 +++++++++------- .../main/java/io/sentry/cache/EnvelopeCache.java | 8 +++++++- .../io/sentry/PreviousSessionFinalizerTest.kt | 2 ++ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AnrV2IntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AnrV2IntegrationTest.kt index 7fce1a126e..77267d7154 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AnrV2IntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AnrV2IntegrationTest.kt @@ -67,6 +67,7 @@ class AnrV2IntegrationTest { useImmediateExecutorService: Boolean = true, isAnrEnabled: Boolean = true, flushTimeoutMillis: Long = 0L, + sessionFlushTimeoutMillis: Long = 0L, lastReportedAnrTimestamp: Long? = null, lastEventId: SentryId = SentryId(), sessionTrackingEnabled: Boolean = true, @@ -86,13 +87,14 @@ class AnrV2IntegrationTest { this.isAttachAnrThreadDump = attachAnrThreadDump addInAppInclude("io.sentry.samples") setEnvelopeDiskCache(EnvelopeCache.create(this)) + (envelopeDiskCache as? EnvelopeCache) + ?.overrideSessionFlushTimeout(sessionFlushTimeoutMillis) } options.cacheDirPath?.let { cacheDir -> lastReportedAnrFile = File(cacheDir, AndroidEnvelopeCache.LAST_ANR_REPORT) lastReportedAnrFile.writeText(lastReportedAnrTimestamp.toString()) } whenever(hub.captureEvent(any(), anyOrNull())).thenReturn(lastEventId) - return AnrV2Integration(context) } @@ -306,7 +308,7 @@ class AnrV2IntegrationTest { val integration = fixture.getSut( tmpDir, lastReportedAnrTimestamp = oldTimestamp, - flushTimeoutMillis = 1000L + flushTimeoutMillis = 500L ) fixture.addAppExitInfo(timestamp = newTimestamp) @@ -314,7 +316,7 @@ class AnrV2IntegrationTest { val hint = HintUtils.getSentrySdkHint(invocation.getArgument(1)) as DiskFlushNotification thread { - Thread.sleep(500L) + Thread.sleep(200L) hint.markFlushed() } SentryId() @@ -458,12 +460,12 @@ class AnrV2IntegrationTest { val integration = fixture.getSut( tmpDir, lastReportedAnrTimestamp = oldTimestamp, - flushTimeoutMillis = 1000L + sessionFlushTimeoutMillis = 500L ) fixture.addAppExitInfo(timestamp = newTimestamp) thread { - Thread.sleep(500L) + Thread.sleep(200L) val sessionHint = HintUtils.createWithTypeCheckHint(SessionStartHint()) fixture.options.envelopeDiskCache.store( SentryEnvelope(SentryId.EMPTY_ID, null, emptyList()), @@ -487,7 +489,7 @@ class AnrV2IntegrationTest { val integration = fixture.getSut( tmpDir, lastReportedAnrTimestamp = oldTimestamp, - flushTimeoutMillis = 500L, + sessionFlushTimeoutMillis = 500L, sessionTrackingEnabled = false ) fixture.addAppExitInfo(timestamp = newTimestamp) @@ -507,7 +509,7 @@ class AnrV2IntegrationTest { val integration = fixture.getSut( tmpDir, lastReportedAnrTimestamp = oldTimestamp, - flushTimeoutMillis = 500L + sessionFlushTimeoutMillis = 500L ) fixture.addAppExitInfo(timestamp = newTimestamp) diff --git a/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java index 0b5f8ac2fb..f4fe0f8095 100644 --- a/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java +++ b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java @@ -50,6 +50,7 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; @Open @ApiStatus.Internal @@ -67,7 +68,7 @@ public class EnvelopeCache extends CacheStrategy implements IEnvelopeCache { public static final String STARTUP_CRASH_MARKER_FILE = "startup_crash"; - private static final long SESSION_FLUSH_DISK_TIMEOUT_MS = 15000; + private static long SESSION_FLUSH_DISK_TIMEOUT_MS = 15000; private final CountDownLatch previousSessionLatch; @@ -444,4 +445,9 @@ public boolean waitPreviousSessionFlush() { public void flushPreviousSession() { previousSessionLatch.countDown(); } + + @TestOnly + public void overrideSessionFlushTimeout(final long sessionFlushTimeoutMs) { + SESSION_FLUSH_DISK_TIMEOUT_MS = sessionFlushTimeoutMs; + } } diff --git a/sentry/src/test/java/io/sentry/PreviousSessionFinalizerTest.kt b/sentry/src/test/java/io/sentry/PreviousSessionFinalizerTest.kt index 8e27662b5b..02d0970e7c 100644 --- a/sentry/src/test/java/io/sentry/PreviousSessionFinalizerTest.kt +++ b/sentry/src/test/java/io/sentry/PreviousSessionFinalizerTest.kt @@ -44,6 +44,8 @@ class PreviousSessionFinalizerTest { if (!shouldAwait) { (envelopeDiskCache as? EnvelopeCache)?.flushPreviousSession() } + (envelopeDiskCache as? EnvelopeCache) + ?.overrideSessionFlushTimeout(flushTimeoutMillis) } options.cacheDirPath?.let { sessionFile = EnvelopeCache.getPreviousSessionFile(it) From 62c27af14d0f61a5a49e63822d2772031316d77a Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 29 Dec 2023 12:41:59 +0100 Subject: [PATCH 18/31] Api dump --- sentry/api/sentry.api | 1 + 1 file changed, 1 insertion(+) diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index ae27abdbe7..7b32aa05c0 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -2871,6 +2871,7 @@ public class io/sentry/cache/EnvelopeCache : io/sentry/cache/IEnvelopeCache { public static fun getCurrentSessionFile (Ljava/lang/String;)Ljava/io/File; public static fun getPreviousSessionFile (Ljava/lang/String;)Ljava/io/File; public fun iterator ()Ljava/util/Iterator; + public fun overrideSessionFlushTimeout (J)V public fun store (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)V public fun waitPreviousSessionFlush ()Z } From 5cd1d47927e80db69462e97d1b72aa8b30053d3f Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 29 Dec 2023 17:55:04 +0100 Subject: [PATCH 19/31] Remove unnecessary robolectric test --- .../sentry/android/core/ActivityBreadcrumbsIntegrationTest.kt | 3 --- 1 file changed, 3 deletions(-) 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 index f104acebfa..10dc60e74b 100644 --- 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 @@ -3,11 +3,9 @@ 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 @@ -18,7 +16,6 @@ import org.mockito.kotlin.whenever import kotlin.test.Test import kotlin.test.assertEquals -@RunWith(AndroidJUnit4::class) class ActivityBreadcrumbsIntegrationTest { private class Fixture { From 39ecec949e8edbf7a27f2dc8c74edeee35bfe6f8 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 29 Dec 2023 17:59:34 +0100 Subject: [PATCH 20/31] Reduce number of benchmarks to speed up builds --- .../io/sentry/uitest/android/benchmark/SentryBenchmarkTest.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sentry-android-integration-tests/sentry-uitest-android-benchmark/src/androidTest/java/io/sentry/uitest/android/benchmark/SentryBenchmarkTest.kt b/sentry-android-integration-tests/sentry-uitest-android-benchmark/src/androidTest/java/io/sentry/uitest/android/benchmark/SentryBenchmarkTest.kt index 6dbcb457cc..110f9214b5 100644 --- a/sentry-android-integration-tests/sentry-uitest-android-benchmark/src/androidTest/java/io/sentry/uitest/android/benchmark/SentryBenchmarkTest.kt +++ b/sentry-android-integration-tests/sentry-uitest-android-benchmark/src/androidTest/java/io/sentry/uitest/android/benchmark/SentryBenchmarkTest.kt @@ -41,7 +41,9 @@ class SentryBenchmarkTest : BaseBenchmarkTest() { val op1 = BenchmarkOperation(choreographer, op = getOperation(runner)) val op2 = BenchmarkOperation(choreographer, op = getOperation(runner)) val refreshRate = BenchmarkActivity.refreshRate ?: 60F - val comparisonResults = BenchmarkOperation.compare(op1, "Op1", op2, "Op2", refreshRate) + // since we benchmark the same operation, warmupIterations = 1 would effectively mean + // 2 warmup runs which should be enough + val comparisonResults = BenchmarkOperation.compare(op1, "Op1", op2, "Op2", refreshRate, warmupIterations = 1, measuredIterations = 10) val comparisonResult = comparisonResults.getSummaryResult() comparisonResult.printResults() From d2933c5c9404a68155efb31ceabfe45cbe591be4 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 29 Dec 2023 20:14:53 +0100 Subject: [PATCH 21/31] Add logs to flaky test --- sentry/src/test/java/io/sentry/SentryTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sentry/src/test/java/io/sentry/SentryTest.kt b/sentry/src/test/java/io/sentry/SentryTest.kt index e284cbb4f1..2100a591a1 100644 --- a/sentry/src/test/java/io/sentry/SentryTest.kt +++ b/sentry/src/test/java/io/sentry/SentryTest.kt @@ -743,6 +743,8 @@ class SentryTest { Sentry.init { it.dsn = dsn + it.isDebug = true + it.setLogger(SystemOutLogger()) it.release = "io.sentry.sample@2.0" it.cacheDirPath = tmpDir.newFolder().absolutePath From acc5319aa5167969c891b3aa855c13f4a92aee6e Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 29 Dec 2023 21:02:58 +0100 Subject: [PATCH 22/31] Ensure no shared state in tests --- .../sentry/android/core/AnrV2IntegrationTest.kt | 3 +-- sentry/api/sentry.api | 3 ++- .../src/main/java/io/sentry/SentryOptions.java | 17 +++++++++++++++++ .../java/io/sentry/cache/EnvelopeCache.java | 13 ++----------- .../io/sentry/PreviousSessionFinalizerTest.kt | 3 +-- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AnrV2IntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AnrV2IntegrationTest.kt index 77267d7154..885ad22c8f 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AnrV2IntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AnrV2IntegrationTest.kt @@ -82,13 +82,12 @@ class AnrV2IntegrationTest { if (useImmediateExecutorService) ImmediateExecutorService() else mock() this.isAnrEnabled = isAnrEnabled this.flushTimeoutMillis = flushTimeoutMillis + this.sessionFlushTimeoutMillis = sessionFlushTimeoutMillis this.isEnableAutoSessionTracking = sessionTrackingEnabled this.isReportHistoricalAnrs = reportHistoricalAnrs this.isAttachAnrThreadDump = attachAnrThreadDump addInAppInclude("io.sentry.samples") setEnvelopeDiskCache(EnvelopeCache.create(this)) - (envelopeDiskCache as? EnvelopeCache) - ?.overrideSessionFlushTimeout(sessionFlushTimeoutMillis) } options.cacheDirPath?.let { cacheDir -> lastReportedAnrFile = File(cacheDir, AndroidEnvelopeCache.LAST_ANR_REPORT) diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 7b32aa05c0..5caf13e88b 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -2148,6 +2148,7 @@ public class io/sentry/SentryOptions { public fun getSentryClientName ()Ljava/lang/String; public fun getSerializer ()Lio/sentry/ISerializer; public fun getServerName ()Ljava/lang/String; + public fun getSessionFlushTimeoutMillis ()J public fun getSessionTrackingIntervalMillis ()J public fun getShutdownTimeout ()J public fun getShutdownTimeoutMillis ()J @@ -2252,6 +2253,7 @@ public class io/sentry/SentryOptions { public fun setSentryClientName (Ljava/lang/String;)V public fun setSerializer (Lio/sentry/ISerializer;)V public fun setServerName (Ljava/lang/String;)V + public fun setSessionFlushTimeoutMillis (J)V public fun setSessionTrackingIntervalMillis (J)V public fun setShutdownTimeout (J)V public fun setShutdownTimeoutMillis (J)V @@ -2871,7 +2873,6 @@ public class io/sentry/cache/EnvelopeCache : io/sentry/cache/IEnvelopeCache { public static fun getCurrentSessionFile (Ljava/lang/String;)Ljava/io/File; public static fun getPreviousSessionFile (Ljava/lang/String;)Ljava/io/File; public fun iterator ()Ljava/util/Iterator; - public fun overrideSessionFlushTimeout (J)V public fun store (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)V public fun waitPreviousSessionFlush ()Z } diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 9a6a962dc9..c6d3643ee9 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -99,6 +99,13 @@ public class SentryOptions { */ private long flushTimeoutMillis = 15000; // 15s + /** + * Controls how many seconds to wait before flushing previous session. Sentry SDKs finalizes + * unfinished sessions from a background queue and this queue is given a certain amount to drain + * sessions. Default is 15000 = 15s + */ + private long sessionFlushTimeoutMillis = 15000; // 15s + /** * Turns debug mode on or off. If debug is enabled SDK will attempt to print out useful debugging * information if something goes wrong. Default is disabled. @@ -2216,6 +2223,16 @@ public boolean isEnableBackpressureHandling() { return enableBackpressureHandling; } + @ApiStatus.Internal + public long getSessionFlushTimeoutMillis() { + return sessionFlushTimeoutMillis; + } + + @ApiStatus.Internal + public void setSessionFlushTimeoutMillis(final long sessionFlushTimeoutMillis) { + this.sessionFlushTimeoutMillis = sessionFlushTimeoutMillis; + } + /** The BeforeSend callback */ public interface BeforeSendCallback { diff --git a/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java index f4fe0f8095..5232d6077a 100644 --- a/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java +++ b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java @@ -50,7 +50,6 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.TestOnly; @Open @ApiStatus.Internal @@ -68,8 +67,6 @@ public class EnvelopeCache extends CacheStrategy implements IEnvelopeCache { public static final String STARTUP_CRASH_MARKER_FILE = "startup_crash"; - private static long SESSION_FLUSH_DISK_TIMEOUT_MS = 15000; - private final CountDownLatch previousSessionLatch; private final @NotNull Map fileNameMap = new WeakHashMap<>(); @@ -432,9 +429,8 @@ public void discard(final @NotNull SentryEnvelope envelope) { /** Awaits until the previous session (if any) is flushed to its own file. */ public boolean waitPreviousSessionFlush() { try { - // use fixed timeout instead of configurable options.getFlushTimeoutMillis() to ensure there's - // enough time to flush the session to disk - return previousSessionLatch.await(SESSION_FLUSH_DISK_TIMEOUT_MS, TimeUnit.MILLISECONDS); + return previousSessionLatch.await( + options.getSessionFlushTimeoutMillis(), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); options.getLogger().log(DEBUG, "Timed out waiting for previous session to flush."); @@ -445,9 +441,4 @@ public boolean waitPreviousSessionFlush() { public void flushPreviousSession() { previousSessionLatch.countDown(); } - - @TestOnly - public void overrideSessionFlushTimeout(final long sessionFlushTimeoutMs) { - SESSION_FLUSH_DISK_TIMEOUT_MS = sessionFlushTimeoutMs; - } } diff --git a/sentry/src/test/java/io/sentry/PreviousSessionFinalizerTest.kt b/sentry/src/test/java/io/sentry/PreviousSessionFinalizerTest.kt index 02d0970e7c..239e90905e 100644 --- a/sentry/src/test/java/io/sentry/PreviousSessionFinalizerTest.kt +++ b/sentry/src/test/java/io/sentry/PreviousSessionFinalizerTest.kt @@ -39,13 +39,12 @@ class PreviousSessionFinalizerTest { isDebug = true cacheDirPath = dir?.newFolder()?.absolutePath this.flushTimeoutMillis = flushTimeoutMillis + this.sessionFlushTimeoutMillis = flushTimeoutMillis isEnableAutoSessionTracking = sessionTrackingEnabled setEnvelopeDiskCache(EnvelopeCache.create(this)) if (!shouldAwait) { (envelopeDiskCache as? EnvelopeCache)?.flushPreviousSession() } - (envelopeDiskCache as? EnvelopeCache) - ?.overrideSessionFlushTimeout(flushTimeoutMillis) } options.cacheDirPath?.let { sessionFile = EnvelopeCache.getPreviousSessionFile(it) From ff1e6a32dfd5f903b4feb24d4105f583139c5da9 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Sat, 30 Dec 2023 00:02:37 +0100 Subject: [PATCH 23/31] Do not submit to another queue in PersistingOptionsObserver --- .../cache/PersistingOptionsObserver.java | 87 ++++++------------- 1 file changed, 26 insertions(+), 61 deletions(-) diff --git a/sentry/src/main/java/io/sentry/cache/PersistingOptionsObserver.java b/sentry/src/main/java/io/sentry/cache/PersistingOptionsObserver.java index 296b602534..bb1bb71572 100644 --- a/sentry/src/main/java/io/sentry/cache/PersistingOptionsObserver.java +++ b/sentry/src/main/java/io/sentry/cache/PersistingOptionsObserver.java @@ -1,7 +1,5 @@ package io.sentry.cache; -import static io.sentry.SentryLevel.ERROR; - import io.sentry.IOptionsObserver; import io.sentry.JsonDeserializer; import io.sentry.SentryOptions; @@ -25,87 +23,54 @@ public PersistingOptionsObserver(final @NotNull SentryOptions options) { this.options = options; } - @SuppressWarnings("FutureReturnValueIgnored") - private void serializeToDisk(final @NotNull Runnable task) { - try { - options - .getExecutorService() - .submit( - () -> { - try { - task.run(); - } catch (Throwable e) { - options.getLogger().log(ERROR, "Serialization task failed", e); - } - }); - } catch (Throwable e) { - options.getLogger().log(ERROR, "Serialization task could not be scheduled", e); - } - } - @Override public void setRelease(@Nullable String release) { - serializeToDisk( - () -> { - if (release == null) { - delete(RELEASE_FILENAME); - } else { - store(release, RELEASE_FILENAME); - } - }); + if (release == null) { + delete(RELEASE_FILENAME); + } else { + store(release, RELEASE_FILENAME); + } } @Override public void setProguardUuid(@Nullable String proguardUuid) { - serializeToDisk( - () -> { - if (proguardUuid == null) { - delete(PROGUARD_UUID_FILENAME); - } else { - store(proguardUuid, PROGUARD_UUID_FILENAME); - } - }); + if (proguardUuid == null) { + delete(PROGUARD_UUID_FILENAME); + } else { + store(proguardUuid, PROGUARD_UUID_FILENAME); + } } @Override public void setSdkVersion(@Nullable SdkVersion sdkVersion) { - serializeToDisk( - () -> { - if (sdkVersion == null) { - delete(SDK_VERSION_FILENAME); - } else { - store(sdkVersion, SDK_VERSION_FILENAME); - } - }); + if (sdkVersion == null) { + delete(SDK_VERSION_FILENAME); + } else { + store(sdkVersion, SDK_VERSION_FILENAME); + } } @Override public void setDist(@Nullable String dist) { - serializeToDisk( - () -> { - if (dist == null) { - delete(DIST_FILENAME); - } else { - store(dist, DIST_FILENAME); - } - }); + if (dist == null) { + delete(DIST_FILENAME); + } else { + store(dist, DIST_FILENAME); + } } @Override public void setEnvironment(@Nullable String environment) { - serializeToDisk( - () -> { - if (environment == null) { - delete(ENVIRONMENT_FILENAME); - } else { - store(environment, ENVIRONMENT_FILENAME); - } - }); + if (environment == null) { + delete(ENVIRONMENT_FILENAME); + } else { + store(environment, ENVIRONMENT_FILENAME); + } } @Override public void setTags(@NotNull Map tags) { - serializeToDisk(() -> store(tags, TAGS_FILENAME)); + store(tags, TAGS_FILENAME); } private void store(final @NotNull T entity, final @NotNull String fileName) { From 78a44b18ddc8bc4b9de1763fd74dd11f96040fcb Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Sat, 30 Dec 2023 00:55:14 +0100 Subject: [PATCH 24/31] Set timeouts for spring-boot tests to avoid long-runnings --- .../boot/jakarta/SentrySpanRestTemplateCustomizerTest.kt | 6 +++++- .../spring/boot/SentrySpanRestTemplateCustomizerTest.kt | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestTemplateCustomizerTest.kt b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestTemplateCustomizerTest.kt index 2c69175fa5..db5b25de44 100644 --- a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestTemplateCustomizerTest.kt +++ b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestTemplateCustomizerTest.kt @@ -28,6 +28,7 @@ import org.springframework.http.HttpHeaders import org.springframework.http.HttpMethod import org.springframework.http.HttpStatus import org.springframework.web.client.RestTemplate +import java.time.Duration import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -37,7 +38,10 @@ class SentrySpanRestTemplateCustomizerTest { class Fixture { val sentryOptions = SentryOptions() val hub = mock() - val restTemplate = RestTemplateBuilder().build() + val restTemplate = RestTemplateBuilder() + .setConnectTimeout(Duration.ofSeconds(2)) + .setReadTimeout(Duration.ofSeconds(2)) + .build() var mockServer = MockWebServer() val transaction: SentryTracer internal val customizer = SentrySpanRestTemplateCustomizer(hub) diff --git a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt index 21c989fb7d..0d675b6841 100644 --- a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt +++ b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt @@ -28,6 +28,7 @@ import org.springframework.http.HttpHeaders import org.springframework.http.HttpMethod import org.springframework.http.HttpStatus import org.springframework.web.client.RestTemplate +import java.time.Duration import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -37,7 +38,10 @@ class SentrySpanRestTemplateCustomizerTest { class Fixture { val sentryOptions = SentryOptions() val hub = mock() - val restTemplate = RestTemplateBuilder().build() + val restTemplate = RestTemplateBuilder() + .setConnectTimeout(Duration.ofSeconds(2)) + .setReadTimeout(Duration.ofSeconds(2)) + .build() var mockServer = MockWebServer() val transaction: SentryTracer internal val customizer = SentrySpanRestTemplateCustomizer(hub) From 65887b40d6a3c74a6bccfe154bcc72ee4fd4a76a Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Sat, 30 Dec 2023 20:41:41 +0100 Subject: [PATCH 25/31] Decouple robolectric and unit tests for sentry-android-core --- build.gradle.kts | 30 ++++---- sentry-android-core/build.gradle.kts | 70 +++++++++++++++++-- .../io/sentry/uitest/android/EnvelopeTests.kt | 9 +++ 3 files changed, 90 insertions(+), 19 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index dd566028f4..1d03b24cdd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -83,20 +83,22 @@ allprojects { version = properties[Config.Sentry.versionNameProp].toString() description = Config.Sentry.description tasks { - withType { - testLogging.showStandardStreams = true - testLogging.exceptionFormat = TestExceptionFormat.FULL - testLogging.events = setOf( - TestLogEvent.SKIPPED, - TestLogEvent.PASSED, - TestLogEvent.FAILED - ) - maxParallelForks = Runtime.getRuntime().availableProcessors() / 2 - - // Cap JVM args per test - minHeapSize = "128m" - maxHeapSize = "1g" - dependsOn("cleanTest") + if (this@allprojects.name != "sentry-android-core") { + withType { + testLogging.showStandardStreams = true + testLogging.exceptionFormat = TestExceptionFormat.FULL + testLogging.events = setOf( + TestLogEvent.SKIPPED, + TestLogEvent.PASSED, + TestLogEvent.FAILED + ) + maxParallelForks = Runtime.getRuntime().availableProcessors() / 2 + + // Cap JVM args per test + minHeapSize = "128m" + maxHeapSize = "1g" + dependsOn("cleanTest") + } } withType { options.compilerArgs.addAll(arrayOf("-Xlint:all", "-Werror", "-Xlint:-classfile", "-Xlint:-processing")) diff --git a/sentry-android-core/build.gradle.kts b/sentry-android-core/build.gradle.kts index 4ab0aec423..c2d09d8a61 100644 --- a/sentry-android-core/build.gradle.kts +++ b/sentry-android-core/build.gradle.kts @@ -1,4 +1,7 @@ import net.ltgt.gradle.errorprone.errorprone +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent +import org.gradle.configurationcache.extensions.capitalized import org.jetbrains.kotlin.config.KotlinCompilerVersion plugins { @@ -20,7 +23,11 @@ android { testInstrumentationRunner = Config.TestLibs.androidJUnitRunner - buildConfigField("String", "SENTRY_ANDROID_SDK_NAME", "\"${Config.Sentry.SENTRY_ANDROID_SDK_NAME}\"") + buildConfigField( + "String", + "SENTRY_ANDROID_SDK_NAME", + "\"${Config.Sentry.SENTRY_ANDROID_SDK_NAME}\"" + ) // for AGP 4.1 buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") @@ -65,10 +72,63 @@ android { } } -tasks.withType().configureEach { - options.errorprone { - check("NullAway", net.ltgt.gradle.errorprone.CheckSeverity.ERROR) - option("NullAway:AnnotatedPackages", "io.sentry") +tasks { + withType().configureEach { + options.errorprone { + check("NullAway", net.ltgt.gradle.errorprone.CheckSeverity.ERROR) + option("NullAway:AnnotatedPackages", "io.sentry") + } + } + + withType().configureEach { + testLogging.showStandardStreams = true + testLogging.exceptionFormat = TestExceptionFormat.FULL + testLogging.events = setOf( + TestLogEvent.SKIPPED, + TestLogEvent.PASSED, + TestLogEvent.FAILED + ) + maxParallelForks = Runtime.getRuntime().availableProcessors() / 2 + + // Cap JVM args per test + minHeapSize = "128m" + maxHeapSize = "1g" + if (!this.name.contains("robolectric", ignoreCase = true)) { + filter { + exclude { element -> + if (element.isDirectory || !element.file.exists()) { + return@exclude false + } + return@exclude element.file + .readText() + .contains("Landroidx/test/ext/junit/runners/AndroidJUnit4;") + } + } + } + dependsOn("cleanTest") + } +} + +afterEvaluate { + setOf("debug", "release").forEach { variant -> + task("${variant}RobolectricTest") { + group = "verification" + description = "Runs the Robolectric tests" + + val testTask = tasks.findByName("test${variant.capitalized()}UnitTest") as Test + classpath = testTask.classpath + testClassesDirs = testTask.testClassesDirs + filter { + include { element -> + if (element.isDirectory || !element.file.exists()) { + return@include true + } + return@include element.file + .readText() + .contains("Landroidx/test/ext/junit/runners/AndroidJUnit4;") + } + } + } } } diff --git a/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt b/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt index fddd0680d1..08f79ee086 100644 --- a/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt +++ b/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt @@ -9,15 +9,18 @@ import androidx.test.espresso.IdlingRegistry import androidx.test.espresso.action.ViewActions import androidx.test.espresso.matcher.ViewMatchers import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.sentry.NoOpLogger import io.sentry.ProfilingTraceData import io.sentry.Sentry import io.sentry.SentryEvent import io.sentry.android.core.AndroidLogger +import io.sentry.android.core.BuildInfoProvider import io.sentry.android.core.SentryAndroidOptions import io.sentry.assertEnvelopeProfile import io.sentry.assertEnvelopeTransaction import io.sentry.profilemeasurements.ProfileMeasurement import io.sentry.protocol.SentryTransaction +import org.junit.Assume.assumeFalse import org.junit.Assume.assumeNotNull import org.junit.runner.RunWith import java.util.concurrent.TimeUnit @@ -176,6 +179,12 @@ class EnvelopeTests : BaseUiTest() { @Test fun checkTimedOutProfile() { + assumeFalse( + "Sometimes traceFile does not exist for profiles on emulators and it fails." + + " Although, Android Runtime is the one that manages the file, so something" + + " must be wrong with Debug.startMethodTracing", + BuildInfoProvider(NoOpLogger.getInstance()).isEmulator ?: true + ) // We increase the IdlingResources timeout to exceed the profiling timeout IdlingPolicies.setIdlingResourceTimeout(1, TimeUnit.MINUTES) initSentry(true) { options: SentryAndroidOptions -> From 881e0efc79ee7ad5b054a1e9458c667d79c26551 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Sat, 30 Dec 2023 20:52:17 +0100 Subject: [PATCH 26/31] Revert "Decouple robolectric and unit tests for sentry-android-core" This reverts commit 65887b40d6a3c74a6bccfe154bcc72ee4fd4a76a. --- build.gradle.kts | 30 ++++---- sentry-android-core/build.gradle.kts | 70 ++----------------- .../io/sentry/uitest/android/EnvelopeTests.kt | 9 --- 3 files changed, 19 insertions(+), 90 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1d03b24cdd..dd566028f4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -83,22 +83,20 @@ allprojects { version = properties[Config.Sentry.versionNameProp].toString() description = Config.Sentry.description tasks { - if (this@allprojects.name != "sentry-android-core") { - withType { - testLogging.showStandardStreams = true - testLogging.exceptionFormat = TestExceptionFormat.FULL - testLogging.events = setOf( - TestLogEvent.SKIPPED, - TestLogEvent.PASSED, - TestLogEvent.FAILED - ) - maxParallelForks = Runtime.getRuntime().availableProcessors() / 2 - - // Cap JVM args per test - minHeapSize = "128m" - maxHeapSize = "1g" - dependsOn("cleanTest") - } + withType { + testLogging.showStandardStreams = true + testLogging.exceptionFormat = TestExceptionFormat.FULL + testLogging.events = setOf( + TestLogEvent.SKIPPED, + TestLogEvent.PASSED, + TestLogEvent.FAILED + ) + maxParallelForks = Runtime.getRuntime().availableProcessors() / 2 + + // Cap JVM args per test + minHeapSize = "128m" + maxHeapSize = "1g" + dependsOn("cleanTest") } withType { options.compilerArgs.addAll(arrayOf("-Xlint:all", "-Werror", "-Xlint:-classfile", "-Xlint:-processing")) diff --git a/sentry-android-core/build.gradle.kts b/sentry-android-core/build.gradle.kts index c2d09d8a61..4ab0aec423 100644 --- a/sentry-android-core/build.gradle.kts +++ b/sentry-android-core/build.gradle.kts @@ -1,7 +1,4 @@ import net.ltgt.gradle.errorprone.errorprone -import org.gradle.api.tasks.testing.logging.TestExceptionFormat -import org.gradle.api.tasks.testing.logging.TestLogEvent -import org.gradle.configurationcache.extensions.capitalized import org.jetbrains.kotlin.config.KotlinCompilerVersion plugins { @@ -23,11 +20,7 @@ android { testInstrumentationRunner = Config.TestLibs.androidJUnitRunner - buildConfigField( - "String", - "SENTRY_ANDROID_SDK_NAME", - "\"${Config.Sentry.SENTRY_ANDROID_SDK_NAME}\"" - ) + buildConfigField("String", "SENTRY_ANDROID_SDK_NAME", "\"${Config.Sentry.SENTRY_ANDROID_SDK_NAME}\"") // for AGP 4.1 buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") @@ -72,63 +65,10 @@ android { } } -tasks { - withType().configureEach { - options.errorprone { - check("NullAway", net.ltgt.gradle.errorprone.CheckSeverity.ERROR) - option("NullAway:AnnotatedPackages", "io.sentry") - } - } - - withType().configureEach { - testLogging.showStandardStreams = true - testLogging.exceptionFormat = TestExceptionFormat.FULL - testLogging.events = setOf( - TestLogEvent.SKIPPED, - TestLogEvent.PASSED, - TestLogEvent.FAILED - ) - maxParallelForks = Runtime.getRuntime().availableProcessors() / 2 - - // Cap JVM args per test - minHeapSize = "128m" - maxHeapSize = "1g" - if (!this.name.contains("robolectric", ignoreCase = true)) { - filter { - exclude { element -> - if (element.isDirectory || !element.file.exists()) { - return@exclude false - } - return@exclude element.file - .readText() - .contains("Landroidx/test/ext/junit/runners/AndroidJUnit4;") - } - } - } - dependsOn("cleanTest") - } -} - -afterEvaluate { - setOf("debug", "release").forEach { variant -> - task("${variant}RobolectricTest") { - group = "verification" - description = "Runs the Robolectric tests" - - val testTask = tasks.findByName("test${variant.capitalized()}UnitTest") as Test - classpath = testTask.classpath - testClassesDirs = testTask.testClassesDirs - filter { - include { element -> - if (element.isDirectory || !element.file.exists()) { - return@include true - } - return@include element.file - .readText() - .contains("Landroidx/test/ext/junit/runners/AndroidJUnit4;") - } - } - } +tasks.withType().configureEach { + options.errorprone { + check("NullAway", net.ltgt.gradle.errorprone.CheckSeverity.ERROR) + option("NullAway:AnnotatedPackages", "io.sentry") } } diff --git a/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt b/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt index 08f79ee086..fddd0680d1 100644 --- a/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt +++ b/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt @@ -9,18 +9,15 @@ import androidx.test.espresso.IdlingRegistry import androidx.test.espresso.action.ViewActions import androidx.test.espresso.matcher.ViewMatchers import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.sentry.NoOpLogger import io.sentry.ProfilingTraceData import io.sentry.Sentry import io.sentry.SentryEvent import io.sentry.android.core.AndroidLogger -import io.sentry.android.core.BuildInfoProvider import io.sentry.android.core.SentryAndroidOptions import io.sentry.assertEnvelopeProfile import io.sentry.assertEnvelopeTransaction import io.sentry.profilemeasurements.ProfileMeasurement import io.sentry.protocol.SentryTransaction -import org.junit.Assume.assumeFalse import org.junit.Assume.assumeNotNull import org.junit.runner.RunWith import java.util.concurrent.TimeUnit @@ -179,12 +176,6 @@ class EnvelopeTests : BaseUiTest() { @Test fun checkTimedOutProfile() { - assumeFalse( - "Sometimes traceFile does not exist for profiles on emulators and it fails." + - " Although, Android Runtime is the one that manages the file, so something" + - " must be wrong with Debug.startMethodTracing", - BuildInfoProvider(NoOpLogger.getInstance()).isEmulator ?: true - ) // We increase the IdlingResources timeout to exceed the profiling timeout IdlingPolicies.setIdlingResourceTimeout(1, TimeUnit.MINUTES) initSentry(true) { options: SentryAndroidOptions -> From 4313dca31bed59cd7f276fe2a2a901da8bb50a9b Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Sat, 30 Dec 2023 20:55:23 +0100 Subject: [PATCH 27/31] Revert --- .../java/io/sentry/uitest/android/EnvelopeTests.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt b/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt index fddd0680d1..924c4cedcb 100644 --- a/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt +++ b/sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt @@ -9,15 +9,18 @@ import androidx.test.espresso.IdlingRegistry import androidx.test.espresso.action.ViewActions import androidx.test.espresso.matcher.ViewMatchers import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.sentry.NoOpLogger import io.sentry.ProfilingTraceData import io.sentry.Sentry import io.sentry.SentryEvent import io.sentry.android.core.AndroidLogger +import io.sentry.android.core.BuildInfoProvider import io.sentry.android.core.SentryAndroidOptions import io.sentry.assertEnvelopeProfile import io.sentry.assertEnvelopeTransaction import io.sentry.profilemeasurements.ProfileMeasurement import io.sentry.protocol.SentryTransaction +import org.junit.Assume import org.junit.Assume.assumeNotNull import org.junit.runner.RunWith import java.util.concurrent.TimeUnit @@ -176,6 +179,12 @@ class EnvelopeTests : BaseUiTest() { @Test fun checkTimedOutProfile() { + Assume.assumeFalse( + "Sometimes traceFile does not exist for profiles on emulators and it fails." + + " Although, Android Runtime is the one that manages the file, so something" + + " must be wrong with Debug.startMethodTracing", + BuildInfoProvider(NoOpLogger.getInstance()).isEmulator ?: true + ) // We increase the IdlingResources timeout to exceed the profiling timeout IdlingPolicies.setIdlingResourceTimeout(1, TimeUnit.MINUTES) initSentry(true) { options: SentryAndroidOptions -> From 959b9e354dcb51aa13a5bfd39a171b5c6a9919f3 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 2 Jan 2024 17:16:48 +0100 Subject: [PATCH 28/31] Delete SdkBenchmarkTest as it replicates what app-metrics action does --- .../android/benchmark/SdkBenchmarkTest.kt | 62 ------------------- 1 file changed, 62 deletions(-) delete mode 100644 sentry-android-integration-tests/sentry-uitest-android-benchmark/src/androidTest/java/io/sentry/uitest/android/benchmark/SdkBenchmarkTest.kt diff --git a/sentry-android-integration-tests/sentry-uitest-android-benchmark/src/androidTest/java/io/sentry/uitest/android/benchmark/SdkBenchmarkTest.kt b/sentry-android-integration-tests/sentry-uitest-android-benchmark/src/androidTest/java/io/sentry/uitest/android/benchmark/SdkBenchmarkTest.kt deleted file mode 100644 index 75789bec51..0000000000 --- a/sentry-android-integration-tests/sentry-uitest-android-benchmark/src/androidTest/java/io/sentry/uitest/android/benchmark/SdkBenchmarkTest.kt +++ /dev/null @@ -1,62 +0,0 @@ -package io.sentry.uitest.android.benchmark - -import android.os.Bundle -import androidx.lifecycle.Lifecycle -import androidx.test.core.app.launchActivity -import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.sentry.Sentry -import io.sentry.android.core.SentryAndroid -import io.sentry.uitest.android.benchmark.util.BenchmarkOperation -import org.junit.runner.RunWith -import java.util.concurrent.TimeUnit -import kotlin.test.Test -import kotlin.test.assertTrue - -@RunWith(AndroidJUnit4::class) -class SdkBenchmarkTest : BaseBenchmarkTest() { - - @Test - fun benchmarkSdkInit() { - // We compare starting an activity with and without the sdk init, to measure its impact on startup time. - val opNoSdk = getOperation() - val opSimpleSdk = getOperation { - SentryAndroid.init(context) { - it.dsn = "https://key@host/proj" - } - } - val opNoSdk2 = getOperation() - val opPerfProfilingSdk = getOperation { - SentryAndroid.init(context) { - it.dsn = "https://key@host/proj" - it.profilesSampleRate = 1.0 - it.tracesSampleRate = 1.0 - } - } - val refreshRate = BenchmarkActivity.refreshRate ?: 60F - val simpleSdkResults = BenchmarkOperation.compare(opNoSdk, "No Sdk", opSimpleSdk, "Simple Sdk", refreshRate) - val simpleSdkResult = simpleSdkResults.getSummaryResult() - simpleSdkResult.printResults() - val perfProfilingSdkResults = BenchmarkOperation.compare(opNoSdk2, "No Sdk", opPerfProfilingSdk, "Sdk with perf and profiling", refreshRate) - val perfProfilingSdkResult = perfProfilingSdkResults.getSummaryResult() - perfProfilingSdkResult.printResults() - - assertTrue(simpleSdkResult.cpuTimeIncreaseNanos in 0..TimeUnit.MILLISECONDS.toNanos(100), "Expected ${simpleSdkResult.cpuTimeIncreaseNanos} to be in range 0 < x < 100000000") - assertTrue(perfProfilingSdkResult.cpuTimeIncreaseNanos in 0..TimeUnit.MILLISECONDS.toNanos(100), "Expected ${perfProfilingSdkResult.cpuTimeIncreaseNanos} to be in range 0 < x < 100000000") - } - - private fun getOperation(init: (() -> Unit)? = null) = BenchmarkOperation( - choreographer, - op = { - runner.runOnMainSync { - init?.invoke() - } - val benchmarkScenario = launchActivity( - activityOptions = Bundle().apply { putBoolean(BenchmarkActivity.EXTRA_SUSTAINED_PERFORMANCE_MODE, false) } - ) - benchmarkScenario.moveToState(Lifecycle.State.DESTROYED) - }, - after = { - Sentry.close() - } - ) -} From cbf6a2b4a7d45491ad2443cfa01df382e9c13a94 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 8 Jan 2024 12:10:49 +0100 Subject: [PATCH 29/31] Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9773f3a15d..b315afda6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - If you are setting global job listeners please also add `SentryJobListener` - Ensure serialVersionUID of Exception classes are unique ([#3115](https://github.com/getsentry/sentry-java/pull/3115)) - Get rid of "is not eligible for getting processed by all BeanPostProcessors" warnings in Spring Boot ([#3108](https://github.com/getsentry/sentry-java/pull/3108)) +- Fix missing `release` and other fields for ANRs reported with `mechanism:AppExitInfo` ([#3074](https://github.com/getsentry/sentry-java/pull/3074)) ### Dependencies From a0a31ca8192691b2f985186e08b11f7f96d35fa0 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 8 Jan 2024 12:24:01 +0100 Subject: [PATCH 30/31] Add --no-build-cache for distribution artifacts --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9a23391aa5..2117e6da21 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ javadocs: # do a dry release (like a local deploy) dryRelease: - ./gradlew aggregateJavadocs distZip + ./gradlew aggregateJavadocs distZip --no-build-cache # check for dependencies update update: From 594399779116df636953d207dc82f7fe816e6f66 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 8 Jan 2024 14:24:17 +0100 Subject: [PATCH 31/31] Add largeHeap to the test app --- .../sentry-uitest-android/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/sentry-android-integration-tests/sentry-uitest-android/src/main/AndroidManifest.xml b/sentry-android-integration-tests/sentry-uitest-android/src/main/AndroidManifest.xml index 5576160bb0..6bcad62e6d 100644 --- a/sentry-android-integration-tests/sentry-uitest-android/src/main/AndroidManifest.xml +++ b/sentry-android-integration-tests/sentry-uitest-android/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@