Skip to content

Commit dd8554c

Browse files
authored
Merge 2b7a319 into 22a5f81
2 parents 22a5f81 + 2b7a319 commit dd8554c

File tree

13 files changed

+539
-73
lines changed

13 files changed

+539
-73
lines changed

CHANGELOG.md

+2
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

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"dsn": "invalid-dsn"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
invalid-options
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"dsn": "https://[email protected]/123456"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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 io.sentry.ILogger
7+
import io.sentry.Sentry
8+
import io.sentry.Sentry.OptionsConfiguration
9+
import io.sentry.android.core.AndroidLogger
10+
import io.sentry.android.core.SentryAndroidOptions
11+
import org.junit.After
12+
import org.junit.Assert.assertEquals
13+
import org.junit.Assert.assertFalse
14+
import org.junit.Assert.assertTrue
15+
import org.junit.Before
16+
import org.junit.Test
17+
import org.junit.runner.RunWith
18+
19+
@RunWith(AndroidJUnit4::class)
20+
class RNSentrySDKTest {
21+
private val logger: ILogger = AndroidLogger(RNSentrySDKTest::class.java.simpleName)
22+
private lateinit var context: Context
23+
24+
companion object {
25+
private const val INITIALISATION_ERROR = "Failed to initialize Sentry's React Native SDK"
26+
private const val VALID_OPTIONS = "sentry.options.json"
27+
private const val INVALID_OPTIONS = "invalid.options.json"
28+
private const val INVALID_JSON = "invalid.options.txt"
29+
private const val MISSING = "non-existing-file"
30+
31+
private val validConfig =
32+
OptionsConfiguration<SentryAndroidOptions> { options ->
33+
options.dsn = "https://[email protected]/123456"
34+
}
35+
private val invalidConfig =
36+
OptionsConfiguration<SentryAndroidOptions> { options ->
37+
options.dsn = "invalid-dsn"
38+
}
39+
private val emptyConfig = OptionsConfiguration<SentryAndroidOptions> {}
40+
}
41+
42+
@Before
43+
fun setUp() {
44+
context = InstrumentationRegistry.getInstrumentation().context
45+
}
46+
47+
@After
48+
fun tearDown() {
49+
Sentry.close()
50+
}
51+
52+
@Test
53+
fun initialisesSuccessfullyWithDefaultValidJsonFile() { // sentry.options.json
54+
RNSentrySDK.init(context)
55+
assertTrue(Sentry.isEnabled())
56+
}
57+
58+
@Test
59+
fun initialisesSuccessfullyWithValidConfigurationAndDefaultValidJsonFile() {
60+
RNSentrySDK.init(context, validConfig)
61+
assertTrue(Sentry.isEnabled())
62+
}
63+
64+
@Test
65+
fun initialisesSuccessfullyWithValidConfigurationAndInvalidJsonFile() {
66+
RNSentrySDK.init(context, validConfig, INVALID_OPTIONS, logger)
67+
assertTrue(Sentry.isEnabled())
68+
}
69+
70+
@Test
71+
fun initialisesSuccessfullyWithValidConfigurationAndMissingJsonFile() {
72+
RNSentrySDK.init(context, validConfig, MISSING, logger)
73+
assertTrue(Sentry.isEnabled())
74+
}
75+
76+
@Test
77+
fun initialisesSuccessfullyWithValidConfigurationAndErrorInParsingJsonFile() {
78+
RNSentrySDK.init(context, validConfig, INVALID_JSON, logger)
79+
assertTrue(Sentry.isEnabled())
80+
}
81+
82+
@Test
83+
fun initialisesSuccessfullyWithNoConfigurationAndValidJsonFile() {
84+
RNSentrySDK.init(context, emptyConfig, VALID_OPTIONS, logger)
85+
assertTrue(Sentry.isEnabled())
86+
}
87+
88+
@Test
89+
fun failsToInitialiseWithNoConfigurationAndInvalidJsonFile() {
90+
try {
91+
RNSentrySDK.init(context, emptyConfig, INVALID_OPTIONS, logger)
92+
} catch (e: Exception) {
93+
assertEquals(INITIALISATION_ERROR, e.message)
94+
}
95+
assertFalse(Sentry.isEnabled())
96+
}
97+
98+
@Test
99+
fun failsToInitialiseWithInvalidConfigAndInvalidJsonFile() {
100+
try {
101+
RNSentrySDK.init(context, invalidConfig, INVALID_OPTIONS, logger)
102+
} catch (e: Exception) {
103+
assertEquals(INITIALISATION_ERROR, e.message)
104+
}
105+
assertFalse(Sentry.isEnabled())
106+
}
107+
108+
@Test
109+
fun failsToInitialiseWithInvalidConfigAndValidJsonFile() {
110+
try {
111+
RNSentrySDK.init(context, invalidConfig, VALID_OPTIONS, logger)
112+
} catch (e: Exception) {
113+
assertEquals(INITIALISATION_ERROR, e.message)
114+
}
115+
assertFalse(Sentry.isEnabled())
116+
}
117+
118+
@Test
119+
fun failsToInitialiseWithInvalidConfigurationAndDefaultValidJsonFile() {
120+
try {
121+
RNSentrySDK.init(context, invalidConfig)
122+
} catch (e: Exception) {
123+
assertEquals(INITIALISATION_ERROR, e.message)
124+
}
125+
assertFalse(Sentry.isEnabled())
126+
}
127+
}
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+
}

packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/react/RNSentryStartTest.kt

+76-16
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@ import com.facebook.react.bridge.JavaOnlyMap
55
import com.facebook.react.common.JavascriptException
66
import io.sentry.Breadcrumb
77
import io.sentry.ILogger
8+
import io.sentry.SentryEvent
9+
import io.sentry.android.core.CurrentActivityHolder
810
import io.sentry.android.core.SentryAndroidOptions
11+
import io.sentry.protocol.SdkVersion
912
import org.junit.Assert.assertEquals
1013
import org.junit.Assert.assertFalse
14+
import org.junit.Assert.assertNotNull
1115
import org.junit.Assert.assertNull
1216
import org.junit.Assert.assertTrue
1317
import org.junit.Before
@@ -40,7 +44,7 @@ class RNSentryStartTest {
4044
"http://localhost:8969/teststream",
4145
)
4246
val actualOptions = SentryAndroidOptions()
43-
RNSentryStart.getSentryAndroidOptions(actualOptions, options, activity, logger)
47+
RNSentryStart.getSentryAndroidOptions(actualOptions, options, logger)
4448
assert(actualOptions.isEnableSpotlight)
4549
assertEquals("http://localhost:8969/teststream", actualOptions.spotlightConnectionUrl)
4650
}
@@ -49,7 +53,7 @@ class RNSentryStartTest {
4953
fun `when the spotlight url is passed, the spotlight is enabled for the given url`() {
5054
val options = JavaOnlyMap.of("spotlight", "http://localhost:8969/teststream")
5155
val actualOptions = SentryAndroidOptions()
52-
RNSentryStart.getSentryAndroidOptions(actualOptions, options, activity, logger)
56+
RNSentryStart.getSentryAndroidOptions(actualOptions, options, logger)
5357
assert(actualOptions.isEnableSpotlight)
5458
assertEquals("http://localhost:8969/teststream", actualOptions.spotlightConnectionUrl)
5559
}
@@ -58,17 +62,10 @@ class RNSentryStartTest {
5862
fun `when the spotlight option is disabled, the spotlight SentryAndroidOption is set to false`() {
5963
val options = JavaOnlyMap.of("spotlight", false)
6064
val actualOptions = SentryAndroidOptions()
61-
RNSentryStart.getSentryAndroidOptions(actualOptions, options, activity, logger)
65+
RNSentryStart.getSentryAndroidOptions(actualOptions, options, logger)
6266
assertFalse(actualOptions.isEnableSpotlight)
6367
}
6468

65-
@Test
66-
fun `the JavascriptException is added to the ignoredExceptionsForType list on initialisation`() {
67-
val actualOptions = SentryAndroidOptions()
68-
RNSentryStart.getSentryAndroidOptions(actualOptions, JavaOnlyMap.of(), activity, logger)
69-
assertTrue(actualOptions.ignoredExceptionsForType.contains(JavascriptException::class.java))
70-
}
71-
7269
@Test
7370
fun `beforeBreadcrumb callback filters out Sentry DSN requests breadcrumbs`() {
7471
val options = SentryAndroidOptions()
@@ -79,7 +76,7 @@ class RNSentryStartTest {
7976
"devServerUrl",
8077
"http://localhost:8081",
8178
)
82-
RNSentryStart.getSentryAndroidOptions(options, rnOptions, activity, logger)
79+
RNSentryStart.getSentryAndroidOptions(options, rnOptions, logger)
8380

8481
val breadcrumb =
8582
Breadcrumb().apply {
@@ -103,7 +100,7 @@ class RNSentryStartTest {
103100
"devServerUrl",
104101
mockDevServerUrl,
105102
)
106-
RNSentryStart.getSentryAndroidOptions(options, rnOptions, activity, logger)
103+
RNSentryStart.getSentryAndroidOptions(options, rnOptions, logger)
107104

108105
val breadcrumb =
109106
Breadcrumb().apply {
@@ -126,7 +123,7 @@ class RNSentryStartTest {
126123
"devServerUrl",
127124
"http://localhost:8081",
128125
)
129-
RNSentryStart.getSentryAndroidOptions(options, rnOptions, activity, logger)
126+
RNSentryStart.getSentryAndroidOptions(options, rnOptions, logger)
130127

131128
val breadcrumb =
132129
Breadcrumb().apply {
@@ -142,7 +139,7 @@ class RNSentryStartTest {
142139
@Test
143140
fun `the breadcrumb is not filtered out when the dev server url and dsn are not passed`() {
144141
val options = SentryAndroidOptions()
145-
RNSentryStart.getSentryAndroidOptions(options, JavaOnlyMap(), activity, logger)
142+
RNSentryStart.getSentryAndroidOptions(options, JavaOnlyMap(), logger)
146143

147144
val breadcrumb =
148145
Breadcrumb().apply {
@@ -159,7 +156,7 @@ class RNSentryStartTest {
159156
fun `the breadcrumb is not filtered out when the dev server url is not passed and the dsn does not match`() {
160157
val options = SentryAndroidOptions()
161158
val rnOptions = JavaOnlyMap.of("dsn", "https://[email protected]/1234567")
162-
RNSentryStart.getSentryAndroidOptions(options, rnOptions, activity, logger)
159+
RNSentryStart.getSentryAndroidOptions(options, rnOptions, logger)
163160

164161
val breadcrumb =
165162
Breadcrumb().apply {
@@ -176,7 +173,7 @@ class RNSentryStartTest {
176173
fun `the breadcrumb is not filtered out when the dev server url does not match and the dsn is not passed`() {
177174
val options = SentryAndroidOptions()
178175
val rnOptions = JavaOnlyMap.of("devServerUrl", "http://localhost:8081")
179-
RNSentryStart.getSentryAndroidOptions(options, rnOptions, activity, logger)
176+
RNSentryStart.getSentryAndroidOptions(options, rnOptions, logger)
180177

181178
val breadcrumb =
182179
Breadcrumb().apply {
@@ -188,4 +185,67 @@ class RNSentryStartTest {
188185

189186
assertEquals(breadcrumb, result)
190187
}
188+
189+
@Test
190+
fun `the JavascriptException is added to the ignoredExceptionsForType list on with react defaults`() {
191+
val actualOptions = SentryAndroidOptions()
192+
RNSentryStart.updateWithReactDefaults(actualOptions, activity)
193+
assertTrue(actualOptions.ignoredExceptionsForType.contains(JavascriptException::class.java))
194+
}
195+
196+
@Test
197+
fun `the sdk version information is added to the initialisation options with react defaults`() {
198+
val actualOptions = SentryAndroidOptions()
199+
RNSentryStart.updateWithReactDefaults(actualOptions, activity)
200+
assertEquals(RNSentryVersion.ANDROID_SDK_NAME, actualOptions.sdkVersion?.name)
201+
assertEquals(
202+
io.sentry.android.core.BuildConfig.VERSION_NAME,
203+
actualOptions.sdkVersion?.version,
204+
)
205+
assertEquals(true, actualOptions.sdkVersion?.packages?.isNotEmpty())
206+
assertEquals(
207+
RNSentryVersion.REACT_NATIVE_SDK_PACKAGE_NAME,
208+
actualOptions.sdkVersion
209+
?.packages
210+
?.last()
211+
?.name,
212+
)
213+
assertEquals(
214+
RNSentryVersion.REACT_NATIVE_SDK_PACKAGE_VERSION,
215+
actualOptions.sdkVersion
216+
?.packages
217+
?.last()
218+
?.version,
219+
)
220+
}
221+
222+
@Test
223+
fun `the tracing options are added to the initialisation options with react defaults`() {
224+
val actualOptions = SentryAndroidOptions()
225+
RNSentryStart.updateWithReactDefaults(actualOptions, activity)
226+
assertNull(actualOptions.tracesSampleRate)
227+
assertNull(actualOptions.tracesSampler)
228+
assertEquals(false, actualOptions.enableTracing)
229+
}
230+
231+
@Test
232+
fun `the current activity is added to the initialisation options with react defaults`() {
233+
val actualOptions = SentryAndroidOptions()
234+
RNSentryStart.updateWithReactDefaults(actualOptions, activity)
235+
assertEquals(activity, CurrentActivityHolder.getInstance().activity)
236+
}
237+
238+
@Test
239+
fun `beforeSend callback that sets event tags is set with react finals`() {
240+
val options = SentryAndroidOptions()
241+
val event =
242+
SentryEvent().apply { sdk = SdkVersion(RNSentryVersion.ANDROID_SDK_NAME, "1.0") }
243+
244+
RNSentryStart.updateWithReactFinals(options)
245+
val result = options.beforeSend?.execute(event, mock())
246+
247+
assertNotNull(result)
248+
assertEquals("android", result?.getTag("event.origin"))
249+
assertEquals("java", result?.getTag("event.environment"))
250+
}
191251
}

0 commit comments

Comments
 (0)