Skip to content

Commit

Permalink
Create Stripe.retrieveSource() for async Source retrieval (#1885)
Browse files Browse the repository at this point in the history
All other API methods have both synchronous and asynchronous
versions.
  • Loading branch information
mshafrir-stripe authored Nov 27, 2019
1 parent a9c85ab commit 5c39264
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 45 deletions.
50 changes: 47 additions & 3 deletions stripe/src/main/java/com/stripe/android/Stripe.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<Source>
) {
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`
Expand Down Expand Up @@ -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<Source>
) : ApiOperation<Source>(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,
Expand Down
111 changes: 69 additions & 42 deletions stripe/src/test/java/com/stripe/android/StripeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@ public class StripeTest {

private Context mContext;

@Captor private ArgumentCaptor<StripeRequest> mStripeRequestArgumentCaptor;
@Mock private FireAndForgetRequestExecutor mFireAndForgetRequestExecutor;
@Mock private ApiResultCallback<Token> mApiResultCallback;
@Captor private ArgumentCaptor<Token> mTokenArgumentCaptor;
@Captor private ArgumentCaptor<StripeRequest> stripeRequestArgumentCaptor;
@Mock private FireAndForgetRequestExecutor fireAndForgetRequestExecutor;
@Mock private ApiResultCallback<Token> tokenCallback;
@Mock private ApiResultCallback<Source> sourceCallback;
@Captor private ArgumentCaptor<Token> tokenArgumentCaptor;
@Captor private ArgumentCaptor<Source> sourceArgumentCaptor;

@Before
public void setup() {
Expand Down Expand Up @@ -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_"));
}
Expand Down Expand Up @@ -252,7 +254,7 @@ public void onError(@NonNull Exception e) {
}

@Test
public void createSource() {
public void testCreateSource() {
createStripe().createSource(CARD_SOURCE_PARAMS,
new ApiResultCallback<Source>() {
@Override
Expand Down Expand Up @@ -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<String, String> metamap = new HashMap<String, String>() {{
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
Expand Down Expand Up @@ -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);
Expand All @@ -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<StripeRequest> fireAndForgetRequests =
mStripeRequestArgumentCaptor.getAllValues();
stripeRequestArgumentCaptor.getAllValues();
final StripeRequest analyticsRequest = fireAndForgetRequests.get(1);
assertEquals(AnalyticsRequest.HOST, analyticsRequest.getBaseUrl());
assertEquals(createdPaymentMethod.id,
Expand Down Expand Up @@ -1225,18 +1223,18 @@ 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);
assertEquals(expectedBillingDetails, createdPaymentMethod.billingDetails);
assertNull(createdPaymentMethod.card);
assertEquals("INGBNL2A", createdPaymentMethod.ideal.bankIdentifierCode);

verify(mFireAndForgetRequestExecutor, times(2))
.executeAsync(mStripeRequestArgumentCaptor.capture());
verify(fireAndForgetRequestExecutor, times(2))
.executeAsync(stripeRequestArgumentCaptor.capture());
final List<StripeRequest> fireAndForgetRequests =
mStripeRequestArgumentCaptor.getAllValues();
stripeRequestArgumentCaptor.getAllValues();
final StripeRequest analyticsRequest = fireAndForgetRequests.get(1);
assertEquals(AnalyticsRequest.HOST, analyticsRequest.getBaseUrl());
assertEquals(createdPaymentMethod.id,
Expand Down Expand Up @@ -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<StripeRequest> fireAndForgetRequests =
mStripeRequestArgumentCaptor.getAllValues();
stripeRequestArgumentCaptor.getAllValues();
final StripeRequest analyticsRequest = fireAndForgetRequests.get(1);
assertEquals(AnalyticsRequest.HOST, analyticsRequest.getBaseUrl());
assertEquals(createdPaymentMethod.id,
Expand All @@ -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<String, String> metamap = new HashMap<String, String>() {{
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);
Expand Down

0 comments on commit 5c39264

Please sign in to comment.