Skip to content

Commit

Permalink
Remove CustomerSession#StripeApiProxy
Browse files Browse the repository at this point in the history
This interface was only used for testing and added complexity to the
logic of `CustomerSession`. Refactor `CustomerSession` to allow for
passing in mock objects to verify interactions.
  • Loading branch information
mshafrir-stripe committed Apr 9, 2019
1 parent b5f5f00 commit 794658a
Show file tree
Hide file tree
Showing 3 changed files with 435 additions and 601 deletions.
219 changes: 59 additions & 160 deletions stripe/src/main/java/com/stripe/android/CustomerSession.java
Expand Up @@ -12,9 +12,6 @@
import android.support.annotation.VisibleForTesting;
import android.support.v4.content.LocalBroadcastManager;

import com.stripe.android.exception.APIConnectionException;
import com.stripe.android.exception.APIException;
import com.stripe.android.exception.InvalidRequestException;
import com.stripe.android.exception.StripeException;
import com.stripe.android.model.Customer;
import com.stripe.android.model.ShippingInformation;
Expand All @@ -25,10 +22,8 @@
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -88,10 +83,8 @@ public class CustomerSession
@NonNull private final Handler mUiThreadHandler;
@NonNull private final Set<String> mProductUsageTokens;
@Nullable private final Calendar mProxyNowCalendar;
@Nullable private final StripeApiProxy mStripeApiProxy;

// A queue of Runnables for doing customer updates
@NonNull private final BlockingQueue<Runnable> mNetworkQueue = new LinkedBlockingQueue<>();
@NonNull private final ThreadPoolExecutor mThreadPoolExecutor;
@NonNull private final StripeApiHandler mApiHandler;

Expand All @@ -102,7 +95,7 @@ public class CustomerSession
* {@link CustomerEphemeralKey EphemeralKeys} as needed
*/
public static void initCustomerSession(@NonNull EphemeralKeyProvider keyProvider) {
initCustomerSession(keyProvider, null, null);
setInstance(new CustomerSession(keyProvider));
}

