From 52bee14d08a49c8581e2159ce04c4959f3f91dcd Mon Sep 17 00:00:00 2001 From: rosariopf Date: Tue, 30 Aug 2022 20:12:08 +0100 Subject: [PATCH 1/5] add kotlinx-coroutines-play-services as a transitive dep to firebase-common-ktx --- build.gradle | 4 ++ firebase-common/ktx/ktx.gradle | 5 +++ .../kotlin/com/google/firebase/ktx/Tests.kt | 39 +++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/build.gradle b/build.gradle index 243e929c49b..3bd436346a6 100644 --- a/build.gradle +++ b/build.gradle @@ -17,6 +17,10 @@ import com.google.firebase.gradle.MultiProjectReleasePlugin buildscript { ext.kotlinVersion = '1.4.32' + // Please update $coroutinesVersion alongside $kotlinVersion + // A map of versions can be found here: https://kotlinlang.org/docs/releases.html + ext.coroutinesVersion = '1.4.3' + repositories { google() mavenCentral() diff --git a/firebase-common/ktx/ktx.gradle b/firebase-common/ktx/ktx.gradle index fac922882f5..2d15573ab83 100644 --- a/firebase-common/ktx/ktx.gradle +++ b/firebase-common/ktx/ktx.gradle @@ -42,8 +42,13 @@ dependencies { implementation project(':firebase-components') implementation 'androidx.annotation:annotation:1.1.0' + // We're exposing this library as a transitive dependency so developers can + // get Kotlin Coroutines support out-of-the-box for methods that return a Task + api "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutinesVersion" + testImplementation "org.robolectric:robolectric:$robolectricVersion" testImplementation 'junit:junit:4.12' testImplementation "com.google.truth:truth:$googleTruthVersion" testImplementation 'androidx.test:core:1.2.0' + testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion" } diff --git a/firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt b/firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt index 62a2d757169..05ec05dbcd0 100644 --- a/firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt +++ b/firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt @@ -15,10 +15,14 @@ package com.google.firebase.ktx import androidx.test.core.app.ApplicationProvider +import com.google.android.gms.tasks.Tasks import com.google.common.truth.Truth.assertThat import com.google.firebase.FirebaseApp import com.google.firebase.FirebaseOptions import com.google.firebase.platforminfo.UserAgentPublisher +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.tasks.await +import org.junit.Assert.fail import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @@ -36,6 +40,8 @@ fun withApp(name: String, block: FirebaseApp.() -> Unit) { } } +class TestException(message: String) : Exception(message) + @RunWith(RobolectricTestRunner::class) class VersionTests { @Test @@ -101,3 +107,36 @@ class KtxTests { } } } + +// TODO(thatfiredev): replace runBlocking() with runTest() once we update kotlin to version >= 1.6 +class CoroutinesPlayServicesTests { + // We are only interested in the await() function offered by kotlinx-coroutines-play-services + // So we're not testing the other functions provided by that library. + + @Test + fun `Task#await() resolves to the same result as Task#getResult()`() = runBlocking { + val task = Tasks.forResult(21) + + val expected = task.result + val actual = task.await() + + assertThat(actual).isEqualTo(expected) + assertThat(task.isSuccessful).isTrue() + assertThat(task.exception).isNull() + } + + @Test + fun `Task#await() throws an Exception for failing Tasks`() = runBlocking { + val task = Tasks.forException(TestException("some error happened")) + + try { + task.await() + fail("Task#await should throw an Exception") + } catch (e: Exception) { + assertThat(e).isInstanceOf(TestException::class.java) + assertThat(task.isSuccessful).isFalse() + } + } + + // TODO(thatfiredev): add a test for CancellationToken once we support Coroutines >= 1.6 +} From eea8af6dc84d0b4a97529c9f64559c0eee6bc739 Mon Sep 17 00:00:00 2001 From: rosariopf Date: Tue, 30 Aug 2022 20:59:58 +0100 Subject: [PATCH 2/5] refactor: only expose the await function --- firebase-common/ktx/ktx.gradle | 6 ++---- .../main/kotlin/com/google/firebase/ktx/Firebase.kt | 11 +++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/firebase-common/ktx/ktx.gradle b/firebase-common/ktx/ktx.gradle index 2d15573ab83..909b712767c 100644 --- a/firebase-common/ktx/ktx.gradle +++ b/firebase-common/ktx/ktx.gradle @@ -41,10 +41,8 @@ dependencies { implementation project(':firebase-common') implementation project(':firebase-components') implementation 'androidx.annotation:annotation:1.1.0' - - // We're exposing this library as a transitive dependency so developers can - // get Kotlin Coroutines support out-of-the-box for methods that return a Task - api "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutinesVersion" + implementation "com.google.android.gms:play-services-tasks:18.0.2" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutinesVersion" testImplementation "org.robolectric:robolectric:$robolectricVersion" testImplementation 'junit:junit:4.12' diff --git a/firebase-common/ktx/src/main/kotlin/com/google/firebase/ktx/Firebase.kt b/firebase-common/ktx/src/main/kotlin/com/google/firebase/ktx/Firebase.kt index f939f218f0f..bbcea56c3a5 100644 --- a/firebase-common/ktx/src/main/kotlin/com/google/firebase/ktx/Firebase.kt +++ b/firebase-common/ktx/src/main/kotlin/com/google/firebase/ktx/Firebase.kt @@ -15,11 +15,13 @@ package com.google.firebase.ktx import android.content.Context import androidx.annotation.Keep +import com.google.android.gms.tasks.Task import com.google.firebase.FirebaseApp import com.google.firebase.FirebaseOptions import com.google.firebase.components.Component import com.google.firebase.components.ComponentRegistrar import com.google.firebase.platforminfo.LibraryVersionComponent +import kotlinx.coroutines.tasks.await /** * Single access point to all firebase SDKs from Kotlin. @@ -50,6 +52,15 @@ fun Firebase.initialize(context: Context, options: FirebaseOptions, name: String val Firebase.options: FirebaseOptions get() = Firebase.app.options +/** + * Awaits the completion of the task without blocking a thread. + * + * This suspending function is cancellable. + * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function + * stops waiting for the completion stage and immediately resumes with [CancellationException]. + */ +suspend fun Task.await(): T = await() + internal const val LIBRARY_NAME: String = "fire-core-ktx" /** @suppress */ From 9a4bb4213697168ded151e05305962f87c6f0eb1 Mon Sep 17 00:00:00 2001 From: rosariopf Date: Wed, 31 Aug 2022 12:38:27 +0100 Subject: [PATCH 3/5] Revert "refactor: only expose the await function" This reverts commit eea8af6dc84d0b4a97529c9f64559c0eee6bc739. --- firebase-common/ktx/ktx.gradle | 6 ++++-- .../main/kotlin/com/google/firebase/ktx/Firebase.kt | 11 ----------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/firebase-common/ktx/ktx.gradle b/firebase-common/ktx/ktx.gradle index 909b712767c..2d15573ab83 100644 --- a/firebase-common/ktx/ktx.gradle +++ b/firebase-common/ktx/ktx.gradle @@ -41,8 +41,10 @@ dependencies { implementation project(':firebase-common') implementation project(':firebase-components') implementation 'androidx.annotation:annotation:1.1.0' - implementation "com.google.android.gms:play-services-tasks:18.0.2" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutinesVersion" + + // We're exposing this library as a transitive dependency so developers can + // get Kotlin Coroutines support out-of-the-box for methods that return a Task + api "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutinesVersion" testImplementation "org.robolectric:robolectric:$robolectricVersion" testImplementation 'junit:junit:4.12' diff --git a/firebase-common/ktx/src/main/kotlin/com/google/firebase/ktx/Firebase.kt b/firebase-common/ktx/src/main/kotlin/com/google/firebase/ktx/Firebase.kt index bbcea56c3a5..f939f218f0f 100644 --- a/firebase-common/ktx/src/main/kotlin/com/google/firebase/ktx/Firebase.kt +++ b/firebase-common/ktx/src/main/kotlin/com/google/firebase/ktx/Firebase.kt @@ -15,13 +15,11 @@ package com.google.firebase.ktx import android.content.Context import androidx.annotation.Keep -import com.google.android.gms.tasks.Task import com.google.firebase.FirebaseApp import com.google.firebase.FirebaseOptions import com.google.firebase.components.Component import com.google.firebase.components.ComponentRegistrar import com.google.firebase.platforminfo.LibraryVersionComponent -import kotlinx.coroutines.tasks.await /** * Single access point to all firebase SDKs from Kotlin. @@ -52,15 +50,6 @@ fun Firebase.initialize(context: Context, options: FirebaseOptions, name: String val Firebase.options: FirebaseOptions get() = Firebase.app.options -/** - * Awaits the completion of the task without blocking a thread. - * - * This suspending function is cancellable. - * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function - * stops waiting for the completion stage and immediately resumes with [CancellationException]. - */ -suspend fun Task.await(): T = await() - internal const val LIBRARY_NAME: String = "fire-core-ktx" /** @suppress */ From 2cf32e7726b075961172e868bd6af94a13e3d7ac Mon Sep 17 00:00:00 2001 From: rosariopf Date: Wed, 31 Aug 2022 14:18:58 +0100 Subject: [PATCH 4/5] bump coroutines to 1.5.2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3bd436346a6..900cd5d3d87 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ buildscript { ext.kotlinVersion = '1.4.32' // Please update $coroutinesVersion alongside $kotlinVersion // A map of versions can be found here: https://kotlinlang.org/docs/releases.html - ext.coroutinesVersion = '1.4.3' + ext.coroutinesVersion = '1.5.2' repositories { google() From 5131b740a102260a5f79c7ae97d67868a1f5ff44 Mon Sep 17 00:00:00 2001 From: rosariopf Date: Tue, 13 Sep 2022 20:21:59 +0100 Subject: [PATCH 5/5] Update to Coroutines 1.6.4 --- build.gradle | 4 +--- .../ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt | 9 +++------ firebase-firestore/ktx/ktx.gradle | 2 +- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index b174a241316..30208819267 100644 --- a/build.gradle +++ b/build.gradle @@ -17,9 +17,7 @@ import com.google.firebase.gradle.MultiProjectReleasePlugin buildscript { ext.kotlinVersion = '1.7.10' - // Please update $coroutinesVersion alongside $kotlinVersion - // A map of versions can be found here: https://kotlinlang.org/docs/releases.html - ext.coroutinesVersion = '1.5.2' + ext.coroutinesVersion = '1.6.4' repositories { google() diff --git a/firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt b/firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt index 05ec05dbcd0..45bcaece248 100644 --- a/firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt +++ b/firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt @@ -20,8 +20,8 @@ import com.google.common.truth.Truth.assertThat import com.google.firebase.FirebaseApp import com.google.firebase.FirebaseOptions import com.google.firebase.platforminfo.UserAgentPublisher -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.tasks.await +import kotlinx.coroutines.test.runTest import org.junit.Assert.fail import org.junit.Test import org.junit.runner.RunWith @@ -108,13 +108,12 @@ class KtxTests { } } -// TODO(thatfiredev): replace runBlocking() with runTest() once we update kotlin to version >= 1.6 class CoroutinesPlayServicesTests { // We are only interested in the await() function offered by kotlinx-coroutines-play-services // So we're not testing the other functions provided by that library. @Test - fun `Task#await() resolves to the same result as Task#getResult()`() = runBlocking { + fun `Task#await() resolves to the same result as Task#getResult()`() = runTest { val task = Tasks.forResult(21) val expected = task.result @@ -126,7 +125,7 @@ class CoroutinesPlayServicesTests { } @Test - fun `Task#await() throws an Exception for failing Tasks`() = runBlocking { + fun `Task#await() throws an Exception for failing Tasks`() = runTest { val task = Tasks.forException(TestException("some error happened")) try { @@ -137,6 +136,4 @@ class CoroutinesPlayServicesTests { assertThat(task.isSuccessful).isFalse() } } - - // TODO(thatfiredev): add a test for CancellationToken once we support Coroutines >= 1.6 } diff --git a/firebase-firestore/ktx/ktx.gradle b/firebase-firestore/ktx/ktx.gradle index a520029398a..04e58cf4d5c 100644 --- a/firebase-firestore/ktx/ktx.gradle +++ b/firebase-firestore/ktx/ktx.gradle @@ -57,7 +57,7 @@ dependencies { implementation project(':firebase-common:ktx') implementation project(':firebase-firestore') implementation 'androidx.annotation:annotation:1.1.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" implementation 'com.google.android.gms:play-services-basement:18.1.0' testImplementation project(':firebase-database-collection') testImplementation 'org.mockito:mockito-core:2.25.0'