From b680de15b14c6a1346e2954afbbd62a20796409d Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Mon, 17 Feb 2025 12:50:29 +0000 Subject: [PATCH] Add coroutines executeAsync extension to OkHttp in sample (#2520) * Add coroutines executeAsync extension to OkHttp in sample --- gradle/libs.versions.toml | 1 + network-awareness/okhttp/build.gradle.kts | 1 + .../rules/NetworkSelectingCallFactoryTest.kt | 43 +++++-------------- sample/build.gradle.kts | 1 + .../horologist/networks/ExecuteAsync.kt | 41 ------------------ .../networks/NetworkScreenViewModel.kt | 1 + 6 files changed, 14 insertions(+), 74 deletions(-) delete mode 100644 sample/src/main/java/com/google/android/horologist/networks/ExecuteAsync.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6cc1253c50..a49be26c52 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -199,6 +199,7 @@ mikepenz-markdown = "com.mikepenz:multiplatform-markdown-renderer:0.27.0" moshi-adapters = { module = "com.squareup.moshi:moshi-adapters", version.ref = "moshi" } moshi-kotlin = { module = "com.squareup.moshi:moshi-kotlin", version.ref = "moshi" } moshi-kotlin-codegen = { module = "com.squareup.moshi:moshi-kotlin-codegen", version.ref = "moshi" } +okhttp-coroutines = { module = "com.squareup.okhttp3:okhttp-coroutines", version.ref = "com-squareup-okhttp3" } okio = { module = "com.squareup.okio:okio", version.ref = "okio" } oss-licenses-plugin = { module = "com.google.android.gms:oss-licenses-plugin", version.ref = "ossLicensesPlugin" } osslicenses-parser = { module = "com.github.droibit.oss-licenses-android:parser", version.ref = "osslicenses" } diff --git a/network-awareness/okhttp/build.gradle.kts b/network-awareness/okhttp/build.gradle.kts index b8c013ad08..2e4bd0c6ba 100644 --- a/network-awareness/okhttp/build.gradle.kts +++ b/network-awareness/okhttp/build.gradle.kts @@ -92,6 +92,7 @@ dependencies { implementation(libs.kotlin.stdlib) implementation(libs.com.squareup.okhttp3.okhttp) + implementation(libs.okhttp.coroutines) implementation(libs.androidx.annotation) api(libs.kotlinx.coroutines.core) diff --git a/network-awareness/okhttp/src/test/java/com/google/android/horologist/networks/rules/NetworkSelectingCallFactoryTest.kt b/network-awareness/okhttp/src/test/java/com/google/android/horologist/networks/rules/NetworkSelectingCallFactoryTest.kt index 2e7a7e027f..b9a113995f 100644 --- a/network-awareness/okhttp/src/test/java/com/google/android/horologist/networks/rules/NetworkSelectingCallFactoryTest.kt +++ b/network-awareness/okhttp/src/test/java/com/google/android/horologist/networks/rules/NetworkSelectingCallFactoryTest.kt @@ -36,17 +36,13 @@ import com.google.android.horologist.networks.testdoubles.FakeNetworkRequester import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope -import okhttp3.Call -import okhttp3.Callback +import kotlinx.coroutines.test.runTest import okhttp3.OkHttpClient import okhttp3.Request -import okhttp3.Response +import okhttp3.coroutines.executeAsync import org.junit.Assert.assertThrows import org.junit.Test import java.io.IOException -import java.util.concurrent.CompletableFuture -import java.util.concurrent.ExecutionException -import java.util.concurrent.TimeUnit import kotlin.time.Duration.Companion.seconds class NetworkSelectingCallFactoryTest { @@ -114,7 +110,7 @@ class NetworkSelectingCallFactoryTest { } @Test - fun enqueueNormalConnectionForImages() { + fun enqueueNormalConnectionForImages() = runTest { val request = Request.Builder() .url("https://example.org/image.png") .requestType(RequestType.ImageRequest) @@ -128,7 +124,7 @@ class NetworkSelectingCallFactoryTest { } @Test - fun enqueueRequestHighBandwidthForDownloads() { + fun enqueueRequestHighBandwidthForDownloads() = runTest { networkingRules.preferredNetworks[RequestType.MediaRequest(Download)] = NetworkType.Wifi networkingRules.highBandwidthTypes[RequestType.MediaRequest(Download)] = true networkRequester.supportedNetworks = listOf(NetworkType.Wifi) @@ -149,7 +145,7 @@ class NetworkSelectingCallFactoryTest { } @Test - fun enqueueRequestHighBandwidthForDownloadsButFails() { + fun enqueueRequestHighBandwidthForDownloadsButFails(): Unit = runTest { networkingRules.preferredNetworks[DownloadRequest] = NetworkType.Wifi networkingRules.highBandwidthTypes[DownloadRequest] = true networkingRules.validRequests[Pair(DownloadRequest, BT)] = false @@ -160,32 +156,13 @@ class NetworkSelectingCallFactoryTest { .requestType(RequestType.MediaRequest(Download)) .build() - val thrown = assertThrows(IOException::class.java) { - callFactory.newCall(request).executeAsync() - } + val result = runCatching { callFactory.newCall(request).executeAsync() } - assertThat(thrown).hasMessageThat().isEqualTo("Unable to use BT for media-download") + assertThat(result.isFailure).isTrue() + val throwable = result.exceptionOrNull() + assertThat(throwable).isInstanceOf(IOException::class.java) + assertThat(throwable).hasMessageThat().isEqualTo("Unable to use BT for media-download") // assertThat(highBandwidthRequester.pinned.value).isNull() } } - -private fun Call.executeAsync(): Response { - val future = CompletableFuture() - - enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - future.completeExceptionally(e) - } - - override fun onResponse(call: Call, response: Response) { - future.complete(response) - } - }) - - return try { - future.get(5, TimeUnit.SECONDS) - } catch (ee: ExecutionException) { - throw ee.cause!! - } -} diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index b788a169d1..9ec8946e55 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -142,6 +142,7 @@ dependencies { implementation(libs.lottie.compose) implementation(libs.com.squareup.okhttp3.logging.interceptor) + implementation(libs.okhttp.coroutines) implementation(libs.compose.ui.toolingpreview) implementation(libs.androidx.wear.tooling.preview) diff --git a/sample/src/main/java/com/google/android/horologist/networks/ExecuteAsync.kt b/sample/src/main/java/com/google/android/horologist/networks/ExecuteAsync.kt deleted file mode 100644 index b1b5b55865..0000000000 --- a/sample/src/main/java/com/google/android/horologist/networks/ExecuteAsync.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.horologist.networks - -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.suspendCancellableCoroutine -import okhttp3.Call -import okhttp3.Callback -import okhttp3.Response -import java.io.IOException -import kotlin.coroutines.resumeWithException - -@OptIn(ExperimentalCoroutinesApi::class) -suspend fun Call.executeAsync(): Response = suspendCancellableCoroutine { continuation -> - continuation.invokeOnCancellation { - this.cancel() - } - this.enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - continuation.resumeWithException(e) - } - - override fun onResponse(call: Call, response: Response) { - continuation.resume(value = response, onCancellation = { call.cancel() }) - } - }) -} diff --git a/sample/src/main/java/com/google/android/horologist/networks/NetworkScreenViewModel.kt b/sample/src/main/java/com/google/android/horologist/networks/NetworkScreenViewModel.kt index 9df32e663c..642914aa98 100644 --- a/sample/src/main/java/com/google/android/horologist/networks/NetworkScreenViewModel.kt +++ b/sample/src/main/java/com/google/android/horologist/networks/NetworkScreenViewModel.kt @@ -36,6 +36,7 @@ import kotlinx.coroutines.launch import okhttp3.Call import okhttp3.OkHttpClient import okhttp3.Request +import okhttp3.coroutines.executeAsync import java.io.IOException public class NetworkScreenViewModel(