From f0670e2f3936f0223c02e9ec0d0de52f31a3539f Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 11 Aug 2020 09:41:40 -0300 Subject: [pos] Improve coroutine-based merchant library access --- merchant-lib/build.gradle | 1 + .../main/java/net/taler/merchantlib/MerchantApi.kt | 76 +++++++++++++--------- .../main/java/net/taler/merchantlib/Response.kt | 4 +- .../java/net/taler/merchantlib/MerchantApiTest.kt | 20 +++--- 4 files changed, 60 insertions(+), 41 deletions(-) (limited to 'merchant-lib') diff --git a/merchant-lib/build.gradle b/merchant-lib/build.gradle index 33e8379..5082253 100644 --- a/merchant-lib/build.gradle +++ b/merchant-lib/build.gradle @@ -56,4 +56,5 @@ dependencies { testImplementation 'junit:junit:4.13' testImplementation "io.ktor:ktor-client-mock-jvm:$ktor_version" testImplementation "io.ktor:ktor-client-logging-jvm:$ktor_version" + testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8' } diff --git a/merchant-lib/src/main/java/net/taler/merchantlib/MerchantApi.kt b/merchant-lib/src/main/java/net/taler/merchantlib/MerchantApi.kt index c92d4d2..a4ca397 100644 --- a/merchant-lib/src/main/java/net/taler/merchantlib/MerchantApi.kt +++ b/merchant-lib/src/main/java/net/taler/merchantlib/MerchantApi.kt @@ -27,63 +27,81 @@ import io.ktor.client.request.post import io.ktor.http.ContentType.Application.Json import io.ktor.http.HttpHeaders.Authorization import io.ktor.http.contentType +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonConfiguration import net.taler.merchantlib.Response.Companion.response -class MerchantApi(private val httpClient: HttpClient) { +class MerchantApi( + private val httpClient: HttpClient = getDefaultHttpClient(), + private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO +) { - suspend fun getConfig(baseUrl: String): Response = response { - httpClient.get("$baseUrl/config") as ConfigResponse + suspend fun getConfig(baseUrl: String): Response = withContext(ioDispatcher) { + response { + httpClient.get("$baseUrl/config") as ConfigResponse + } } suspend fun postOrder( merchantConfig: MerchantConfig, orderRequest: PostOrderRequest - ): Response = response { - httpClient.post(merchantConfig.urlFor("private/orders")) { - header(Authorization, "ApiKey ${merchantConfig.apiKey}") - contentType(Json) - body = orderRequest - } as PostOrderResponse + ): Response = withContext(ioDispatcher) { + response { + httpClient.post(merchantConfig.urlFor("private/orders")) { + header(Authorization, "ApiKey ${merchantConfig.apiKey}") + contentType(Json) + body = orderRequest + } as PostOrderResponse + } } suspend fun checkOrder( merchantConfig: MerchantConfig, orderId: String - ): Response = response { - httpClient.get(merchantConfig.urlFor("private/orders/$orderId")) { - header(Authorization, "ApiKey ${merchantConfig.apiKey}") - } as CheckPaymentResponse + ): Response = withContext(ioDispatcher) { + response { + httpClient.get(merchantConfig.urlFor("private/orders/$orderId")) { + header(Authorization, "ApiKey ${merchantConfig.apiKey}") + } as CheckPaymentResponse + } } suspend fun deleteOrder( merchantConfig: MerchantConfig, orderId: String - ): Response = response { - httpClient.delete(merchantConfig.urlFor("private/orders/$orderId")) { - header(Authorization, "ApiKey ${merchantConfig.apiKey}") - } as Unit + ): Response = withContext(ioDispatcher) { + response { + httpClient.delete(merchantConfig.urlFor("private/orders/$orderId")) { + header(Authorization, "ApiKey ${merchantConfig.apiKey}") + } as Unit + } } - suspend fun getOrderHistory(merchantConfig: MerchantConfig): Response = response { - httpClient.get(merchantConfig.urlFor("private/orders")) { - header(Authorization, "ApiKey ${merchantConfig.apiKey}") - } as OrderHistory - } + suspend fun getOrderHistory(merchantConfig: MerchantConfig): Response = + withContext(ioDispatcher) { + response { + httpClient.get(merchantConfig.urlFor("private/orders")) { + header(Authorization, "ApiKey ${merchantConfig.apiKey}") + } as OrderHistory + } + } suspend fun giveRefund( merchantConfig: MerchantConfig, orderId: String, request: RefundRequest - ): Response = response { - httpClient.post(merchantConfig.urlFor("private/orders/$orderId/refund")) { - header(Authorization, "ApiKey ${merchantConfig.apiKey}") - contentType(Json) - body = request - } as RefundResponse + ): Response = withContext(ioDispatcher) { + response { + httpClient.post(merchantConfig.urlFor("private/orders/$orderId/refund")) { + header(Authorization, "ApiKey ${merchantConfig.apiKey}") + contentType(Json) + body = request + } as RefundResponse + } } - } fun getDefaultHttpClient(): HttpClient = HttpClient(OkHttp) { diff --git a/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt b/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt index 65a12a9..fb48b46 100644 --- a/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt +++ b/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt @@ -25,7 +25,6 @@ import kotlinx.serialization.Serializable class Response private constructor( private val value: Any? ) { - companion object { suspend fun response(request: suspend () -> T): Response { return try { @@ -45,7 +44,7 @@ class Response private constructor( val isFailure: Boolean get() = value is Failure - suspend fun handle(onFailure: ((String) -> Any)? = null, onSuccess: ((T) -> Any)? = null) { + suspend fun handle(onFailure: ((String) -> Unit)? = null, onSuccess: ((T) -> Unit)? = null) { if (value is Failure) onFailure?.let { it(getFailureString(value)) } else onSuccess?.let { @Suppress("UNCHECKED_CAST") @@ -86,5 +85,4 @@ class Response private constructor( val code: Int?, val hint: String? ) - } diff --git a/merchant-lib/src/test/java/net/taler/merchantlib/MerchantApiTest.kt b/merchant-lib/src/test/java/net/taler/merchantlib/MerchantApiTest.kt index f9f5e87..992af6f 100644 --- a/merchant-lib/src/test/java/net/taler/merchantlib/MerchantApiTest.kt +++ b/merchant-lib/src/test/java/net/taler/merchantlib/MerchantApiTest.kt @@ -17,7 +17,9 @@ package net.taler.merchantlib import io.ktor.http.HttpStatusCode.Companion.NotFound -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestCoroutineDispatcher +import kotlinx.coroutines.test.runBlockingTest import net.taler.common.Amount import net.taler.common.ContractProduct import net.taler.common.ContractTerms @@ -28,9 +30,10 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test +@ExperimentalCoroutinesApi class MerchantApiTest { - private val api = MerchantApi(httpClient) + private val api = MerchantApi(httpClient, TestCoroutineDispatcher()) private val merchantConfig = MerchantConfig( baseUrl = "http://example.net/", instance = "testInstance", @@ -39,7 +42,7 @@ class MerchantApiTest { private val orderId = "orderIdFoo" @Test - fun testGetConfig() = runBlocking { + fun testGetConfig() = runBlockingTest { httpClient.giveJsonResponse("https://backend.int.taler.net/config") { """ { @@ -54,7 +57,7 @@ class MerchantApiTest { } @Test - fun testPostOrder() = runBlocking { + fun testPostOrder() = runBlockingTest { val product = ContractProduct( productId = "foo", description = "bar", @@ -111,7 +114,7 @@ class MerchantApiTest { } @Test - fun testCheckOrder() = runBlocking { + fun testCheckOrder() = runBlockingTest { val unpaidResponse = CheckPaymentResponse.Unpaid(false, "http://taler.net/foo") httpClient.giveJsonResponse("http://example.net/instances/testInstance/private/orders/$orderId") { """{ @@ -140,7 +143,7 @@ class MerchantApiTest { } @Test - fun testDeleteOrder() = runBlocking { + fun testDeleteOrder() = runBlockingTest { httpClient.giveJsonResponse("http://example.net/instances/testInstance/private/orders/$orderId") { "{}" } @@ -163,7 +166,7 @@ class MerchantApiTest { } @Test - fun testGetOrderHistory() = runBlocking { + fun testGetOrderHistory() = runBlockingTest { httpClient.giveJsonResponse("http://example.net/instances/testInstance/private/orders") { """{ "orders": [ { @@ -213,7 +216,7 @@ class MerchantApiTest { } @Test - fun testGiveRefund() = runBlocking { + fun testGiveRefund() = runBlockingTest { httpClient.giveJsonResponse("http://example.net/instances/testInstance/private/orders/$orderId/refund") { """{ "taler_refund_uri": "taler://refund/foo/bar" @@ -227,5 +230,4 @@ class MerchantApiTest { assertEquals("taler://refund/foo/bar", it.talerRefundUri) } } - } -- cgit v1.2.3