Skip to content

Commit 046f833

Browse files
committed
add unit tests for session Repo
1 parent ad11092 commit 046f833

File tree

2 files changed

+238
-1
lines changed

2 files changed

+238
-1
lines changed

firebase-sessions/src/main/kotlin/com/google/firebase/sessions/SharedSessionRepository.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,12 @@ constructor(
5656
* Either notify the subscribers with general multi-process supported session or fallback local
5757
* session
5858
*/
59-
private enum class NotificationType {
59+
@VisibleForTesting
60+
enum class NotificationType {
6061
GENERAL,
6162
FALLBACK
6263
}
64+
@VisibleForTesting var previousNotificationType: NotificationType = NotificationType.GENERAL
6365

6466
init {
6567
println("session repo init")
@@ -142,6 +144,7 @@ constructor(
142144
}
143145

144146
private suspend fun notifySubscribers(sessionId: String, type: NotificationType) {
147+
previousNotificationType = type
145148
FirebaseSessionsDependencies.getRegisteredSubscribers().values.forEach { subscriber ->
146149
// Notify subscribers, regardless of sampling and data collection state
147150
subscriber.onSessionChanged(SessionSubscriber.SessionDetails(sessionId))
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
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
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.settings.SessionsSettings
24+
import com.google.firebase.sessions.testing.FakeDataStore
25+
import com.google.firebase.sessions.testing.FakeEventGDTLogger
26+
import com.google.firebase.sessions.testing.FakeFirebaseApp
27+
import com.google.firebase.sessions.testing.FakeFirebaseInstallations
28+
import com.google.firebase.sessions.testing.FakeSettingsProvider
29+
import com.google.firebase.sessions.testing.FakeTimeProvider
30+
import com.google.firebase.sessions.testing.FakeUuidGenerator
31+
import kotlin.time.Duration
32+
import kotlinx.coroutines.ExperimentalCoroutinesApi
33+
import kotlinx.coroutines.asCoroutineDispatcher
34+
import kotlinx.coroutines.launch
35+
import kotlinx.coroutines.test.runCurrent
36+
import kotlinx.coroutines.test.runTest
37+
import org.junit.After
38+
import org.junit.Test
39+
import org.junit.runner.RunWith
40+
41+
@OptIn(ExperimentalCoroutinesApi::class)
42+
@RunWith(AndroidJUnit4::class)
43+
class SharedSessionRepositoryTest {
44+
private val fakeFirebaseApp = FakeFirebaseApp()
45+
private val fakeEventGDTLogger = FakeEventGDTLogger()
46+
private val firebaseInstallations = FakeFirebaseInstallations("FaKeFiD", "FakeAuthToken")
47+
private var fakeTimeProvider = FakeTimeProvider()
48+
private val sessionGenerator = SessionGenerator(fakeTimeProvider, FakeUuidGenerator())
49+
private var localSettingsProvider = FakeSettingsProvider(true, null, 100.0)
50+
private var remoteSettingsProvider = FakeSettingsProvider(true, null, 100.0)
51+
private var sessionsSettings = SessionsSettings(localSettingsProvider, remoteSettingsProvider)
52+
53+
@After
54+
fun cleanUp() {
55+
FirebaseApp.clearInstancesForTest()
56+
}
57+
58+
@Test
59+
fun initpSharedSessionRepo_readFromDatastore() = runTest {
60+
val publisher =
61+
SessionFirelogPublisherImpl(
62+
fakeFirebaseApp.firebaseApp,
63+
firebaseInstallations,
64+
sessionsSettings,
65+
eventGDTLogger = fakeEventGDTLogger,
66+
TestOnlyExecutors.background().asCoroutineDispatcher() + coroutineContext,
67+
)
68+
val fakeDataStore =
69+
FakeDataStore<SessionData>(
70+
SessionData(
71+
SessionDetails(
72+
SESSION_ID_INIT,
73+
SESSION_ID_INIT,
74+
0,
75+
fakeTimeProvider.currentTime().ms,
76+
),
77+
fakeTimeProvider.currentTime(),
78+
)
79+
)
80+
val sharedSessionRepository =
81+
SharedSessionRepositoryImpl(
82+
sessionsSettings = sessionsSettings,
83+
sessionGenerator = sessionGenerator,
84+
sessionFirelogPublisher = publisher,
85+
timeProvider = fakeTimeProvider,
86+
sessionDataStore = fakeDataStore,
87+
backgroundDispatcher =
88+
TestOnlyExecutors.background().asCoroutineDispatcher() + coroutineContext
89+
)
90+
runCurrent()
91+
fakeDataStore.close()
92+
assertThat(sharedSessionRepository.localSessionData.sessionDetails.sessionId)
93+
.isEqualTo(SESSION_ID_INIT)
94+
}
95+
96+
@Test
97+
fun initSharedSessionRepo_initException() = runTest {
98+
val publisher =
99+
SessionFirelogPublisherImpl(
100+
fakeFirebaseApp.firebaseApp,
101+
firebaseInstallations,
102+
sessionsSettings,
103+
eventGDTLogger = fakeEventGDTLogger,
104+
TestOnlyExecutors.background().asCoroutineDispatcher() + coroutineContext,
105+
)
106+
val fakeDataStore =
107+
FakeDataStore<SessionData>(
108+
SessionData(
109+
SessionDetails(
110+
SESSION_ID_INIT,
111+
SESSION_ID_INIT,
112+
0,
113+
fakeTimeProvider.currentTime().ms,
114+
),
115+
fakeTimeProvider.currentTime(),
116+
),
117+
IllegalArgumentException("Datastore init failed")
118+
)
119+
val sharedSessionRepository =
120+
SharedSessionRepositoryImpl(
121+
sessionsSettings = sessionsSettings,
122+
sessionGenerator = sessionGenerator,
123+
sessionFirelogPublisher = publisher,
124+
timeProvider = fakeTimeProvider,
125+
sessionDataStore = fakeDataStore,
126+
backgroundDispatcher =
127+
TestOnlyExecutors.background().asCoroutineDispatcher() + coroutineContext
128+
)
129+
runCurrent()
130+
fakeDataStore.close()
131+
assertThat(sharedSessionRepository.localSessionData.sessionDetails.sessionId)
132+
.isEqualTo(SESSION_ID_1)
133+
}
134+
135+
@Test
136+
fun appForegroundSharedSessionRepo_updateSuccess() = runTest {
137+
val publisher =
138+
SessionFirelogPublisherImpl(
139+
fakeFirebaseApp.firebaseApp,
140+
firebaseInstallations,
141+
sessionsSettings,
142+
eventGDTLogger = fakeEventGDTLogger,
143+
TestOnlyExecutors.background().asCoroutineDispatcher() + coroutineContext,
144+
)
145+
val fakeDataStore =
146+
FakeDataStore<SessionData>(
147+
SessionData(
148+
SessionDetails(
149+
SESSION_ID_INIT,
150+
SESSION_ID_INIT,
151+
0,
152+
fakeTimeProvider.currentTime().ms,
153+
),
154+
fakeTimeProvider.currentTime(),
155+
),
156+
IllegalArgumentException("Datastore init failed")
157+
)
158+
val sharedSessionRepository =
159+
SharedSessionRepositoryImpl(
160+
sessionsSettings = sessionsSettings,
161+
sessionGenerator = sessionGenerator,
162+
sessionFirelogPublisher = publisher,
163+
timeProvider = fakeTimeProvider,
164+
sessionDataStore = fakeDataStore,
165+
backgroundDispatcher =
166+
TestOnlyExecutors.background().asCoroutineDispatcher() + coroutineContext
167+
)
168+
backgroundScope.launch {
169+
fakeTimeProvider.addInterval(Duration.parse("20h"))
170+
sharedSessionRepository.appForeground()
171+
}
172+
runCurrent()
173+
assertThat(sharedSessionRepository.localSessionData.sessionDetails.sessionId)
174+
.isEqualTo(SESSION_ID_1)
175+
assertThat(sharedSessionRepository.previousNotificationType)
176+
.isEqualTo(SharedSessionRepositoryImpl.NotificationType.GENERAL)
177+
fakeDataStore.close()
178+
}
179+
180+
@Test
181+
fun appForegroundSharedSessionRepo_updateFail() = runTest {
182+
val publisher =
183+
SessionFirelogPublisherImpl(
184+
fakeFirebaseApp.firebaseApp,
185+
firebaseInstallations,
186+
sessionsSettings,
187+
eventGDTLogger = fakeEventGDTLogger,
188+
TestOnlyExecutors.background().asCoroutineDispatcher() + coroutineContext,
189+
)
190+
val fakeDataStore =
191+
FakeDataStore<SessionData>(
192+
SessionData(
193+
SessionDetails(
194+
SESSION_ID_INIT,
195+
SESSION_ID_INIT,
196+
0,
197+
fakeTimeProvider.currentTime().ms,
198+
),
199+
fakeTimeProvider.currentTime(),
200+
),
201+
IllegalArgumentException("Datastore init failed")
202+
)
203+
fakeDataStore.throwOnNextUpdateData(IllegalArgumentException("Datastore update failed"))
204+
val sharedSessionRepository =
205+
SharedSessionRepositoryImpl(
206+
sessionsSettings = sessionsSettings,
207+
sessionGenerator = sessionGenerator,
208+
sessionFirelogPublisher = publisher,
209+
timeProvider = fakeTimeProvider,
210+
sessionDataStore = fakeDataStore,
211+
backgroundDispatcher =
212+
TestOnlyExecutors.background().asCoroutineDispatcher() + coroutineContext
213+
)
214+
215+
backgroundScope.launch {
216+
fakeTimeProvider.addInterval(Duration.parse("20h"))
217+
sharedSessionRepository.appForeground()
218+
}
219+
runCurrent()
220+
// session_2 here because session_1 is failed when try to update datastore
221+
assertThat(sharedSessionRepository.localSessionData.sessionDetails.sessionId)
222+
.isEqualTo(SESSION_ID_2)
223+
assertThat(sharedSessionRepository.previousNotificationType)
224+
.isEqualTo(SharedSessionRepositoryImpl.NotificationType.FALLBACK)
225+
fakeDataStore.close()
226+
}
227+
228+
companion object {
229+
const val SESSION_ID_INIT = "12345678901234546677960"
230+
const val SESSION_ID_1 = "11111111111111111111111111111111"
231+
const val SESSION_ID_2 = "22222222222222222222222222222222"
232+
const val SESSION_ID_3 = "cccccccccccccccccccccccccccccccc"
233+
}
234+
}

0 commit comments

Comments
 (0)