Skip to content
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

Use appLaunchedInForeground to determine invalid app start data on Android #4146

Merged
merged 10 commits into from
Oct 9, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Fixes

- Use `appLaunchedInForeground` to determine invalid app start data on Android ([#4146](https://github.com/getsentry/sentry-react-native/pull/4146))
- Emits Bridge log only in debug mode ([#4145](https://github.com/getsentry/sentry-react-native/pull/4145))

### Dependencies
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package io.sentry.react

import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.WritableMap
import io.sentry.ILogger
import io.sentry.SentryLevel
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mockito.*
import org.mockito.MockitoAnnotations
import org.mockito.MockedStatic
import org.mockito.Mockito.mockStatic
import org.mockito.kotlin.whenever

@RunWith(JUnit4::class)
class RNSentryModuleImplTest {

private lateinit var module: RNSentryModuleImpl
private lateinit var promise: Promise
private lateinit var logger: ILogger
private var argumentsMock: MockedStatic<Arguments>? = null

@Captor
private lateinit var writableMapCaptor: ArgumentCaptor<WritableMap>


antonis marked this conversation as resolved.
Show resolved Hide resolved
@Before
fun setUp() {
MockitoAnnotations.openMocks(this)
val reactContext = mock(ReactApplicationContext::class.java)
promise = mock(Promise::class.java)
logger = mock(ILogger::class.java)
val packageManager = mock(PackageManager::class.java)
val packageInfo = mock(PackageInfo::class.java)

whenever(reactContext.packageManager).thenReturn(packageManager)
whenever(packageManager.getPackageInfo(anyString(), anyInt())).thenReturn(packageInfo)

module = RNSentryModuleImpl(reactContext)

// Mock the Arguments class
argumentsMock = mockStatic(Arguments::class.java)
val writableMap = mock(WritableMap::class.java)
whenever(Arguments.createMap()).thenReturn(writableMap)
}

@After
fun tearDown() {
argumentsMock?.close()
}

@Test
fun `fetchNativeAppStart resolves promise with null when app is not launched in the foreground`() {
// Mock the app start measurement
val appStartMeasurement = mapOf<String, Any>()

// Call the method
module.fetchNativeAppStart(promise, appStartMeasurement, logger, false)

// Verify a warning log is emitted
verify(logger, org.mockito.kotlin.times(1)).log(
SentryLevel.WARNING,
"Invalid app start data: app not launched in foreground."
)

// Verify the promise is resolved with null
verify(promise).resolve(null)
}

@Test
fun `fetchNativeAppStart resolves promise with app start data when app is launched in the foreground`() {
// Mock the app start measurement
val appStartMeasurement = mapOf<String, Any>()

// Call the method
module.fetchNativeAppStart(promise, appStartMeasurement, logger, true)

// Verify no logs are emitted
verify(logger, org.mockito.kotlin.times(0)).log(any(), any())

// Verify the promise is resolved with the expected data
verify(promise).resolve(any(WritableMap::class.java))
verify(promise).resolve(writableMapCaptor.capture())
val capturedMap = writableMapCaptor.value
assertEquals(false, capturedMap.getBoolean("has_fetched"))
}
}
12 changes: 10 additions & 2 deletions android/src/main/java/io/sentry/react/RNSentryModuleImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -380,9 +380,17 @@ public void fetchNativeRelease(Promise promise) {
}

public void fetchNativeAppStart(Promise promise) {
final Map<String, Object> measurement = InternalSentrySdk.getAppStartMeasurement();
fetchNativeAppStart(promise, InternalSentrySdk.getAppStartMeasurement(), logger, AppStartMetrics.getInstance().isAppLaunchedInForeground());
}

protected void fetchNativeAppStart(Promise promise, final Map<String, Object> appStartMeasurement, ILogger logger, boolean isAppLaunchedInForeground) {
if (!isAppLaunchedInForeground) {
logger.log(SentryLevel.WARNING, "Invalid app start data: app not launched in foreground.");
promise.resolve(null);
return;
}

WritableMap mutableMeasurement = (WritableMap) RNSentryMapConverter.convertToWritable(measurement);
WritableMap mutableMeasurement = (WritableMap) RNSentryMapConverter.convertToWritable(appStartMeasurement);
mutableMeasurement.putBoolean("has_fetched", hasFetchedAppStart);

// This is always set to true, as we would only allow an app start fetch to only
Expand Down
Loading