Skip to content

Commit e57a9d7

Browse files
authored
Merge ced915d into 22a5f81
2 parents 22a5f81 + ced915d commit e57a9d7

File tree

13 files changed

+639
-73
lines changed

13 files changed

+639
-73
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
- Rename `navigation.processing` span to more expressive `Navigation dispatch to screen A mounted/navigation cancelled` ([#4423](https://github.com/getsentry/sentry-react-native/pull/4423))
2424
- Add RN SDK package to `sdk.packages` for Cocoa ([#4381](https://github.com/getsentry/sentry-react-native/pull/4381))
2525
- Add experimental version of `startWithConfigureOptions` for Apple platforms ([#4444](https://github.com/getsentry/sentry-react-native/pull/4444))
26+
- Add experimental version of `init` with optional `OptionsConfiguration<SentryAndroidOptions>` for Android ([#4451](https://github.com/getsentry/sentry-react-native/pull/4451))
2627
- Add initialization using `sentry.options.json` for Apple platforms ([#4447](https://github.com/getsentry/sentry-react-native/pull/4447))
28+
- Add initialization using `sentry.options.json` for Android ([#4451](https://github.com/getsentry/sentry-react-native/pull/4451))
2729

2830
### Internal
2931

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"dsn": "invalid-dsn"
3+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
invalid-options
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"dsn": "https://[email protected]/123456",
3+
"enableTracing": true,
4+
"tracesSampleRate": 1.0
5+
}
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
package io.sentry.react
2+
3+
import android.content.Context
4+
import androidx.test.ext.junit.runners.AndroidJUnit4
5+
import androidx.test.platform.app.InstrumentationRegistry
6+
import com.facebook.react.common.JavascriptException
7+
import io.sentry.Hint
8+
import io.sentry.ILogger
9+
import io.sentry.Sentry
10+
import io.sentry.Sentry.OptionsConfiguration
11+
import io.sentry.SentryEvent
12+
import io.sentry.android.core.AndroidLogger
13+
import io.sentry.android.core.SentryAndroidOptions
14+
import io.sentry.protocol.SdkVersion
15+
import org.junit.After
16+
import org.junit.Assert.assertEquals
17+
import org.junit.Assert.assertFalse
18+
import org.junit.Assert.assertNotNull
19+
import org.junit.Assert.assertNull
20+
import org.junit.Assert.assertTrue
21+
import org.junit.Before
22+
import org.junit.Test
23+
import org.junit.runner.RunWith
24+
25+
@RunWith(AndroidJUnit4::class)
26+
class RNSentrySDKTest {
27+
private val logger: ILogger = AndroidLogger(RNSentrySDKTest::class.java.simpleName)
28+
private lateinit var context: Context
29+
30+
companion object {
31+
private const val INITIALISATION_ERROR = "Failed to initialize Sentry's React Native SDK"
32+
private const val VALID_OPTIONS = "sentry.options.json"
33+
private const val INVALID_OPTIONS = "invalid.options.json"
34+
private const val INVALID_JSON = "invalid.options.txt"
35+
private const val MISSING = "non-existing-file"
36+
37+
private val validConfig =
38+
OptionsConfiguration<SentryAndroidOptions> { options ->
39+
options.dsn = "https://[email protected]/123456"
40+
}
41+
private val invalidConfig =
42+
OptionsConfiguration<SentryAndroidOptions> { options ->
43+
options.dsn = "invalid-dsn"
44+
}
45+
private val emptyConfig = OptionsConfiguration<SentryAndroidOptions> {}
46+
}
47+
48+
@Before
49+
fun setUp() {
50+
context = InstrumentationRegistry.getInstrumentation().context
51+
}
52+
53+
@After
54+
fun tearDown() {
55+
Sentry.close()
56+
}
57+
58+
@Test
59+
fun initialisesSuccessfullyWithDefaultValidJsonFile() { // sentry.options.json
60+
RNSentrySDK.init(context)
61+
assertTrue(Sentry.isEnabled())
62+
}
63+
64+
@Test
65+
fun initialisesSuccessfullyWithValidConfigurationAndDefaultValidJsonFile() {
66+
RNSentrySDK.init(context, validConfig)
67+
assertTrue(Sentry.isEnabled())
68+
}
69+
70+
@Test
71+
fun initialisesSuccessfullyWithValidConfigurationAndInvalidJsonFile() {
72+
RNSentrySDK.init(context, validConfig, INVALID_OPTIONS, logger, null)
73+
assertTrue(Sentry.isEnabled())
74+
}
75+
76+
@Test
77+
fun initialisesSuccessfullyWithValidConfigurationAndMissingJsonFile() {
78+
RNSentrySDK.init(context, validConfig, MISSING, logger, null)
79+
assertTrue(Sentry.isEnabled())
80+
}
81+
82+
@Test
83+
fun initialisesSuccessfullyWithValidConfigurationAndErrorInParsingJsonFile() {
84+
RNSentrySDK.init(context, validConfig, INVALID_JSON, logger, null)
85+
assertTrue(Sentry.isEnabled())
86+
}
87+
88+
@Test
89+
fun initialisesSuccessfullyWithNoConfigurationAndValidJsonFile() {
90+
RNSentrySDK.init(context, emptyConfig, VALID_OPTIONS, logger, null)
91+
assertTrue(Sentry.isEnabled())
92+
}
93+
94+
@Test
95+
fun failsToInitialiseWithNoConfigurationAndInvalidJsonFile() {
96+
try {
97+
RNSentrySDK.init(context, emptyConfig, INVALID_OPTIONS, logger, null)
98+
} catch (e: Exception) {
99+
assertEquals(INITIALISATION_ERROR, e.message)
100+
}
101+
assertFalse(Sentry.isEnabled())
102+
}
103+
104+
@Test
105+
fun failsToInitialiseWithInvalidConfigAndInvalidJsonFile() {
106+
try {
107+
RNSentrySDK.init(context, invalidConfig, INVALID_OPTIONS, logger, null)
108+
} catch (e: Exception) {
109+
assertEquals(INITIALISATION_ERROR, e.message)
110+
}
111+
assertFalse(Sentry.isEnabled())
112+
}
113+
114+
@Test
115+
fun failsToInitialiseWithInvalidConfigAndValidJsonFile() {
116+
try {
117+
RNSentrySDK.init(context, invalidConfig, VALID_OPTIONS, logger, null)
118+
} catch (e: Exception) {
119+
assertEquals(INITIALISATION_ERROR, e.message)
120+
}
121+
assertFalse(Sentry.isEnabled())
122+
}
123+
124+
@Test
125+
fun failsToInitialiseWithInvalidConfigurationAndDefaultValidJsonFile() {
126+
try {
127+
RNSentrySDK.init(context, invalidConfig)
128+
} catch (e: Exception) {
129+
assertEquals(INITIALISATION_ERROR, e.message)
130+
}
131+
assertFalse(Sentry.isEnabled())
132+
}
133+
134+
@Test
135+
fun defaultsAndFinalsAreSetWithValidJsonFile() {
136+
RNSentrySDK.init(context, emptyConfig, VALID_OPTIONS, logger) { _, config ->
137+
val actualOptions = SentryAndroidOptions()
138+
config.configure(actualOptions)
139+
verifyDefaults(actualOptions)
140+
verifyFinals(actualOptions)
141+
// options file
142+
assert(actualOptions.dsn == "https://[email protected]/123456")
143+
}
144+
}
145+
146+
@Test
147+
fun defaultsAndFinalsAreSetWithValidConfiguration() {
148+
RNSentrySDK.init(context, validConfig, MISSING, logger) { _, config ->
149+
val actualOptions = SentryAndroidOptions()
150+
config.configure(actualOptions)
151+
verifyDefaults(actualOptions)
152+
verifyFinals(actualOptions)
153+
// configuration
154+
assert(actualOptions.dsn == "https://[email protected]/123456")
155+
}
156+
}
157+
158+
@Test
159+
fun defaultsOverrideOptionsJsonFile() {
160+
RNSentrySDK.init(context, emptyConfig, VALID_OPTIONS, logger) { _, config ->
161+
val actualOptions = SentryAndroidOptions()
162+
config.configure(actualOptions)
163+
assertNull(actualOptions.tracesSampleRate)
164+
assertEquals(false, actualOptions.enableTracing)
165+
}
166+
}
167+
168+
@Test
169+
fun configurationOverridesDefaultOptions() {
170+
val validConfig =
171+
OptionsConfiguration<SentryAndroidOptions> { options ->
172+
options.dsn = "https://[email protected]/123456"
173+
options.tracesSampleRate = 0.5
174+
options.enableTracing = true
175+
}
176+
RNSentrySDK.init(context, validConfig, MISSING, logger) { _, config ->
177+
val actualOptions = SentryAndroidOptions()
178+
config.configure(actualOptions)
179+
assertEquals(0.5, actualOptions.tracesSampleRate)
180+
assertEquals(true, actualOptions.enableTracing)
181+
assert(actualOptions.dsn == "https://[email protected]/123456")
182+
}
183+
}
184+
185+
private fun verifyDefaults(actualOptions: SentryAndroidOptions) {
186+
assertTrue(actualOptions.ignoredExceptionsForType.contains(JavascriptException::class.java))
187+
assertEquals(RNSentryVersion.ANDROID_SDK_NAME, actualOptions.sdkVersion?.name)
188+
assertEquals(
189+
io.sentry.android.core.BuildConfig.VERSION_NAME,
190+
actualOptions.sdkVersion?.version,
191+
)
192+
val pack = actualOptions.sdkVersion?.packages?.first { it.name == RNSentryVersion.REACT_NATIVE_SDK_PACKAGE_NAME }
193+
assertNotNull(pack)
194+
assertEquals(RNSentryVersion.REACT_NATIVE_SDK_PACKAGE_VERSION, pack?.version)
195+
assertNull(actualOptions.tracesSampleRate)
196+
assertNull(actualOptions.tracesSampler)
197+
assertEquals(false, actualOptions.enableTracing)
198+
}
199+
200+
private fun verifyFinals(actualOptions: SentryAndroidOptions) {
201+
val event =
202+
SentryEvent().apply { sdk = SdkVersion(RNSentryVersion.ANDROID_SDK_NAME, "1.0") }
203+
val result = actualOptions.beforeSend?.execute(event, Hint())
204+
assertNotNull(result)
205+
assertEquals("android", result?.getTag("event.origin"))
206+
assertEquals("java", result?.getTag("event.environment"))
207+
}
208+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package io.sentry.react
2+
3+
import io.sentry.Sentry.OptionsConfiguration
4+
import io.sentry.android.core.SentryAndroidOptions
5+
import org.junit.Test
6+
import org.junit.runner.RunWith
7+
import org.junit.runners.JUnit4
8+
import org.mockito.kotlin.mock
9+
import org.mockito.kotlin.verify
10+
11+
@RunWith(JUnit4::class)
12+
class RNSentryCompositeOptionsConfigurationTest {
13+
@Test
14+
fun `configure should call base and overriding configurations`() {
15+
val baseConfig: OptionsConfiguration<SentryAndroidOptions> = mock()
16+
val overridingConfig: OptionsConfiguration<SentryAndroidOptions> = mock()
17+
18+
val compositeConfig = RNSentryCompositeOptionsConfiguration(baseConfig, overridingConfig)
19+
val options = SentryAndroidOptions()
20+
compositeConfig.configure(options)
21+
22+
verify(baseConfig).configure(options)
23+
verify(overridingConfig).configure(options)
24+
}
25+
26+
@Test
27+
fun `configure should apply base configuration and override values`() {
28+
val baseConfig =
29+
OptionsConfiguration<SentryAndroidOptions> { options ->
30+
options.dsn = "https://[email protected]"
31+
options.isDebug = false
32+
options.release = "some-release"
33+
}
34+
val overridingConfig =
35+
OptionsConfiguration<SentryAndroidOptions> { options ->
36+
options.dsn = "https://[email protected]"
37+
options.isDebug = true
38+
options.environment = "production"
39+
}
40+
41+
val compositeConfig = RNSentryCompositeOptionsConfiguration(baseConfig, overridingConfig)
42+
val options = SentryAndroidOptions()
43+
compositeConfig.configure(options)
44+
45+
assert(options.dsn == "https://[email protected]") // overridden value
46+
assert(options.isDebug) // overridden value
47+
assert(options.release == "some-release") // base value not overridden
48+
assert(options.environment == "production") // overridden value not in base
49+
}
50+
}

0 commit comments

Comments
 (0)