From 8c18c4702c7f321f9b920b34b9f57ebb6a9b852c Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Wed, 13 Nov 2024 06:16:47 +0100 Subject: [PATCH] merge --- .github/workflows/agp-matrix.yml | 3 +- .github/workflows/build.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .../workflows/enforce-license-compliance.yml | 2 +- .github/workflows/generate-javadocs.yml | 2 +- .../integration-tests-benchmarks.yml | 4 +- .../integration-tests-ui-critical.yml | 2 +- .github/workflows/integration-tests-ui.yml | 2 +- .github/workflows/release-build.yml | 2 +- .github/workflows/system-tests-backend.yml | 2 +- CHANGELOG.md | 16 ++- .../android/core/ManifestMetadataReader.java | 5 + .../core/ManifestMetadataReaderTest.kt | 25 ++++ .../src/main/AndroidManifest.xml | 3 + .../boot/SentryAutoConfigurationTest.kt | 20 +-- sentry/src/main/java/io/sentry/Baggage.java | 6 +- .../main/java/io/sentry/DisabledQueue.java | 115 ++++++++++++++++++ sentry/src/main/java/io/sentry/DsnUtil.java | 2 +- .../io/sentry/RequestDetailsResolver.java | 2 +- sentry/src/main/java/io/sentry/Scope.java | 4 +- sentry/src/main/java/io/sentry/Sentry.java | 2 +- .../main/java/io/sentry/SentryOptions.java | 8 +- .../test/java/io/sentry/DisabledQueueTest.kt | 93 ++++++++++++++ sentry/src/test/java/io/sentry/ScopeTest.kt | 11 ++ 24 files changed, 302 insertions(+), 33 deletions(-) create mode 100644 sentry/src/main/java/io/sentry/DisabledQueue.java create mode 100644 sentry/src/test/java/io/sentry/DisabledQueueTest.kt diff --git a/.github/workflows/agp-matrix.yml b/.github/workflows/agp-matrix.yml index 182c0fa19ba..b93bc364acb 100644 --- a/.github/workflows/agp-matrix.yml +++ b/.github/workflows/agp-matrix.yml @@ -38,7 +38,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@bb0c460cbf5354b0cddd15bacdf0d6aaa3e5a32b # pin@v3 + uses: gradle/actions/setup-gradle@707359876a764dbcdb9da0b0ed08291818310c3d # pin@v3 with: gradle-home-cache-cleanup: true @@ -69,6 +69,7 @@ jobs: target: 'aosp_atd' arch: x86 channel: canary # Necessary for ATDs + disk-size: 4096M script: ./gradlew sentry-android-integration-tests:sentry-uitest-android:connectedReleaseAndroidTest -DtestBuildType=release --daemon - name: Upload test results diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6b885942e9f..5988e278880 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@bb0c460cbf5354b0cddd15bacdf0d6aaa3e5a32b # pin@v3 + uses: gradle/actions/setup-gradle@707359876a764dbcdb9da0b0ed08291818310c3d # pin@v3 with: gradle-home-cache-cleanup: true diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 99abfbdca6c..771b5274a66 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -34,7 +34,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@bb0c460cbf5354b0cddd15bacdf0d6aaa3e5a32b # pin@v3 + uses: gradle/actions/setup-gradle@707359876a764dbcdb9da0b0ed08291818310c3d # pin@v3 with: gradle-home-cache-cleanup: true diff --git a/.github/workflows/enforce-license-compliance.yml b/.github/workflows/enforce-license-compliance.yml index 2b87c1d278d..c4a22a909b8 100644 --- a/.github/workflows/enforce-license-compliance.yml +++ b/.github/workflows/enforce-license-compliance.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Setup Gradle - uses: gradle/actions/setup-gradle@bb0c460cbf5354b0cddd15bacdf0d6aaa3e5a32b # pin@v3 + uses: gradle/actions/setup-gradle@707359876a764dbcdb9da0b0ed08291818310c3d # pin@v3 with: gradle-home-cache-cleanup: true diff --git a/.github/workflows/generate-javadocs.yml b/.github/workflows/generate-javadocs.yml index b540441fb77..5d358bdf501 100644 --- a/.github/workflows/generate-javadocs.yml +++ b/.github/workflows/generate-javadocs.yml @@ -20,7 +20,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@bb0c460cbf5354b0cddd15bacdf0d6aaa3e5a32b # pin@v3 + uses: gradle/actions/setup-gradle@707359876a764dbcdb9da0b0ed08291818310c3d # pin@v3 with: gradle-home-cache-cleanup: true diff --git a/.github/workflows/integration-tests-benchmarks.yml b/.github/workflows/integration-tests-benchmarks.yml index 58fc933752c..34eea1733c1 100644 --- a/.github/workflows/integration-tests-benchmarks.yml +++ b/.github/workflows/integration-tests-benchmarks.yml @@ -37,7 +37,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@bb0c460cbf5354b0cddd15bacdf0d6aaa3e5a32b # pin@v3 + uses: gradle/actions/setup-gradle@707359876a764dbcdb9da0b0ed08291818310c3d # pin@v3 with: gradle-home-cache-cleanup: true @@ -86,7 +86,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@bb0c460cbf5354b0cddd15bacdf0d6aaa3e5a32b # pin@v3 + uses: gradle/actions/setup-gradle@707359876a764dbcdb9da0b0ed08291818310c3d # pin@v3 with: gradle-home-cache-cleanup: true diff --git a/.github/workflows/integration-tests-ui-critical.yml b/.github/workflows/integration-tests-ui-critical.yml index 815adf9b61d..a28400e50f0 100644 --- a/.github/workflows/integration-tests-ui-critical.yml +++ b/.github/workflows/integration-tests-ui-critical.yml @@ -32,7 +32,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@bb0c460cbf5354b0cddd15bacdf0d6aaa3e5a32b # pin@v3 + uses: gradle/actions/setup-gradle@707359876a764dbcdb9da0b0ed08291818310c3d # pin@v3 with: gradle-home-cache-cleanup: true diff --git a/.github/workflows/integration-tests-ui.yml b/.github/workflows/integration-tests-ui.yml index 6c4ad6564fc..059e3c7424a 100644 --- a/.github/workflows/integration-tests-ui.yml +++ b/.github/workflows/integration-tests-ui.yml @@ -32,7 +32,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@bb0c460cbf5354b0cddd15bacdf0d6aaa3e5a32b # pin@v3 + uses: gradle/actions/setup-gradle@707359876a764dbcdb9da0b0ed08291818310c3d # pin@v3 with: gradle-home-cache-cleanup: true diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 83a3c82f8cb..c625efa8eb9 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -26,7 +26,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@bb0c460cbf5354b0cddd15bacdf0d6aaa3e5a32b # pin@v3 + uses: gradle/actions/setup-gradle@707359876a764dbcdb9da0b0ed08291818310c3d # pin@v3 with: gradle-home-cache-cleanup: true diff --git a/.github/workflows/system-tests-backend.yml b/.github/workflows/system-tests-backend.yml index 6b12df4f8f4..bffb70cf870 100644 --- a/.github/workflows/system-tests-backend.yml +++ b/.github/workflows/system-tests-backend.yml @@ -49,7 +49,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@bb0c460cbf5354b0cddd15bacdf0d6aaa3e5a32b # pin@v3 + uses: gradle/actions/setup-gradle@707359876a764dbcdb9da0b0ed08291818310c3d # pin@v3 with: gradle-home-cache-cleanup: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 43142ef1d68..ea0f7b10990 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,7 +40,6 @@ - Faster generation of Sentry and Span IDs ([#3818](https://github.com/getsentry/sentry-java/pull/3818)) - Uses faster implementation to convert UUID to SentryID String - Uses faster Random implementation to generate UUIDs -- Use a separate `Random` instance per thread to improve SDK performance ([#3835](https://github.com/getsentry/sentry-java/pull/3835)) - Android 15: Add support for 16KB page sizes ([#3851](https://github.com/getsentry/sentry-java/pull/3851)) - See https://developer.android.com/guide/practices/page-sizes for more details @@ -53,7 +52,6 @@ - Starting a child span from a transaction that wasn't in the current `Context` lead to multiple transactions being created (one for the transaction and another per span created). - Add `auto.graphql.graphql22` to ignored span origins when using OpenTelemetry ([#3828](https://github.com/getsentry/sentry-java/pull/3828)) - The Spring Boot 3 WebFlux sample now uses our GraphQL v22 integration ([#3828](https://github.com/getsentry/sentry-java/pull/3828)) -- Accept manifest integer values when requiring floating values ([#3823](https://github.com/getsentry/sentry-java/pull/3823)) - All status codes below 400 are now mapped to `SpanStatus.OK` ([#3869](https://github.com/getsentry/sentry-java/pull/3869)) @@ -311,6 +309,20 @@ You may also use `LifecycleHelper.close(token)`, e.g. in case you need to pass t - Report exceptions returned by Throwable.getSuppressed() to Sentry as exception groups ([#3396] https://github.com/getsentry/sentry-java/pull/3396) +## 7.17.0 + +### Features + +- Add meta option to set the maximum amount of breadcrumbs to be logged. ([#3836](https://github.com/getsentry/sentry-java/pull/3836)) +- Use a separate `Random` instance per thread to improve SDK performance ([#3835](https://github.com/getsentry/sentry-java/pull/3835)) + +### Fixes + +- Using MaxBreadcrumb with value 0 no longer crashes. ([#3836](https://github.com/getsentry/sentry-java/pull/3836)) +- Accept manifest integer values when requiring floating values ([#3823](https://github.com/getsentry/sentry-java/pull/3823)) +- Fix standalone tomcat jndi issue ([#3873](https://github.com/getsentry/sentry-java/pull/3873)) + - Using Sentry Spring Boot on a standalone tomcat caused the following error: + - Failed to bind properties under 'sentry.parsed-dsn' to io.sentry.Dsn ## 7.16.0 diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java b/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java index 993d05d08a3..45661866fa8 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java @@ -104,6 +104,8 @@ final class ManifestMetadataReader { static final String FORCE_INIT = "io.sentry.force-init"; + static final String MAX_BREADCRUMBS = "io.sentry.max-breadcrumbs"; + /** ManifestMetadataReader ctor */ private ManifestMetadataReader() {} @@ -204,6 +206,9 @@ static void applyMetadata( SESSION_TRACKING_TIMEOUT_INTERVAL_MILLIS, options.getSessionTrackingIntervalMillis())); + options.setMaxBreadcrumbs( + (int) readLong(metadata, logger, MAX_BREADCRUMBS, options.getMaxBreadcrumbs())); + options.setEnableActivityLifecycleBreadcrumbs( readBool( metadata, diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt index 761b6b3d69e..5d6e915c0bc 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt @@ -1402,4 +1402,29 @@ class ManifestMetadataReaderTest { assertEquals(expectedSampleRate.toDouble(), fixture.options.experimental.sessionReplay.sessionSampleRate) assertEquals(expectedSampleRate.toDouble(), fixture.options.experimental.sessionReplay.onErrorSampleRate) } + + @Test + fun `applyMetadata reads maxBreadcrumbs to options and sets the value if found`() { + // Arrange + val bundle = bundleOf(ManifestMetadataReader.MAX_BREADCRUMBS to 1) + val context = fixture.getContext(metaData = bundle) + + // Act + ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider) + + // Assert + assertEquals(1, fixture.options.maxBreadcrumbs) + } + + @Test + fun `applyMetadata reads maxBreadcrumbs to options and keeps default if not found`() { + // Arrange + val context = fixture.getContext() + + // Act + ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider) + + // Assert + assertEquals(100, fixture.options.maxBreadcrumbs) + } } diff --git a/sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml b/sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml index ac854110171..84372b7766d 100644 --- a/sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml +++ b/sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml @@ -148,6 +148,9 @@ + + + diff --git a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt index f6e4ea01221..2ec9c763fce 100644 --- a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt +++ b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt @@ -734,7 +734,7 @@ class SentryAutoConfigurationTest { SentryIntegrationPackageStorage.getInstance().clearStorage() contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=false") .run { - assertTrue(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBoot3OpenTelemetryAgentWithoutAutoInit")) + assertTrue(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBootOpenTelemetryAgentWithoutAutoInit")) } } @@ -743,7 +743,7 @@ class SentryAutoConfigurationTest { SentryIntegrationPackageStorage.getInstance().clearStorage() contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") .run { - assertFalse(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBoot3OpenTelemetryAgentWithoutAutoInit")) + assertFalse(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBootOpenTelemetryAgentWithoutAutoInit")) } } @@ -753,39 +753,39 @@ class SentryAutoConfigurationTest { contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=false") .withClassLoader(FilteredClassLoader(AgentMarker::class.java)) .run { - assertFalse(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBoot3OpenTelemetryAgentWithoutAutoInit")) + assertFalse(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBootOpenTelemetryAgentWithoutAutoInit")) } } @Test - fun `when AgentMarker is not on the classpath but OpenTelemetry is, runs SpringBoot3OpenTelemetryNoAgent`() { + fun `when AgentMarker is not on the classpath but OpenTelemetry is, runs SpringBootOpenTelemetryNoAgent`() { SentryIntegrationPackageStorage.getInstance().clearStorage() contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") .withClassLoader(FilteredClassLoader(AgentMarker::class.java)) .withUserConfiguration(OtelBeanConfig::class.java) .run { - assertTrue(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBoot3OpenTelemetryNoAgent")) + assertTrue(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBootOpenTelemetryNoAgent")) } } @Test - fun `when AgentMarker and OpenTelemetry are not on the classpath, does not run SpringBoot3OpenTelemetryNoAgent`() { + fun `when AgentMarker and OpenTelemetry are not on the classpath, does not run SpringBootOpenTelemetryNoAgent`() { SentryIntegrationPackageStorage.getInstance().clearStorage() contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") .withClassLoader(FilteredClassLoader(AgentMarker::class.java, OpenTelemetry::class.java)) .run { - assertFalse(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBoot3OpenTelemetryNoAgent")) + assertFalse(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBootOpenTelemetryNoAgent")) } } @Test - fun `when AgentMarker and SentryAutoConfigurationCustomizerProvider are not on the classpath, does not run SpringBoot3OpenTelemetryNoAgent`() { + fun `when AgentMarker and SentryAutoConfigurationCustomizerProvider are not on the classpath, does not run SpringBootOpenTelemetryNoAgent`() { SentryIntegrationPackageStorage.getInstance().clearStorage() contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") .withClassLoader(FilteredClassLoader(AgentMarker::class.java, SentryAutoConfigurationCustomizerProvider::class.java)) .withUserConfiguration(OtelBeanConfig::class.java) .run { - assertFalse(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBoot3OpenTelemetryNoAgent")) + assertFalse(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBootOpenTelemetryNoAgent")) } } @@ -795,7 +795,7 @@ class SentryAutoConfigurationTest { contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") .withClassLoader(FilteredClassLoader(AgentMarker::class.java)) .run { - assertFalse(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBoot3OpenTelemetryAgentWithoutAutoInit")) + assertFalse(SentryIntegrationPackageStorage.getInstance().integrations.contains("SpringBootOpenTelemetryAgentWithoutAutoInit")) } } diff --git a/sentry/src/main/java/io/sentry/Baggage.java b/sentry/src/main/java/io/sentry/Baggage.java index 954cda7a977..05a59d7053f 100644 --- a/sentry/src/main/java/io/sentry/Baggage.java +++ b/sentry/src/main/java/io/sentry/Baggage.java @@ -133,7 +133,7 @@ public static Baggage fromEvent( final Baggage baggage = new Baggage(options.getLogger()); final SpanContext trace = event.getContexts().getTrace(); baggage.setTraceId(trace != null ? trace.getTraceId().toString() : null); - baggage.setPublicKey(options.getParsedDsn().getPublicKey()); + baggage.setPublicKey(options.retrieveParsedDsn().getPublicKey()); baggage.setRelease(event.getRelease()); baggage.setEnvironment(event.getEnvironment()); baggage.setTransaction(event.getTransaction()); @@ -383,7 +383,7 @@ public void setValuesFromTransaction( final @Nullable String transactionName, final @Nullable TransactionNameSource transactionNameSource) { setTraceId(traceId.toString()); - setPublicKey(sentryOptions.getParsedDsn().getPublicKey()); + setPublicKey(sentryOptions.retrieveParsedDsn().getPublicKey()); setRelease(sentryOptions.getRelease()); setEnvironment(sentryOptions.getEnvironment()); setTransaction(isHighQualityTransactionName(transactionNameSource) ? transactionName : null); @@ -400,7 +400,7 @@ public void setValuesFromScope( final @NotNull PropagationContext propagationContext = scope.getPropagationContext(); final @NotNull SentryId replayId = scope.getReplayId(); setTraceId(propagationContext.getTraceId().toString()); - setPublicKey(options.getParsedDsn().getPublicKey()); + setPublicKey(options.retrieveParsedDsn().getPublicKey()); setRelease(options.getRelease()); setEnvironment(options.getEnvironment()); if (!SentryId.EMPTY_ID.equals(replayId)) { diff --git a/sentry/src/main/java/io/sentry/DisabledQueue.java b/sentry/src/main/java/io/sentry/DisabledQueue.java new file mode 100644 index 00000000000..afef111af4a --- /dev/null +++ b/sentry/src/main/java/io/sentry/DisabledQueue.java @@ -0,0 +1,115 @@ +package io.sentry; + +import java.io.Serializable; +import java.util.AbstractCollection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +final class DisabledQueue extends AbstractCollection implements Queue, Serializable { + + /** Serialization version. */ + private static final long serialVersionUID = -8423413834657610417L; + + /** Constructor that creates a queue that does not accept any element. */ + public DisabledQueue() {} + + // ----------------------------------------------------------------------- + /** + * Returns the number of elements stored in the queue. + * + * @return this queue's size + */ + @Override + public int size() { + return 0; + } + + /** + * Returns true if this queue is empty; false otherwise. + * + * @return false + */ + @Override + public boolean isEmpty() { + return false; + } + + /** Does nothing. */ + @Override + public void clear() {} + + /** + * Since the queue is disabled, the element will not be added. + * + * @param element the element to add + * @return false, always + */ + @Override + public boolean add(final @NotNull E element) { + return false; + } + + // ----------------------------------------------------------------------- + + /** + * Receives an element but do nothing with it. + * + * @param element the element to add + * @return false, always + */ + @Override + public boolean offer(@NotNull E element) { + return false; + } + + @Override + public @Nullable E poll() { + return null; + } + + @Override + public @Nullable E element() { + return null; + } + + @Override + public @Nullable E peek() { + return null; + } + + @Override + public @NotNull E remove() { + throw new NoSuchElementException("queue is disabled"); + } + + // ----------------------------------------------------------------------- + + /** + * Returns an iterator over this queue's elements. + * + * @return an iterator over this queue's elements + */ + @Override + public @NotNull Iterator iterator() { + return new Iterator() { + + @Override + public boolean hasNext() { + return false; + } + + @Override + public E next() { + throw new NoSuchElementException(); + } + + @Override + public void remove() { + throw new IllegalStateException(); + } + }; + } +} diff --git a/sentry/src/main/java/io/sentry/DsnUtil.java b/sentry/src/main/java/io/sentry/DsnUtil.java index 6cc0dc360bd..b6902ad2741 100644 --- a/sentry/src/main/java/io/sentry/DsnUtil.java +++ b/sentry/src/main/java/io/sentry/DsnUtil.java @@ -23,7 +23,7 @@ public static boolean urlContainsDsnHost(@Nullable SentryOptions options, @Nulla return false; } - final @NotNull Dsn dsn = options.getParsedDsn(); + final @NotNull Dsn dsn = options.retrieveParsedDsn(); final @NotNull URI sentryUri = dsn.getSentryUri(); final @Nullable String dsnHost = sentryUri.getHost(); diff --git a/sentry/src/main/java/io/sentry/RequestDetailsResolver.java b/sentry/src/main/java/io/sentry/RequestDetailsResolver.java index 6083c69e994..bba4dc19ac0 100644 --- a/sentry/src/main/java/io/sentry/RequestDetailsResolver.java +++ b/sentry/src/main/java/io/sentry/RequestDetailsResolver.java @@ -21,7 +21,7 @@ public RequestDetailsResolver(final @NotNull SentryOptions options) { @NotNull RequestDetails resolve() { - final Dsn dsn = options.getParsedDsn(); + final Dsn dsn = options.retrieveParsedDsn(); final URI sentryUri = dsn.getSentryUri(); final String envelopeUrl = sentryUri.resolve(sentryUri.getPath() + "/envelope/").toString(); diff --git a/sentry/src/main/java/io/sentry/Scope.java b/sentry/src/main/java/io/sentry/Scope.java index 74e6642546b..4dacc8e4dac 100644 --- a/sentry/src/main/java/io/sentry/Scope.java +++ b/sentry/src/main/java/io/sentry/Scope.java @@ -786,7 +786,9 @@ public void clearAttachments() { * @return the breadcrumbs queue */ static @NotNull Queue createBreadcrumbsList(final int maxBreadcrumb) { - return SynchronizedQueue.synchronizedQueue(new CircularFifoQueue<>(maxBreadcrumb)); + return maxBreadcrumb > 0 + ? SynchronizedQueue.synchronizedQueue(new CircularFifoQueue<>(maxBreadcrumb)) + : SynchronizedQueue.synchronizedQueue(new DisabledQueue<>()); } /** diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index 7a35720e2dc..e8317365ed9 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -475,7 +475,7 @@ private static boolean preInitConfigurations(final @NotNull SentryOptions option } // This creates the DSN object and performs some checks - options.getParsedDsn(); + options.retrieveParsedDsn(); return true; } diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 5110d6c2f0d..8e427251e69 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -553,13 +553,15 @@ public void addIntegration(@NotNull Integration integration) { } /** - * Evaluates and parses the DSN. May throw an exception if the DSN is invalid. + * Evaluates and parses the DSN. May throw an exception if the DSN is invalid. Renamed from + * `getParsedDsn` as this would cause an error when deploying as WAR to Tomcat due to `JNDI` + * property binding. * * @return the parsed DSN or throws if dsn is invalid */ @ApiStatus.Internal @NotNull - Dsn getParsedDsn() throws IllegalArgumentException { + Dsn retrieveParsedDsn() throws IllegalArgumentException { return parsedDsn.getValue(); } @@ -2438,7 +2440,7 @@ public void setGlobalHubMode(final @Nullable Boolean globalHubMode) { */ void loadLazyFields() { getSerializer(); - getParsedDsn(); + retrieveParsedDsn(); getEnvelopeReader(); getDateProvider(); } diff --git a/sentry/src/test/java/io/sentry/DisabledQueueTest.kt b/sentry/src/test/java/io/sentry/DisabledQueueTest.kt new file mode 100644 index 00000000000..351f87eaff7 --- /dev/null +++ b/sentry/src/test/java/io/sentry/DisabledQueueTest.kt @@ -0,0 +1,93 @@ +package io.sentry +import org.junit.Assert.assertThrows +import java.util.NoSuchElementException +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNull + +class DisabledQueueTest { + + @Test + fun `size starts empty`() { + val queue = DisabledQueue() + assertEquals(0, queue.size, "Size should always be zero.") + } + + @Test + fun `add does not add elements`() { + val queue = DisabledQueue() + assertFalse(queue.add(1), "add should always return false.") + assertEquals(0, queue.size, "Size should still be zero after attempting to add an element.") + } + + @Test + fun `isEmpty returns false when created`() { + val queue = DisabledQueue() + assertFalse(queue.isEmpty(), "isEmpty should always return false.") + } + + @Test + fun `isEmpty always returns false if add function was called`() { + val queue = DisabledQueue() + queue.add(1) + + assertFalse(queue.isEmpty(), "isEmpty should always return false.") + } + + @Test + fun `offer does not add elements`() { + val queue = DisabledQueue() + assertFalse(queue.offer(1), "offer should always return false.") + assertEquals(0, queue.size, "Size should still be zero after attempting to offer an element.") + } + + @Test + fun `poll returns null`() { + val queue = DisabledQueue() + queue.add(1) + assertNull(queue.poll(), "poll should always return null.") + } + + @Test + fun `peek returns null`() { + val queue = DisabledQueue() + queue.add(1) + + assertNull(queue.peek(), "peek should always return null.") + } + + @Test + fun `element returns null`() { + val queue = DisabledQueue() + assertNull(queue.element(), "element should always return null.") + } + + @Test + fun `remove throws NoSuchElementException`() { + val queue = DisabledQueue() + assertThrows(NoSuchElementException::class.java) { queue.remove() } + } + + @Test + fun `clear does nothing`() { + val queue = DisabledQueue() + queue.clear() // Should not throw an exception + assertEquals(0, queue.size, "Size should remain zero after clear.") + } + + @Test + fun `iterator has no elements`() { + val queue = DisabledQueue() + val iterator = queue.iterator() + assertFalse(iterator.hasNext(), "Iterator should have no elements.") + assertThrows(NoSuchElementException::class.java) { iterator.next() } + } + + @Test + fun `iterator remove throws IllegalStateException`() { + val queue = DisabledQueue() + val iterator = queue.iterator() + assertThrows(IllegalStateException::class.java) { iterator.remove() } + } +} diff --git a/sentry/src/test/java/io/sentry/ScopeTest.kt b/sentry/src/test/java/io/sentry/ScopeTest.kt index 71c6c6f380c..b8025735e8a 100644 --- a/sentry/src/test/java/io/sentry/ScopeTest.kt +++ b/sentry/src/test/java/io/sentry/ScopeTest.kt @@ -1029,6 +1029,17 @@ class ScopeTest { ) } + @Test + fun `creating a new scope won't crash if max breadcrumbs is set to zero`() { + val options = SentryOptions().apply { + maxBreadcrumbs = 0 + } + val scope = Scope(options) + + // expect no exception to be thrown + // previously was crashing, see https://github.com/getsentry/sentry-java/issues/3313 + } + private fun eventProcessor(): EventProcessor { return object : EventProcessor { override fun process(event: SentryEvent, hint: Hint): SentryEvent? {