Skip to content

Commit fb7aa6f

Browse files
committed
Merge branch 'main' into coroutines-convert-BTClient.getConfiguration
# Conflicts: # BraintreeCore/src/main/java/com/braintreepayments/api/core/BraintreeClient.kt # BraintreeCore/src/test/java/com/braintreepayments/api/core/BraintreeClientUnitTest.kt # TestUtils/src/main/java/com/braintreepayments/api/testutils/MockkBraintreeClientBuilder.kt
2 parents c99a29d + 353b093 commit fb7aa6f

File tree

1,423 files changed

+3616
-1812
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,423 files changed

+3616
-1812
lines changed

BraintreeCore/src/androidTest/java/com/braintreepayments/api/core/BraintreeGraphQLClientTest.kt

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import android.content.Context
44
import androidx.test.core.app.ApplicationProvider
55
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
66
import com.braintreepayments.api.testutils.Fixtures
7+
import kotlinx.coroutines.CoroutineDispatcher
8+
import kotlinx.coroutines.CoroutineScope
9+
import kotlinx.coroutines.Dispatchers
10+
import kotlinx.coroutines.launch
711
import org.json.JSONException
812
import org.json.JSONObject
913
import org.junit.Assert.assertFalse
@@ -17,6 +21,8 @@ import javax.net.ssl.SSLException
1721
class BraintreeGraphQLClientTest {
1822

1923
private lateinit var countDownLatch: CountDownLatch
24+
private val mainDispatcher: CoroutineDispatcher = Dispatchers.Main
25+
private val coroutineScope: CoroutineScope = CoroutineScope(mainDispatcher)
2026

2127
@Before
2228
fun setup() {
@@ -29,10 +35,14 @@ class BraintreeGraphQLClientTest {
2935
val context = ApplicationProvider.getApplicationContext<Context>()
3036
val braintreeClient = BraintreeClient(context, Fixtures.TOKENIZATION_KEY)
3137

32-
braintreeClient.sendGraphQLPOST(JSONObject("{}")) { _, httpError ->
33-
// Make sure SSL handshake is successful
34-
assertFalse(httpError is SSLException)
35-
countDownLatch.countDown()
38+
coroutineScope.launch {
39+
try {
40+
braintreeClient.sendGraphQLPOST(JSONObject("{}"))
41+
} catch (e: Exception) {
42+
assertFalse(e is SSLException)
43+
} finally {
44+
countDownLatch.countDown()
45+
}
3646
}
3747

3848
countDownLatch.await()
@@ -44,10 +54,14 @@ class BraintreeGraphQLClientTest {
4454
val context = ApplicationProvider.getApplicationContext<Context>()
4555
val braintreeClient = BraintreeClient(context, Fixtures.PROD_TOKENIZATION_KEY)
4656

47-
braintreeClient.sendGraphQLPOST(JSONObject("{}")) { _, httpError ->
48-
// Make sure SSL handshake is successful
49-
assertFalse(httpError is SSLException)
50-
countDownLatch.countDown()
57+
coroutineScope.launch {
58+
try {
59+
braintreeClient.sendGraphQLPOST(JSONObject("{}"))
60+
} catch (e: Exception) {
61+
assertFalse(e is SSLException)
62+
} finally {
63+
countDownLatch.countDown()
64+
}
5165
}
5266

5367
countDownLatch.await()

BraintreeCore/src/main/java/com/braintreepayments/api/core/ApiClient.kt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,17 @@ class ApiClient(
2222

2323
fun tokenizeGraphQL(tokenizePayload: JSONObject, callback: TokenizeCallback) =
2424
braintreeClient.run {
25-
sendGraphQLPOST(tokenizePayload) { responseBody, httpError ->
26-
parseResponseToJSON(responseBody)?.let { json ->
27-
callback.onResult(json, null)
28-
} ?: httpError?.let { error ->
29-
callback.onResult(null, error)
25+
coroutineScope.launch {
26+
try {
27+
val responseBody = sendGraphQLPOST(tokenizePayload)
28+
parseResponseToJSON(responseBody)?.let { json ->
29+
callback.onResult(json, null)
30+
} ?: callback.onResult(
31+
null,
32+
BraintreeException("Unable to parse GraphQL response.")
33+
)
34+
} catch (e: IOException) {
35+
callback.onResult(null, e)
3036
}
3137
}
3238
}

BraintreeCore/src/main/java/com/braintreepayments/api/core/BraintreeClient.kt

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import kotlinx.coroutines.launch
1414
import org.json.JSONException
1515
import org.json.JSONObject
1616
import java.io.IOException
17+
import kotlin.coroutines.resume
18+
import kotlin.coroutines.resumeWithException
19+
import kotlin.coroutines.suspendCoroutine
1720

1821
/**
1922
* Core Braintree class that handles network requests.
@@ -169,37 +172,39 @@ class BraintreeClient internal constructor(
169172
/**
170173
* @suppress
171174
*/
172-
fun sendGraphQLPOST(json: JSONObject, responseCallback: HttpResponseCallback) {
173-
coroutineScope.launch {
174-
try {
175-
val configuration = getConfiguration()
176-
val response = graphQLClient.post(
177-
data = json.toString(),
178-
configuration = configuration,
179-
authorization = merchantRepository.authorization
180-
)
181-
try {
182-
val query = json.optString(GraphQLConstants.Keys.QUERY)
183-
val queryDiscardHolder = query.replace(Regex("^[^\\(]*"), "")
184-
val finalQuery = query.replace(queryDiscardHolder, "")
185-
val params = AnalyticsEventParams(
186-
startTime = response.timing.startTime,
187-
endTime = response.timing.endTime,
188-
endpoint = finalQuery
189-
)
190-
sendAnalyticsEvent(
191-
eventName = CoreAnalytics.API_REQUEST_LATENCY,
192-
params = params,
193-
sendImmediately = false
194-
)
195-
responseCallback.onResult(response.body, null)
196-
} catch (jsonException: JSONException) {
197-
responseCallback.onResult(null, jsonException)
175+
suspend fun sendGraphQLPOST(json: JSONObject): String {
176+
val configuration = suspendCoroutine { continuation ->
177+
getConfiguration { config, error ->
178+
if (config != null) {
179+
continuation.resume(config)
180+
} else {
181+
continuation.resumeWithException(error ?: Exception("Unknown configuration error"))
198182
}
199-
} catch (e: IOException) {
200-
responseCallback.onResult(null, e)
201183
}
202184
}
185+
186+
val response = graphQLClient.post(
187+
data = json.toString(),
188+
configuration = configuration,
189+
authorization = merchantRepository.authorization
190+
)
191+
192+
val query = json.optString(GraphQLConstants.Keys.QUERY)
193+
val queryDiscardHolder = query.replace(Regex("^[^\\(]*"), "")
194+
val finalQuery = query.replace(queryDiscardHolder, "")
195+
val params = AnalyticsEventParams(
196+
startTime = response.timing.startTime,
197+
endTime = response.timing.endTime,
198+
endpoint = finalQuery
199+
)
200+
201+
sendAnalyticsEvent(
202+
eventName = CoreAnalytics.API_REQUEST_LATENCY,
203+
params = params,
204+
sendImmediately = false
205+
)
206+
207+
return response.body ?: throw IOException("Response body is null")
203208
}
204209

205210
/**

BraintreeCore/src/test/java/com/braintreepayments/api/core/ApiClientUnitTest.kt

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,7 @@ package com.braintreepayments.api.core
33
import com.braintreepayments.api.card.Card
44
import com.braintreepayments.api.testutils.Fixtures
55
import com.braintreepayments.api.testutils.MockkBraintreeClientBuilder
6-
import io.mockk.coEvery
7-
import io.mockk.coVerify
8-
import io.mockk.every
9-
import io.mockk.mockk
10-
import io.mockk.slot
11-
import io.mockk.spyk
12-
import io.mockk.verify
13-
import io.mockk.verifyOrder
6+
import io.mockk.*
147
import kotlinx.coroutines.ExperimentalCoroutinesApi
158
import kotlinx.coroutines.test.StandardTestDispatcher
169
import kotlinx.coroutines.test.TestScope
@@ -34,6 +27,7 @@ class ApiClientUnitTest {
3427

3528
private lateinit var graphQLEnabledConfig: Configuration
3629
private lateinit var graphQLDisabledConfig: Configuration
30+
private lateinit var testScope: TestScope
3731
private val testDispatcher = StandardTestDispatcher()
3832

3933
@Before
@@ -44,6 +38,8 @@ class ApiClientUnitTest {
4438

4539
graphQLEnabledConfig = Configuration.fromJson(Fixtures.CONFIGURATION_WITH_GRAPHQL)
4640
graphQLDisabledConfig = Configuration.fromJson(Fixtures.CONFIGURATION_WITHOUT_ACCESS_TOKEN)
41+
42+
testScope = TestScope(testDispatcher)
4743
}
4844

4945
@Test
@@ -62,7 +58,7 @@ class ApiClientUnitTest {
6258
data = capture(bodySlot),
6359
)
6460
} returns "{}"
65-
val testScope = TestScope(testDispatcher)
61+
6662
val sut = ApiClient(
6763
braintreeClient = braintreeClient,
6864
analyticsParamRepository = analyticsParamRepository,
@@ -89,19 +85,21 @@ class ApiClientUnitTest {
8985
assertEquals("session-id", data.getString("sessionId"))
9086
}
9187

88+
@OptIn(ExperimentalCoroutinesApi::class)
9289
@Test
9390
@Throws(BraintreeException::class, InvalidArgumentException::class, JSONException::class)
94-
fun tokenizeGraphQL_tokenizesCardsWithGraphQL() {
91+
fun tokenizeGraphQL_tokenizesCardsWithGraphQL() = runTest(testDispatcher) {
9592
val braintreeClient = MockkBraintreeClientBuilder()
9693
.configurationSuccess(graphQLEnabledConfig)
9794
.build()
9895

9996
val graphQLBodySlot = slot<JSONObject>()
100-
every { braintreeClient.sendGraphQLPOST(capture(graphQLBodySlot), any()) } returns Unit
97+
coEvery { braintreeClient.sendGraphQLPOST(capture(graphQLBodySlot)) } returns ""
10198

102-
val sut = ApiClient(braintreeClient)
99+
val sut = ApiClient(braintreeClient, analyticsParamRepository, testDispatcher, testScope)
103100
val card = Card()
104101
sut.tokenizeGraphQL(card.buildJSONForGraphQL(), tokenizeCallback)
102+
advanceUntilIdle()
105103

106104
coVerify(inverse = true) {
107105
braintreeClient.sendPOST(
@@ -118,7 +116,7 @@ class ApiClientUnitTest {
118116
.configurationSuccess(graphQLEnabledConfig)
119117
.sendPostSuccessfulResponse("{}")
120118
.build()
121-
val testScope = TestScope(testDispatcher)
119+
122120
val sut = ApiClient(
123121
braintreeClient = braintreeClient,
124122
dispatcher = testDispatcher,
@@ -129,7 +127,7 @@ class ApiClientUnitTest {
129127

130128
advanceUntilIdle()
131129

132-
verify(inverse = true) { braintreeClient.sendGraphQLPOST(any(), any()) }
130+
coVerify(inverse = true) { braintreeClient.sendGraphQLPOST(any()) }
133131
}
134132

135133
@Test
@@ -138,7 +136,7 @@ class ApiClientUnitTest {
138136
val braintreeClient = MockkBraintreeClientBuilder()
139137
.sendPostSuccessfulResponse("{}")
140138
.build()
141-
val testScope = TestScope(testDispatcher)
139+
142140
val sut = ApiClient(
143141
braintreeClient = braintreeClient,
144142
dispatcher = testDispatcher,

0 commit comments

Comments
 (0)