-
-
Notifications
You must be signed in to change notification settings - Fork 343
feat(experimental): Initialize Android SDK from json configuration #4451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
krystofwoldrich
merged 50 commits into
capture-app-start-errors
from
antonis/init-from-json
Feb 4, 2025
Merged
Changes from 48 commits
Commits
Show all changes
50 commits
Select commit
Hold shift + click to select a range
bf7c762
Extract Android SDK Init
antonis 897d918
Update tests
antonis e06e6bb
Adds changelog
antonis 903fc55
Fix lint issues
antonis 739ad30
Rename RNSentryStart instance for clarity
antonis 0f06266
WIP: Init with hardcoded json string
antonis 42c32ec
Adds changelog
antonis a98bd88
Expose only a Java Map parameter in the startWithOptions
antonis 1da8ca3
Fix lint issue
antonis be6b815
Convert RNSentrySDK to utility class
antonis 2163884
Initialise from assets json file
antonis 8454727
Copy configuration json in the android assets folder before building
antonis 1c31e21
Adds map converter tests
antonis ff20ed9
Disable by default in the sample
antonis 6509ada
Cleanup sentry.options.json from assets after the build
antonis dcb7e2e
Converts RNSentryStart to utility class
antonis 99410e9
Merge branch 'main' into antonis/extract-android-sdk-init
antonis 06b1def
Merge branch 'antonis/extract-android-sdk-init' into antonis/init-fro…
antonis f96e2d1
Align with merged convertion of RNSentryStart to utility class
antonis 7788b81
Align with Sentry Android naming
antonis 25d142a
Override json configuration with passed Android configuration
antonis cedd24a
Fix comment
antonis 3d41a98
Merge branch 'main' into antonis/extract-android-sdk-init
antonis 0de5bfa
Merge branch 'antonis/extract-android-sdk-init' into antonis/init-fro…
antonis d909ed4
Update changelog
antonis c26ca00
Merge branch 'capture-app-start-errors' into antonis/init-from-json
antonis dfb12d0
Fix changelog
antonis 108c625
Merge branch 'capture-app-start-errors' into antonis/init-from-json
antonis 710f1a0
Use RNSentryJsonConverter.convertToWritable
antonis 7469dc8
Move getOptionsFromConfigurationFile in a utility class
antonis e266ae1
Handle initialisation errors
antonis 7522fce
Remove beforeSend initialisation option
antonis 5ebe8fb
Lower access level were possible
antonis b6a36a1
Allow combining more than two configurations
antonis 8e87539
Add default and final configuration
antonis e0264ef
Add a flag to disable reading from the file
antonis 927a003
Adds RNSentrySDK tests
antonis 007a9d9
Fix lint issue
antonis 32bc0a7
Update changelog
antonis 8fc973f
Updates javadoc
antonis 58e6e9c
Merge branch 'capture-app-start-errors' into antonis/init-from-json
krystofwoldrich 821fef9
Ignore JavascriptException by default
antonis 43b26db
Move SDK name and version to react defaults
antonis d2fd58f
Set current activity in defaults
antonis 5b9665a
Defaults override file/rn configuration
antonis 2b7a319
Add tests for defaults and finals
antonis d236c82
Allow passing sdk init function
antonis ced915d
Add tests verifying defaults, finals and overriding behavior
antonis 1c96a27
Revert "Allow passing sdk init function"
antonis 8a87565
Use Sentry.getCurrentHub().options to check the initialised options
antonis File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
packages/core/RNSentryAndroidTester/app/src/androidTest/assets/invalid.options.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"dsn": "invalid-dsn" | ||
} |
1 change: 1 addition & 0 deletions
1
packages/core/RNSentryAndroidTester/app/src/androidTest/assets/invalid.options.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
invalid-options |
5 changes: 5 additions & 0 deletions
5
packages/core/RNSentryAndroidTester/app/src/androidTest/assets/sentry.options.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"dsn": "https://[email protected]/123456", | ||
"enableTracing": true, | ||
"tracesSampleRate": 1.0 | ||
} |
208 changes: 208 additions & 0 deletions
208
...es/core/RNSentryAndroidTester/app/src/androidTest/java/io/sentry/react/RNSentrySDKTest.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
package io.sentry.react | ||
|
||
import android.content.Context | ||
import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
import androidx.test.platform.app.InstrumentationRegistry | ||
import com.facebook.react.common.JavascriptException | ||
import io.sentry.Hint | ||
import io.sentry.ILogger | ||
import io.sentry.Sentry | ||
import io.sentry.Sentry.OptionsConfiguration | ||
import io.sentry.SentryEvent | ||
import io.sentry.android.core.AndroidLogger | ||
import io.sentry.android.core.SentryAndroidOptions | ||
import io.sentry.protocol.SdkVersion | ||
import org.junit.After | ||
import org.junit.Assert.assertEquals | ||
import org.junit.Assert.assertFalse | ||
import org.junit.Assert.assertNotNull | ||
import org.junit.Assert.assertNull | ||
import org.junit.Assert.assertTrue | ||
import org.junit.Before | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
|
||
@RunWith(AndroidJUnit4::class) | ||
class RNSentrySDKTest { | ||
private val logger: ILogger = AndroidLogger(RNSentrySDKTest::class.java.simpleName) | ||
private lateinit var context: Context | ||
|
||
companion object { | ||
private const val INITIALISATION_ERROR = "Failed to initialize Sentry's React Native SDK" | ||
private const val VALID_OPTIONS = "sentry.options.json" | ||
private const val INVALID_OPTIONS = "invalid.options.json" | ||
private const val INVALID_JSON = "invalid.options.txt" | ||
private const val MISSING = "non-existing-file" | ||
|
||
private val validConfig = | ||
OptionsConfiguration<SentryAndroidOptions> { options -> | ||
options.dsn = "https://[email protected]/123456" | ||
} | ||
private val invalidConfig = | ||
OptionsConfiguration<SentryAndroidOptions> { options -> | ||
options.dsn = "invalid-dsn" | ||
} | ||
private val emptyConfig = OptionsConfiguration<SentryAndroidOptions> {} | ||
} | ||
|
||
@Before | ||
fun setUp() { | ||
context = InstrumentationRegistry.getInstrumentation().context | ||
} | ||
|
||
@After | ||
fun tearDown() { | ||
Sentry.close() | ||
} | ||
|
||
@Test | ||
fun initialisesSuccessfullyWithDefaultValidJsonFile() { // sentry.options.json | ||
RNSentrySDK.init(context) | ||
assertTrue(Sentry.isEnabled()) | ||
} | ||
|
||
@Test | ||
fun initialisesSuccessfullyWithValidConfigurationAndDefaultValidJsonFile() { | ||
RNSentrySDK.init(context, validConfig) | ||
assertTrue(Sentry.isEnabled()) | ||
} | ||
|
||
@Test | ||
fun initialisesSuccessfullyWithValidConfigurationAndInvalidJsonFile() { | ||
RNSentrySDK.init(context, validConfig, INVALID_OPTIONS, logger, null) | ||
assertTrue(Sentry.isEnabled()) | ||
} | ||
|
||
@Test | ||
fun initialisesSuccessfullyWithValidConfigurationAndMissingJsonFile() { | ||
RNSentrySDK.init(context, validConfig, MISSING, logger, null) | ||
assertTrue(Sentry.isEnabled()) | ||
} | ||
|
||
@Test | ||
fun initialisesSuccessfullyWithValidConfigurationAndErrorInParsingJsonFile() { | ||
RNSentrySDK.init(context, validConfig, INVALID_JSON, logger, null) | ||
assertTrue(Sentry.isEnabled()) | ||
} | ||
|
||
@Test | ||
fun initialisesSuccessfullyWithNoConfigurationAndValidJsonFile() { | ||
RNSentrySDK.init(context, emptyConfig, VALID_OPTIONS, logger, null) | ||
assertTrue(Sentry.isEnabled()) | ||
} | ||
|
||
@Test | ||
fun failsToInitialiseWithNoConfigurationAndInvalidJsonFile() { | ||
try { | ||
RNSentrySDK.init(context, emptyConfig, INVALID_OPTIONS, logger, null) | ||
} catch (e: Exception) { | ||
assertEquals(INITIALISATION_ERROR, e.message) | ||
} | ||
assertFalse(Sentry.isEnabled()) | ||
} | ||
|
||
@Test | ||
fun failsToInitialiseWithInvalidConfigAndInvalidJsonFile() { | ||
try { | ||
RNSentrySDK.init(context, invalidConfig, INVALID_OPTIONS, logger, null) | ||
} catch (e: Exception) { | ||
assertEquals(INITIALISATION_ERROR, e.message) | ||
} | ||
assertFalse(Sentry.isEnabled()) | ||
} | ||
|
||
@Test | ||
fun failsToInitialiseWithInvalidConfigAndValidJsonFile() { | ||
try { | ||
RNSentrySDK.init(context, invalidConfig, VALID_OPTIONS, logger, null) | ||
} catch (e: Exception) { | ||
assertEquals(INITIALISATION_ERROR, e.message) | ||
} | ||
assertFalse(Sentry.isEnabled()) | ||
} | ||
|
||
@Test | ||
fun failsToInitialiseWithInvalidConfigurationAndDefaultValidJsonFile() { | ||
try { | ||
RNSentrySDK.init(context, invalidConfig) | ||
} catch (e: Exception) { | ||
assertEquals(INITIALISATION_ERROR, e.message) | ||
} | ||
assertFalse(Sentry.isEnabled()) | ||
} | ||
|
||
@Test | ||
fun defaultsAndFinalsAreSetWithValidJsonFile() { | ||
RNSentrySDK.init(context, emptyConfig, VALID_OPTIONS, logger) { _, config -> | ||
val actualOptions = SentryAndroidOptions() | ||
config.configure(actualOptions) | ||
verifyDefaults(actualOptions) | ||
verifyFinals(actualOptions) | ||
// options file | ||
assert(actualOptions.dsn == "https://[email protected]/123456") | ||
} | ||
} | ||
|
||
@Test | ||
fun defaultsAndFinalsAreSetWithValidConfiguration() { | ||
RNSentrySDK.init(context, validConfig, MISSING, logger) { _, config -> | ||
val actualOptions = SentryAndroidOptions() | ||
config.configure(actualOptions) | ||
verifyDefaults(actualOptions) | ||
verifyFinals(actualOptions) | ||
// configuration | ||
assert(actualOptions.dsn == "https://[email protected]/123456") | ||
} | ||
} | ||
|
||
@Test | ||
fun defaultsOverrideOptionsJsonFile() { | ||
RNSentrySDK.init(context, emptyConfig, VALID_OPTIONS, logger) { _, config -> | ||
val actualOptions = SentryAndroidOptions() | ||
config.configure(actualOptions) | ||
assertNull(actualOptions.tracesSampleRate) | ||
assertEquals(false, actualOptions.enableTracing) | ||
} | ||
} | ||
|
||
@Test | ||
fun configurationOverridesDefaultOptions() { | ||
val validConfig = | ||
OptionsConfiguration<SentryAndroidOptions> { options -> | ||
options.dsn = "https://[email protected]/123456" | ||
options.tracesSampleRate = 0.5 | ||
options.enableTracing = true | ||
} | ||
RNSentrySDK.init(context, validConfig, MISSING, logger) { _, config -> | ||
val actualOptions = SentryAndroidOptions() | ||
config.configure(actualOptions) | ||
assertEquals(0.5, actualOptions.tracesSampleRate) | ||
assertEquals(true, actualOptions.enableTracing) | ||
assert(actualOptions.dsn == "https://[email protected]/123456") | ||
} | ||
} | ||
|
||
private fun verifyDefaults(actualOptions: SentryAndroidOptions) { | ||
assertTrue(actualOptions.ignoredExceptionsForType.contains(JavascriptException::class.java)) | ||
assertEquals(RNSentryVersion.ANDROID_SDK_NAME, actualOptions.sdkVersion?.name) | ||
assertEquals( | ||
io.sentry.android.core.BuildConfig.VERSION_NAME, | ||
actualOptions.sdkVersion?.version, | ||
) | ||
val pack = actualOptions.sdkVersion?.packages?.first { it.name == RNSentryVersion.REACT_NATIVE_SDK_PACKAGE_NAME } | ||
assertNotNull(pack) | ||
assertEquals(RNSentryVersion.REACT_NATIVE_SDK_PACKAGE_VERSION, pack?.version) | ||
assertNull(actualOptions.tracesSampleRate) | ||
assertNull(actualOptions.tracesSampler) | ||
assertEquals(false, actualOptions.enableTracing) | ||
} | ||
|
||
private fun verifyFinals(actualOptions: SentryAndroidOptions) { | ||
val event = | ||
SentryEvent().apply { sdk = SdkVersion(RNSentryVersion.ANDROID_SDK_NAME, "1.0") } | ||
val result = actualOptions.beforeSend?.execute(event, Hint()) | ||
assertNotNull(result) | ||
assertEquals("android", result?.getTag("event.origin")) | ||
assertEquals("java", result?.getTag("event.environment")) | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
...roidTester/app/src/test/java/io/sentry/react/RNSentryCompositeOptionsConfigurationTest.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package io.sentry.react | ||
|
||
import io.sentry.Sentry.OptionsConfiguration | ||
import io.sentry.android.core.SentryAndroidOptions | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
import org.junit.runners.JUnit4 | ||
import org.mockito.kotlin.mock | ||
import org.mockito.kotlin.verify | ||
|
||
@RunWith(JUnit4::class) | ||
class RNSentryCompositeOptionsConfigurationTest { | ||
@Test | ||
fun `configure should call base and overriding configurations`() { | ||
val baseConfig: OptionsConfiguration<SentryAndroidOptions> = mock() | ||
val overridingConfig: OptionsConfiguration<SentryAndroidOptions> = mock() | ||
|
||
val compositeConfig = RNSentryCompositeOptionsConfiguration(baseConfig, overridingConfig) | ||
val options = SentryAndroidOptions() | ||
compositeConfig.configure(options) | ||
|
||
verify(baseConfig).configure(options) | ||
verify(overridingConfig).configure(options) | ||
} | ||
|
||
@Test | ||
fun `configure should apply base configuration and override values`() { | ||
val baseConfig = | ||
OptionsConfiguration<SentryAndroidOptions> { options -> | ||
options.dsn = "https://[email protected]" | ||
options.isDebug = false | ||
options.release = "some-release" | ||
} | ||
val overridingConfig = | ||
OptionsConfiguration<SentryAndroidOptions> { options -> | ||
options.dsn = "https://[email protected]" | ||
options.isDebug = true | ||
options.environment = "production" | ||
} | ||
|
||
val compositeConfig = RNSentryCompositeOptionsConfiguration(baseConfig, overridingConfig) | ||
val options = SentryAndroidOptions() | ||
compositeConfig.configure(options) | ||
|
||
assert(options.dsn == "https://[email protected]") // overridden value | ||
assert(options.isDebug) // overridden value | ||
assert(options.release == "some-release") // base value not overridden | ||
assert(options.environment == "production") // overridden value not in base | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.