From f8c2b46ee4bd2272a67cf3e0f0b2b4d251cebc24 Mon Sep 17 00:00:00 2001 From: Michael Shafrir Date: Tue, 26 Nov 2019 12:06:30 -0500 Subject: [PATCH] Create Stripe.retrieveSource() for async Source retrieval All other API methods have both synchronous and asynchronous versions. --- .../main/java/com/stripe/android/Stripe.kt | 50 +++++++- .../java/com/stripe/android/StripeTest.java | 111 +++++++++++------- 2 files changed, 116 insertions(+), 45 deletions(-) diff --git a/stripe/src/main/java/com/stripe/android/Stripe.kt b/stripe/src/main/java/com/stripe/android/Stripe.kt index c29fa00a8f7..25089193fcd 100644 --- a/stripe/src/main/java/com/stripe/android/Stripe.kt +++ b/stripe/src/main/java/com/stripe/android/Stripe.kt @@ -570,9 +570,35 @@ class Stripe internal constructor( } /** - * Retrieve an existing [Source] from the Stripe API. Note that this is a - * synchronous method, and cannot be called on the main thread. Doing so will cause your app - * to crash. + * Retrieve a [Source] asynchronously. + * + * See [Retrieve a source](https://stripe.com/docs/api/sources/retrieve). + * `GET /v1/sources/:id` + * + * @param sourceId the [Source.id] field of the desired Source object + * @param clientSecret the [Source.clientSecret] field of the desired Source object + * @param callback a [ApiResultCallback] to receive the result or error + * + * @throws AuthenticationException failure to properly authenticate yourself (check your key) + * @throws InvalidRequestException your request has invalid parameters + * @throws APIConnectionException failure to connect to Stripe's API + * @throws APIException any other type of problem (for instance, a temporary issue with Stripe's servers) + */ + @UiThread + fun retrieveSource( + @Size(min = 1) sourceId: String, + @Size(min = 1) clientSecret: String, + callback: ApiResultCallback + ) { + RetrieveSourceTask( + stripeRepository, sourceId, clientSecret, publishableKey, stripeAccountId, workScope, + callback + ).execute() + } + + /** + * Retrieve an existing [Source] from the Stripe API. Do not call this on the UI thread + * or your app will crash. * * See [Retrieve a source](https://stripe.com/docs/api/sources/retrieve). * `GET /v1/sources/:id` @@ -959,6 +985,24 @@ class Stripe internal constructor( } } + private class RetrieveSourceTask internal constructor( + private val stripeRepository: StripeRepository, + private val sourceId: String, + private val clientSecret: String, + publishableKey: String, + stripeAccount: String?, + workScope: CoroutineScope = CoroutineScope(Dispatchers.IO), + callback: ApiResultCallback + ) : ApiOperation(workScope, callback) { + private val options: ApiRequest.Options = + ApiRequest.Options(publishableKey, stripeAccount) + + @Throws(StripeException::class) + override suspend fun getResult(): Source? { + return stripeRepository.retrieveSource(sourceId, clientSecret, options) + } + } + private class CreatePaymentMethodTask internal constructor( private val stripeRepository: StripeRepository, private val paymentMethodCreateParams: PaymentMethodCreateParams, diff --git a/stripe/src/test/java/com/stripe/android/StripeTest.java b/stripe/src/test/java/com/stripe/android/StripeTest.java index f51995c45bf..ea1222e4748 100644 --- a/stripe/src/test/java/com/stripe/android/StripeTest.java +++ b/stripe/src/test/java/com/stripe/android/StripeTest.java @@ -82,10 +82,12 @@ public class StripeTest { private Context mContext; - @Captor private ArgumentCaptor mStripeRequestArgumentCaptor; - @Mock private FireAndForgetRequestExecutor mFireAndForgetRequestExecutor; - @Mock private ApiResultCallback mApiResultCallback; - @Captor private ArgumentCaptor mTokenArgumentCaptor; + @Captor private ArgumentCaptor stripeRequestArgumentCaptor; + @Mock private FireAndForgetRequestExecutor fireAndForgetRequestExecutor; + @Mock private ApiResultCallback tokenCallback; + @Mock private ApiResultCallback sourceCallback; + @Captor private ArgumentCaptor tokenArgumentCaptor; + @Captor private ArgumentCaptor sourceArgumentCaptor; @Before public void setup() { @@ -139,9 +141,9 @@ public void run() { @Test public void createCardTokenShouldCreateRealToken() { final Stripe stripe = createStripe(MainScope()); - stripe.createCardToken(CARD, mApiResultCallback); - verify(mApiResultCallback).onSuccess(mTokenArgumentCaptor.capture()); - final Token token = mTokenArgumentCaptor.getValue(); + stripe.createCardToken(CARD, tokenCallback); + verify(tokenCallback).onSuccess(tokenArgumentCaptor.capture()); + final Token token = tokenArgumentCaptor.getValue(); final String tokenId = token.getId(); assertTrue(tokenId.startsWith("tok_")); } @@ -252,7 +254,7 @@ public void onError(@NonNull Exception e) { } @Test - public void createSource() { + public void testCreateSource() { createStripe().createSource(CARD_SOURCE_PARAMS, new ApiResultCallback() { @Override @@ -833,40 +835,36 @@ public void createSourceSynchronous_withSofortParams_passesIntegrationTest() } @Test - public void retrieveSourceSynchronous_withValidData_passesIntegrationTest() - throws StripeException { - final Stripe stripe = createStripe(); - Card card = Card.create(VALID_VISA_NO_SPACES, 12, 2050, "123"); - SourceParams params = SourceParams.createCardParams(card); + public void retrieveSourceAsync_withValidData_passesIntegrationTest() throws StripeException { + final Source source = createSource(); - final Source cardSource = stripe.createSourceSynchronous(params); + final Stripe stripe = createStripe(MainScope()); + stripe.retrieveSource(source.getId(), source.getClientSecret(), sourceCallback); + verify(sourceCallback).onSuccess(sourceArgumentCaptor.capture()); - assertNotNull(cardSource); - assertNotNull(cardSource.getId()); - SourceParams threeDParams = SourceParams.createThreeDSecureParams( - 5000L, - "brl", - "example://return", - cardSource.getId()); + final Source capturedSource = sourceArgumentCaptor.getValue(); + assertEquals( + source.getId(), + capturedSource.getId() + ); + } - final Map metamap = new HashMap() {{ - put("dimensions", "three"); - put("type", "beach ball"); - }}; - threeDParams.setMetaData(metamap); - final Source threeDSource = stripe.createSourceSynchronous(threeDParams); - assertNotNull(threeDSource); + @Test + public void retrieveSourceSynchronous_withValidData_passesIntegrationTest() + throws StripeException { + final Source source = createSource(); - final String sourceId = threeDSource.getId(); - final String clientSecret = threeDSource.getClientSecret(); + final String sourceId = source.getId(); + final String clientSecret = source.getClientSecret(); assertNotNull(sourceId); assertNotNull(clientSecret); - final Source retrievedSource = stripe.retrieveSourceSynchronous(sourceId, clientSecret); + final Source retrievedSource = createStripe() + .retrieveSourceSynchronous(sourceId, clientSecret); // We aren't actually updating the source on the server, so the two sources should // be identical. - assertEquals(threeDSource, retrievedSource); + assertEquals(source, retrievedSource); } @Test @@ -1183,7 +1181,7 @@ public void createPaymentMethodSynchronous_withCardAndMetadata() final PaymentMethodCreateParams paymentMethodCreateParams = PaymentMethodCreateParamsFixtures.createWith(metadata); - final Stripe stripe = createStripe(mFireAndForgetRequestExecutor); + final Stripe stripe = createStripe(fireAndForgetRequestExecutor); final PaymentMethod createdPaymentMethod = stripe.createPaymentMethodSynchronous( paymentMethodCreateParams); assertNotNull(createdPaymentMethod); @@ -1193,10 +1191,10 @@ public void createPaymentMethodSynchronous_withCardAndMetadata() assertEquals("4242", createdPaymentMethod.card.last4); assertEquals(metadata, createdPaymentMethod.metadata); - verify(mFireAndForgetRequestExecutor, times(2)) - .executeAsync(mStripeRequestArgumentCaptor.capture()); + verify(fireAndForgetRequestExecutor, times(2)) + .executeAsync(stripeRequestArgumentCaptor.capture()); final List fireAndForgetRequests = - mStripeRequestArgumentCaptor.getAllValues(); + stripeRequestArgumentCaptor.getAllValues(); final StripeRequest analyticsRequest = fireAndForgetRequests.get(1); assertEquals(AnalyticsRequest.HOST, analyticsRequest.getBaseUrl()); assertEquals(createdPaymentMethod.id, @@ -1225,7 +1223,7 @@ public void createPaymentMethodSynchronous_withIdeal() .setBank("ing") .build(), expectedBillingDetails); - final Stripe stripe = createStripe(mFireAndForgetRequestExecutor); + final Stripe stripe = createStripe(fireAndForgetRequestExecutor); final PaymentMethod createdPaymentMethod = stripe.createPaymentMethodSynchronous( paymentMethodCreateParams); assertNotNull(createdPaymentMethod); @@ -1233,10 +1231,10 @@ public void createPaymentMethodSynchronous_withIdeal() assertNull(createdPaymentMethod.card); assertEquals("INGBNL2A", createdPaymentMethod.ideal.bankIdentifierCode); - verify(mFireAndForgetRequestExecutor, times(2)) - .executeAsync(mStripeRequestArgumentCaptor.capture()); + verify(fireAndForgetRequestExecutor, times(2)) + .executeAsync(stripeRequestArgumentCaptor.capture()); final List fireAndForgetRequests = - mStripeRequestArgumentCaptor.getAllValues(); + stripeRequestArgumentCaptor.getAllValues(); final StripeRequest analyticsRequest = fireAndForgetRequests.get(1); assertEquals(AnalyticsRequest.HOST, analyticsRequest.getBaseUrl()); assertEquals(createdPaymentMethod.id, @@ -1280,9 +1278,9 @@ public void createPaymentMethodSynchronous_withFpx() assertEquals("hsbc", createdPaymentMethod.fpx.bank); verify(fireAndForgetRequestExecutor, times(2)) - .executeAsync(mStripeRequestArgumentCaptor.capture()); + .executeAsync(stripeRequestArgumentCaptor.capture()); final List fireAndForgetRequests = - mStripeRequestArgumentCaptor.getAllValues(); + stripeRequestArgumentCaptor.getAllValues(); final StripeRequest analyticsRequest = fireAndForgetRequests.get(1); assertEquals(AnalyticsRequest.HOST, analyticsRequest.getBaseUrl()); assertEquals(createdPaymentMethod.id, @@ -1298,6 +1296,35 @@ public void setAppInfo() { assertEquals(appInfo, Stripe.getAppInfo()); } + @NonNull + private Source createSource() throws StripeException { + final Stripe stripe = createStripe(); + final SourceParams params = SourceParams.createCardParams( + Card.create(VALID_VISA_NO_SPACES, 12, 2050, "123") + ); + + final Source cardSource = stripe.createSourceSynchronous(params); + + assertNotNull(cardSource); + assertNotNull(cardSource.getId()); + SourceParams threeDParams = SourceParams.createThreeDSecureParams( + 5000L, + "brl", + "example://return", + cardSource.getId() + ); + + final Map metamap = new HashMap() {{ + put("dimensions", "three"); + put("type", "beach ball"); + }}; + threeDParams.setMetaData(metamap); + + final Source source = stripe.createSourceSynchronous(threeDParams); + assertNotNull(source); + return source; + } + @NonNull private Stripe createStripe() { return createStripe(NON_LOGGING_PK);