/**
Expand All @@ -120,6 +113,11 @@ public static CustomerSession getInstance() {
return mInstance;
}

@VisibleForTesting
static void setInstance(@Nullable CustomerSession customerSession) {
mInstance = customerSession;
}

/**
* End the singleton instance of a {@link CustomerSession}.
* Calls to {@link CustomerSession#getInstance()} will throw an {@link IllegalStateException}
Expand All @@ -130,18 +128,10 @@ public static void endCustomerSession() {
clearInstance();
}

@VisibleForTesting
static void initCustomerSession(
@NonNull EphemeralKeyProvider keyProvider,
@Nullable StripeApiProxy stripeApiProxy,
@Nullable Calendar proxyNowCalendar) {
mInstance = new CustomerSession(keyProvider, stripeApiProxy, proxyNowCalendar);
}

@VisibleForTesting
static void clearInstance() {
cancelCallbacks();
mInstance = null;
setInstance(null);
}

/**
Expand All @@ -159,22 +149,27 @@ public static void cancelCallbacks() {
mInstance.mThreadPoolExecutor.shutdownNow();
}

private CustomerSession(
private CustomerSession(@NonNull EphemeralKeyProvider keyProvider) {
this(keyProvider, null, createThreadPoolExecutor(), new StripeApiHandler());
}

@VisibleForTesting
CustomerSession(
@NonNull EphemeralKeyProvider keyProvider,
@Nullable StripeApiProxy stripeApiProxy,
@Nullable Calendar proxyNowCalendar) {
mThreadPoolExecutor = createThreadPoolExecutor();
mUiThreadHandler = createMainThreadHandler();
mStripeApiProxy = stripeApiProxy;
@Nullable Calendar proxyNowCalendar,
@NonNull ThreadPoolExecutor threadPoolExecutor,
@NonNull StripeApiHandler apiHandler) {
mThreadPoolExecutor = threadPoolExecutor;
mProxyNowCalendar = proxyNowCalendar;
mProductUsageTokens = new HashSet<>();
mApiHandler = apiHandler;
mUiThreadHandler = createMainThreadHandler();
mEphemeralKeyManager = new EphemeralKeyManager<>(
keyProvider,
this,
KEY_REFRESH_BUFFER_IN_SECONDS,
proxyNowCalendar,
CustomerEphemeralKey.class);
mApiHandler = new StripeApiHandler();
}

@RestrictTo(RestrictTo.Scope.LIBRARY)
Expand All @@ -193,8 +188,9 @@ public void addProductUsageTokenIfValid(@Nullable String token) {
* customer, either from the cache or from the server
*/
public void retrieveCurrentCustomer(@NonNull CustomerRetrievalListener listener) {
if (canUseCachedCustomer()) {
listener.onCustomerRetrieved(getCachedCustomer());
final Customer cachedCustomer = getCachedCustomer();
if (cachedCustomer != null) {
listener.onCustomerRetrieved(cachedCustomer);
} else {
mCustomer = null;
mCustomerRetrievalListener = listener;
Expand Down Expand Up @@ -445,12 +441,6 @@ public void run() {
}

private void executeRunnable(@NonNull Runnable runnable) {
// In automation, run on the main thread.
if (mStripeApiProxy != null) {
runnable.run();
return;
}

mThreadPoolExecutor.execute(runnable);
}

Expand Down Expand Up @@ -586,13 +576,13 @@ public void handleMessage(@NonNull Message msg) {
}

@NonNull
private ThreadPoolExecutor createThreadPoolExecutor() {
private static ThreadPoolExecutor createThreadPoolExecutor() {
return new ThreadPoolExecutor(
THREAD_POOL_SIZE,
THREAD_POOL_SIZE,
KEEP_ALIVE_TIME,
KEEP_ALIVE_TIME_UNIT,
mNetworkQueue);
new LinkedBlockingQueue<Runnable>());
}

@NonNull
Expand All @@ -606,76 +596,45 @@ private Source addCustomerSourceWithKey(
@NonNull CustomerEphemeralKey key,
@NonNull String sourceId,
@NonNull @Source.SourceType String sourceType) throws StripeException {
if (mStripeApiProxy != null) {
return mStripeApiProxy.addCustomerSourceWithKey(
context,
key.getCustomerId(),
PaymentConfiguration.getInstance().getPublishableKey(),
new ArrayList<>(mProductUsageTokens),
sourceId,
sourceType,
key.getSecret());
} else {
return mApiHandler.addCustomerSource(
context,
key.getCustomerId(),
PaymentConfiguration.getInstance().getPublishableKey(),
new ArrayList<>(mProductUsageTokens),
sourceId,
sourceType,
key.getSecret(),
null);
}
return mApiHandler.addCustomerSource(
context,
key.getCustomerId(),
PaymentConfiguration.getInstance().getPublishableKey(),
new ArrayList<>(mProductUsageTokens),
sourceId,
sourceType,
key.getSecret(),
null);
}

@Nullable
private Source deleteCustomerSourceWithKey(
@NonNull Context context,
@NonNull CustomerEphemeralKey key,
@NonNull String sourceId) throws StripeException {
if (mStripeApiProxy != null) {
return mStripeApiProxy.deleteCustomerSourceWithKey(
context,
key.getCustomerId(),
PaymentConfiguration.getInstance().getPublishableKey(),
new ArrayList<>(mProductUsageTokens),
sourceId,
key.getSecret());
} else {
return mApiHandler.deleteCustomerSource(
context,
key.getCustomerId(),
PaymentConfiguration.getInstance().getPublishableKey(),
new ArrayList<>(mProductUsageTokens),
sourceId,
key.getSecret(),
null);
}
return mApiHandler.deleteCustomerSource(
context,
key.getCustomerId(),
PaymentConfiguration.getInstance().getPublishableKey(),
new ArrayList<>(mProductUsageTokens),
sourceId,
key.getSecret(),
null);
}

@Nullable
private Customer setCustomerShippingInfoWithKey(
@NonNull Context context,
@NonNull CustomerEphemeralKey key,
@NonNull ShippingInformation shippingInformation) throws StripeException {
if (mStripeApiProxy != null) {
return mStripeApiProxy.setCustomerShippingInfoWithKey(
context,
key.getCustomerId(),
PaymentConfiguration.getInstance().getPublishableKey(),
new ArrayList<>(mProductUsageTokens),
shippingInformation,
key.getSecret());
} else {
return mApiHandler.setCustomerShippingInfo(
context,
key.getCustomerId(),
PaymentConfiguration.getInstance().getPublishableKey(),
new ArrayList<>(mProductUsageTokens),
shippingInformation,
key.getSecret(),
null);
}
return mApiHandler.setCustomerShippingInfo(
context,
key.getCustomerId(),
PaymentConfiguration.getInstance().getPublishableKey(),
new ArrayList<>(mProductUsageTokens),
shippingInformation,
key.getSecret(),
null);
}

@Nullable
Expand All @@ -684,26 +643,15 @@ private Customer setCustomerSourceDefaultWithKey(
@NonNull CustomerEphemeralKey key,
@NonNull String sourceId,
@NonNull @Source.SourceType String sourceType) throws StripeException {
if (mStripeApiProxy != null) {
return mStripeApiProxy.setDefaultCustomerSourceWithKey(
context,
key.getCustomerId(),
PaymentConfiguration.getInstance().getPublishableKey(),
new ArrayList<>(mProductUsageTokens),
sourceId,
sourceType,
key.getSecret());
} else {
return mApiHandler.setDefaultCustomerSource(
context,
key.getCustomerId(),
PaymentConfiguration.getInstance().getPublishableKey(),
new ArrayList<>(mProductUsageTokens),
sourceId,
sourceType,
key.getSecret(),
null);
}
return mApiHandler.setDefaultCustomerSource(
context,
key.getCustomerId(),
PaymentConfiguration.getInstance().getPublishableKey(),
new ArrayList<>(mProductUsageTokens),
sourceId,
sourceType,
key.getSecret(),
null);
}

/**
Expand All @@ -718,11 +666,7 @@ private Customer setCustomerSourceDefaultWithKey(
@Nullable
private Customer retrieveCustomerWithKey(@NonNull CustomerEphemeralKey key)
throws StripeException {
if (mStripeApiProxy != null) {
return mStripeApiProxy.retrieveCustomerWithKey(key.getCustomerId(), key.getSecret());
} else {
return mApiHandler.retrieveCustomer(key.getCustomerId(), key.getSecret());
}
return mApiHandler.retrieveCustomer(key.getCustomerId(), key.getSecret());
}

private void sendErrorIntent(@NonNull StripeException exception) {
Expand All @@ -749,49 +693,4 @@ public interface SourceRetrievalListener {
void onError(int errorCode, @Nullable String errorMessage,
@Nullable StripeError stripeError);
}

interface StripeApiProxy {
@Nullable Customer retrieveCustomerWithKey(@NonNull String customerId,
@NonNull String secret)
throws InvalidRequestException, APIConnectionException, APIException;

@Nullable Source addCustomerSourceWithKey(
@Nullable Context context,
@NonNull String customerId,
@NonNull String publicKey,
@NonNull List<String> productUsageTokens,
@NonNull String sourceId,
@NonNull String sourceType,
@NonNull String secret)
throws InvalidRequestException, APIConnectionException, APIException;

@Nullable Source deleteCustomerSourceWithKey(
@Nullable Context context,
@NonNull String customerId,
@NonNull String publicKey,
@NonNull List<String> productUsageTokens,
@NonNull String sourceId,
@NonNull String secret)
throws InvalidRequestException, APIConnectionException, APIException;

@Nullable Customer setDefaultCustomerSourceWithKey(
@Nullable Context context,
@NonNull String customerId,
@NonNull String publicKey,
@NonNull List<String> productUsageTokens,
@NonNull String sourceId,
@NonNull String sourceType,
@NonNull String secret)
throws InvalidRequestException, APIConnectionException, APIException;


@Nullable Customer setCustomerShippingInfoWithKey(
@Nullable Context context,
@NonNull String customerId,
@NonNull String publicKey,
@NonNull List<String> productUsageTokens,
@NonNull ShippingInformation shippingInformation,
@NonNull String secret)
throws InvalidRequestException, APIConnectionException, APIException;
}
}

0 comments on commit 794658a

Please sign in to comment.