Skip to content

Commit b06fcf7

Browse files
committed
Add unit test
1 parent fdf379d commit b06fcf7

File tree

2 files changed

+127
-1
lines changed

2 files changed

+127
-1
lines changed

firebase-sessions/src/main/kotlin/com/google/firebase/sessions/api/CrashEventReceiver.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.google.firebase.sessions.api
1818

19+
import androidx.annotation.VisibleForTesting
1920
import com.google.firebase.sessions.SharedSessionRepository
2021

2122
/**
@@ -25,6 +26,7 @@ import com.google.firebase.sessions.SharedSessionRepository
2526
* crash has occurred.
2627
*/
2728
object CrashEventReceiver {
29+
@VisibleForTesting internal lateinit var sharedSessionRepository: SharedSessionRepository
2830

2931
/**
3032
* Notifies the Firebase Sessions SDK that a fatal crash has occurred.
@@ -38,8 +40,10 @@ object CrashEventReceiver {
3840
@JvmStatic
3941
fun notifyCrashOccurred() {
4042
try {
43+
if (!::sharedSessionRepository.isInitialized) {
44+
sharedSessionRepository = SharedSessionRepository.instance
45+
}
4146
// Treat a foreground crash as if the app went to the background, and update session state.
42-
val sharedSessionRepository = SharedSessionRepository.instance
4347
if (sharedSessionRepository.isInForeground) {
4448
sharedSessionRepository.appBackground()
4549
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.firebase.sessions.api
18+
19+
import androidx.test.ext.junit.runners.AndroidJUnit4
20+
import com.google.common.truth.Truth.assertThat
21+
import com.google.firebase.FirebaseApp
22+
import com.google.firebase.concurrent.TestOnlyExecutors
23+
import com.google.firebase.sessions.SessionData
24+
import com.google.firebase.sessions.SessionDetails
25+
import com.google.firebase.sessions.SessionFirelogPublisherImpl
26+
import com.google.firebase.sessions.SessionGenerator
27+
import com.google.firebase.sessions.SharedSessionRepositoryImpl
28+
import com.google.firebase.sessions.SharedSessionRepositoryTest.Companion.SESSION_ID_INIT
29+
import com.google.firebase.sessions.settings.SessionsSettings
30+
import com.google.firebase.sessions.testing.FakeDataStore
31+
import com.google.firebase.sessions.testing.FakeEventGDTLogger
32+
import com.google.firebase.sessions.testing.FakeFirebaseApp
33+
import com.google.firebase.sessions.testing.FakeFirebaseInstallations
34+
import com.google.firebase.sessions.testing.FakeProcessDataManager
35+
import com.google.firebase.sessions.testing.FakeSettingsProvider
36+
import com.google.firebase.sessions.testing.FakeTimeProvider
37+
import com.google.firebase.sessions.testing.FakeUuidGenerator
38+
import kotlin.time.Duration.Companion.minutes
39+
import kotlin.time.Duration.Companion.seconds
40+
import kotlinx.coroutines.ExperimentalCoroutinesApi
41+
import kotlinx.coroutines.asCoroutineDispatcher
42+
import kotlinx.coroutines.test.runCurrent
43+
import kotlinx.coroutines.test.runTest
44+
import org.junit.Test
45+
import org.junit.runner.RunWith
46+
47+
@OptIn(ExperimentalCoroutinesApi::class)
48+
@RunWith(AndroidJUnit4::class)
49+
class CrashEventReceiverTest {
50+
@Test
51+
fun notifyCrashOccurredOnForegroundOnly() = runTest {
52+
// Setup
53+
val fakeFirebaseApp = FakeFirebaseApp()
54+
val fakeEventGDTLogger = FakeEventGDTLogger()
55+
val firebaseInstallations = FakeFirebaseInstallations("FaKeFiD", "FakeAuthToken")
56+
val fakeTimeProvider = FakeTimeProvider()
57+
val sessionGenerator = SessionGenerator(fakeTimeProvider, FakeUuidGenerator())
58+
val localSettingsProvider = FakeSettingsProvider(true, null, 100.0)
59+
val remoteSettingsProvider = FakeSettingsProvider(true, null, 100.0)
60+
val sessionsSettings = SessionsSettings(localSettingsProvider, remoteSettingsProvider)
61+
val publisher =
62+
SessionFirelogPublisherImpl(
63+
fakeFirebaseApp.firebaseApp,
64+
firebaseInstallations,
65+
sessionsSettings,
66+
eventGDTLogger = fakeEventGDTLogger,
67+
TestOnlyExecutors.background().asCoroutineDispatcher() + coroutineContext,
68+
)
69+
val fakeDataStore =
70+
FakeDataStore(
71+
SessionData(
72+
SessionDetails(SESSION_ID_INIT, SESSION_ID_INIT, 0, fakeTimeProvider.currentTime().ms),
73+
fakeTimeProvider.currentTime(),
74+
)
75+
)
76+
val sharedSessionRepository =
77+
SharedSessionRepositoryImpl(
78+
sessionsSettings = sessionsSettings,
79+
sessionGenerator = sessionGenerator,
80+
sessionFirelogPublisher = publisher,
81+
timeProvider = fakeTimeProvider,
82+
sessionDataStore = fakeDataStore,
83+
processDataManager = FakeProcessDataManager(),
84+
backgroundDispatcher =
85+
TestOnlyExecutors.background().asCoroutineDispatcher() + coroutineContext,
86+
)
87+
CrashEventReceiver.sharedSessionRepository = sharedSessionRepository
88+
89+
runCurrent()
90+
91+
// Process starts in the background
92+
assertThat(sharedSessionRepository.isInForeground).isFalse()
93+
94+
// This will not update background time since the process is already in the background
95+
CrashEventReceiver.notifyCrashOccurred()
96+
assertThat(sharedSessionRepository.localSessionData.backgroundTime)
97+
.isEqualTo(fakeTimeProvider.currentTime())
98+
99+
// Wait a bit, then bring the process to foreground
100+
fakeTimeProvider.addInterval(31.minutes)
101+
sharedSessionRepository.appForeground()
102+
103+
runCurrent()
104+
105+
// The background time got cleared
106+
assertThat(sharedSessionRepository.localSessionData.backgroundTime).isNull()
107+
108+
// Wait a bit, then notify of a crash
109+
fakeTimeProvider.addInterval(3.seconds)
110+
CrashEventReceiver.notifyCrashOccurred()
111+
112+
runCurrent()
113+
114+
// Verify the background time got updated
115+
assertThat(sharedSessionRepository.localSessionData.backgroundTime)
116+
.isEqualTo(fakeTimeProvider.currentTime())
117+
118+
// Clean up
119+
fakeDataStore.close()
120+
FirebaseApp.clearInstancesForTest()
121+
}
122+
}

0 commit comments

Comments
 (0)