@@ -19,10 +19,7 @@ package com.google.firebase.sessions.settings
1919import androidx.test.ext.junit.runners.AndroidJUnit4
2020import com.google.common.truth.Truth.assertThat
2121import com.google.firebase.FirebaseApp
22- import com.google.firebase.installations.FirebaseInstallationsApi
23- import com.google.firebase.sessions.ApplicationInfo
2422import com.google.firebase.sessions.SessionEvents
25- import com.google.firebase.sessions.TimeProvider
2623import com.google.firebase.sessions.testing.FakeFirebaseApp
2724import com.google.firebase.sessions.testing.FakeFirebaseInstallations
2825import com.google.firebase.sessions.testing.FakeRemoteConfigFetcher
@@ -31,55 +28,46 @@ import com.google.firebase.sessions.testing.FakeTimeProvider
3128import kotlin.time.Duration.Companion.minutes
3229import kotlin.time.Duration.Companion.seconds
3330import kotlinx.coroutines.Dispatchers
34- import kotlinx.coroutines.ExperimentalCoroutinesApi
3531import kotlinx.coroutines.delay
3632import kotlinx.coroutines.launch
37- import kotlinx.coroutines.test.UnconfinedTestDispatcher
38- import kotlinx.coroutines.test.runCurrent
3933import kotlinx.coroutines.test.runTest
4034import kotlinx.coroutines.withTimeout
4135import org.json.JSONObject
4236import org.junit.After
4337import org.junit.Test
4438import org.junit.runner.RunWith
4539
46- @OptIn(ExperimentalCoroutinesApi ::class )
4740@RunWith(AndroidJUnit4 ::class )
4841class RemoteSettingsTest {
4942
5043 @Test
51- fun remoteSettings_successfulFetchCachesValues () =
52- runTest(UnconfinedTestDispatcher ()) {
53- val firebaseApp = FakeFirebaseApp ().firebaseApp
54- val firebaseInstallations = FakeFirebaseInstallations (" FaKeFiD" )
55- val fakeFetcher = FakeRemoteConfigFetcher ()
56-
57- val remoteSettings =
58- buildRemoteSettings(
59- FakeTimeProvider (),
60- firebaseInstallations,
61- SessionEvents .getApplicationInfo(firebaseApp),
62- fakeFetcher,
63- FakeSettingsCache (),
64- )
65-
66- runCurrent()
44+ fun remoteSettings_successfulFetchCachesValues () = runTest {
45+ val firebaseApp = FakeFirebaseApp ().firebaseApp
46+ val firebaseInstallations = FakeFirebaseInstallations (" FaKeFiD" )
47+ val fakeFetcher = FakeRemoteConfigFetcher ()
6748
68- assertThat(remoteSettings.sessionEnabled).isNull()
69- assertThat(remoteSettings.samplingRate).isNull()
70- assertThat(remoteSettings.sessionRestartTimeout).isNull()
49+ val remoteSettings =
50+ RemoteSettings (
51+ FakeTimeProvider (),
52+ firebaseInstallations,
53+ SessionEvents .getApplicationInfo(firebaseApp),
54+ fakeFetcher,
55+ FakeSettingsCache (),
56+ )
7157
72- fakeFetcher.responseJSONObject = JSONObject (VALID_RESPONSE )
73- remoteSettings.updateSettings()
58+ assertThat(remoteSettings.sessionEnabled).isNull()
59+ assertThat(remoteSettings.samplingRate).isNull()
60+ assertThat(remoteSettings.sessionRestartTimeout).isNull()
7461
75- runCurrent()
62+ fakeFetcher.responseJSONObject = JSONObject (VALID_RESPONSE )
63+ remoteSettings.updateSettings()
7664
77- assertThat(remoteSettings.sessionEnabled).isFalse()
78- assertThat(remoteSettings.samplingRate).isEqualTo(0.75 )
79- assertThat(remoteSettings.sessionRestartTimeout).isEqualTo(40 .minutes)
65+ assertThat(remoteSettings.sessionEnabled).isFalse()
66+ assertThat(remoteSettings.samplingRate).isEqualTo(0.75 )
67+ assertThat(remoteSettings.sessionRestartTimeout).isEqualTo(40 .minutes)
8068
81- remoteSettings.clearCachedSettings()
82- }
69+ remoteSettings.clearCachedSettings()
70+ }
8371
8472 @Test
8573 fun remoteSettings_successfulFetchWithLessConfigsCachesOnlyReceivedValues () = runTest {
@@ -88,16 +76,14 @@ class RemoteSettingsTest {
8876 val fakeFetcher = FakeRemoteConfigFetcher ()
8977
9078 val remoteSettings =
91- buildRemoteSettings (
79+ RemoteSettings (
9280 FakeTimeProvider (),
9381 firebaseInstallations,
9482 SessionEvents .getApplicationInfo(firebaseApp),
9583 fakeFetcher,
9684 FakeSettingsCache (),
9785 )
9886
99- runCurrent()
100-
10187 assertThat(remoteSettings.sessionEnabled).isNull()
10288 assertThat(remoteSettings.samplingRate).isNull()
10389 assertThat(remoteSettings.sessionRestartTimeout).isNull()
@@ -107,8 +93,6 @@ class RemoteSettingsTest {
10793 fakeFetcher.responseJSONObject = fetchedResponse
10894 remoteSettings.updateSettings()
10995
110- runCurrent()
111-
11296 assertThat(remoteSettings.sessionEnabled).isNull()
11397 assertThat(remoteSettings.samplingRate).isEqualTo(0.75 )
11498 assertThat(remoteSettings.sessionRestartTimeout).isEqualTo(40 .minutes)
@@ -124,7 +108,7 @@ class RemoteSettingsTest {
124108 val fakeTimeProvider = FakeTimeProvider ()
125109
126110 val remoteSettings =
127- buildRemoteSettings (
111+ RemoteSettings (
128112 fakeTimeProvider,
129113 firebaseInstallations,
130114 SessionEvents .getApplicationInfo(firebaseApp),
@@ -137,8 +121,6 @@ class RemoteSettingsTest {
137121 fakeFetcher.responseJSONObject = fetchedResponse
138122 remoteSettings.updateSettings()
139123
140- runCurrent()
141-
142124 assertThat(remoteSettings.sessionEnabled).isFalse()
143125 assertThat(remoteSettings.samplingRate).isEqualTo(0.75 )
144126 assertThat(remoteSettings.sessionRestartTimeout).isEqualTo(40 .minutes)
@@ -152,8 +134,6 @@ class RemoteSettingsTest {
152134 fakeFetcher.responseJSONObject = fetchedResponse
153135 remoteSettings.updateSettings()
154136
155- runCurrent()
156-
157137 assertThat(remoteSettings.sessionEnabled).isTrue()
158138 assertThat(remoteSettings.samplingRate).isEqualTo(0.25 )
159139 assertThat(remoteSettings.sessionRestartTimeout).isEqualTo(20 .minutes)
@@ -162,110 +142,99 @@ class RemoteSettingsTest {
162142 }
163143
164144 @Test
165- fun remoteSettings_successfulFetchWithEmptyConfigRetainsOldConfigs () =
166- runTest(UnconfinedTestDispatcher ()) {
167- val firebaseApp = FakeFirebaseApp ().firebaseApp
168- val firebaseInstallations = FakeFirebaseInstallations (" FaKeFiD" )
169- val fakeFetcher = FakeRemoteConfigFetcher ()
170- val fakeTimeProvider = FakeTimeProvider ()
171-
172- val remoteSettings =
173- buildRemoteSettings(
174- fakeTimeProvider,
175- firebaseInstallations,
176- SessionEvents .getApplicationInfo(firebaseApp),
177- fakeFetcher,
178- FakeSettingsCache (),
179- )
180-
181- val fetchedResponse = JSONObject (VALID_RESPONSE )
182- fetchedResponse.getJSONObject(" app_quality" ).put(" cache_duration" , 1 )
183- fakeFetcher.responseJSONObject = fetchedResponse
184- remoteSettings.updateSettings()
185-
186- runCurrent()
187- fakeTimeProvider.addInterval(31 .seconds)
188-
189- assertThat(remoteSettings.sessionEnabled).isFalse()
190- assertThat(remoteSettings.samplingRate).isEqualTo(0.75 )
191- assertThat(remoteSettings.sessionRestartTimeout).isEqualTo(40 .minutes)
192-
193- fetchedResponse.remove(" app_quality" )
194-
195- // Sleep for a second before updating configs
196- Thread .sleep(2000 )
197-
198- fakeFetcher.responseJSONObject = fetchedResponse
199- remoteSettings.updateSettings()
200-
201- runCurrent()
202- Thread .sleep(30 )
203-
204- assertThat(remoteSettings.sessionEnabled).isFalse()
205- assertThat(remoteSettings.samplingRate).isEqualTo(0.75 )
206- assertThat(remoteSettings.sessionRestartTimeout).isEqualTo(40 .minutes)
207-
208- remoteSettings.clearCachedSettings()
209- }
145+ fun remoteSettings_successfulFetchWithEmptyConfigRetainsOldConfigs () = runTest {
146+ val firebaseApp = FakeFirebaseApp ().firebaseApp
147+ val firebaseInstallations = FakeFirebaseInstallations (" FaKeFiD" )
148+ val fakeFetcher = FakeRemoteConfigFetcher ()
149+ val fakeTimeProvider = FakeTimeProvider ()
150+
151+ val remoteSettings =
152+ RemoteSettings (
153+ fakeTimeProvider,
154+ firebaseInstallations,
155+ SessionEvents .getApplicationInfo(firebaseApp),
156+ fakeFetcher,
157+ FakeSettingsCache (),
158+ )
159+
160+ val fetchedResponse = JSONObject (VALID_RESPONSE )
161+ fetchedResponse.getJSONObject(" app_quality" ).put(" cache_duration" , 1 )
162+ fakeFetcher.responseJSONObject = fetchedResponse
163+ remoteSettings.updateSettings()
164+
165+ fakeTimeProvider.addInterval(31 .seconds)
166+
167+ assertThat(remoteSettings.sessionEnabled).isFalse()
168+ assertThat(remoteSettings.samplingRate).isEqualTo(0.75 )
169+ assertThat(remoteSettings.sessionRestartTimeout).isEqualTo(40 .minutes)
170+
171+ fetchedResponse.remove(" app_quality" )
172+
173+ fakeFetcher.responseJSONObject = fetchedResponse
174+ remoteSettings.updateSettings()
175+
176+ assertThat(remoteSettings.sessionEnabled).isFalse()
177+ assertThat(remoteSettings.samplingRate).isEqualTo(0.75 )
178+ assertThat(remoteSettings.sessionRestartTimeout).isEqualTo(40 .minutes)
179+
180+ remoteSettings.clearCachedSettings()
181+ }
210182
211183 @Test
212- fun remoteSettings_fetchWhileFetchInProgress () =
213- runTest(UnconfinedTestDispatcher ()) {
214- // This test does:
215- // 1. Do a fetch with a fake fetcher that will block for 3 seconds.
216- // 2. While that is happening, do a second fetch.
217- // - First fetch is still fetching, so second fetch should fall through to the mutex.
218- // - Second fetch will be blocked until first completes.
219- // - First fetch returns, should unblock the second fetch.
220- // - Second fetch should go into mutex, sees cache is valid in "double check," exist early.
221- // 3. After a fetch completes, do a third fetch.
222- // - First fetch should have have updated the cache.
223- // - Third fetch should exit even earlier, never having gone into the mutex.
224-
225- val firebaseApp = FakeFirebaseApp ().firebaseApp
226- val firebaseInstallations = FakeFirebaseInstallations (" FaKeFiD" )
227- val fakeFetcherWithDelay =
228- FakeRemoteConfigFetcher (JSONObject (VALID_RESPONSE ), networkDelay = 3 .seconds)
229-
230- fakeFetcherWithDelay.responseJSONObject
231- .getJSONObject(" app_quality" )
232- .put(" sampling_rate" , 0.125 )
233-
234- val remoteSettingsWithDelay =
235- buildRemoteSettings(
236- FakeTimeProvider (),
237- firebaseInstallations,
238- SessionEvents .getApplicationInfo(firebaseApp),
239- configsFetcher = fakeFetcherWithDelay,
240- FakeSettingsCache (),
241- )
242-
243- // Do the first fetch. This one should fetched the configsFetcher.
244- val firstFetch = launch(Dispatchers .Default ) { remoteSettingsWithDelay.updateSettings() }
245-
246- // Wait a second, and then do the second fetch while first is still running.
247- // This one should block until the first fetch completes, but then exit early.
248- launch(Dispatchers .Default ) {
249- delay(1 .seconds)
250- remoteSettingsWithDelay.updateSettings()
251- }
184+ fun remoteSettings_fetchWhileFetchInProgress () = runTest {
185+ // This test does:
186+ // 1. Do a fetch with a fake fetcher that will block for 3 seconds.
187+ // 2. While that is happening, do a second fetch.
188+ // - First fetch is still fetching, so second fetch should fall through to the mutex.
189+ // - Second fetch will be blocked until first completes.
190+ // - First fetch returns, should unblock the second fetch.
191+ // - Second fetch should go into mutex, sees cache is valid in "double check," exist early.
192+ // 3. After a fetch completes, do a third fetch.
193+ // - First fetch should have have updated the cache.
194+ // - Third fetch should exit even earlier, never having gone into the mutex.
195+
196+ val firebaseApp = FakeFirebaseApp ().firebaseApp
197+ val firebaseInstallations = FakeFirebaseInstallations (" FaKeFiD" )
198+ val fakeFetcherWithDelay =
199+ FakeRemoteConfigFetcher (JSONObject (VALID_RESPONSE ), networkDelay = 3 .seconds)
200+
201+ fakeFetcherWithDelay.responseJSONObject.getJSONObject(" app_quality" ).put(" sampling_rate" , 0.125 )
202+
203+ val remoteSettingsWithDelay =
204+ RemoteSettings (
205+ FakeTimeProvider (),
206+ firebaseInstallations,
207+ SessionEvents .getApplicationInfo(firebaseApp),
208+ configsFetcher = fakeFetcherWithDelay,
209+ FakeSettingsCache (),
210+ )
252211
253- // Wait until the first fetch is done, then do a third fetch.
254- // This one should not even block, and exit early.
255- firstFetch.join()
256- withTimeout(1 .seconds) { remoteSettingsWithDelay.updateSettings() }
212+ // Do the first fetch. This one should fetched the configsFetcher.
213+ val firstFetch = launch(Dispatchers .Default ) { remoteSettingsWithDelay.updateSettings() }
257214
258- // Assert that the configsFetcher was fetched exactly once.
259- assertThat(fakeFetcherWithDelay.timesCalled).isEqualTo(1 )
260- assertThat(remoteSettingsWithDelay.samplingRate).isEqualTo(0.125 )
215+ // Wait a second, and then do the second fetch while first is still running.
216+ // This one should block until the first fetch completes, but then exit early.
217+ launch(Dispatchers .Default ) {
218+ delay(1 .seconds)
219+ remoteSettingsWithDelay.updateSettings()
261220 }
262221
222+ // Wait until the first fetch is done, then do a third fetch.
223+ // This one should not even block, and exit early.
224+ firstFetch.join()
225+ withTimeout(1 .seconds) { remoteSettingsWithDelay.updateSettings() }
226+
227+ // Assert that the configsFetcher was fetched exactly once.
228+ assertThat(fakeFetcherWithDelay.timesCalled).isEqualTo(1 )
229+ assertThat(remoteSettingsWithDelay.samplingRate).isEqualTo(0.125 )
230+ }
231+
263232 @After
264233 fun cleanUp () {
265234 FirebaseApp .clearInstancesForTest()
266235 }
267236
268- internal companion object {
237+ private companion object {
269238 const val VALID_RESPONSE =
270239 """
271240 {
@@ -284,30 +253,5 @@ class RemoteSettingsTest {
284253 }
285254 }
286255 """
287-
288- /* *
289- * Build an instance of [RemoteSettings] using the Dagger factory.
290- *
291- * This is needed because the SDK vendors Dagger to a difference namespace, but it does not for
292- * these unit tests. The [RemoteSettings.lazySettingsCache] has type [dagger.Lazy] in these
293- * tests, but type `com.google.firebase.sessions.dagger.Lazy` in the SDK. This method to build
294- * the instance is the easiest I could find that does not need any reference to [dagger.Lazy] in
295- * the test code.
296- */
297- fun buildRemoteSettings (
298- timeProvider : TimeProvider ,
299- firebaseInstallationsApi : FirebaseInstallationsApi ,
300- appInfo : ApplicationInfo ,
301- configsFetcher : CrashlyticsSettingsFetcher ,
302- settingsCache : SettingsCache ,
303- ): RemoteSettings =
304- RemoteSettings_Factory .create(
305- { timeProvider },
306- { firebaseInstallationsApi },
307- { appInfo },
308- { configsFetcher },
309- { settingsCache },
310- )
311- .get()
312256 }
313257}
0 commit comments