com.fitpay.android.TestActions.java Source code

Java tutorial

Introduction

Here is the source code for com.fitpay.android.TestActions.java

Source

package com.fitpay.android;

import com.fitpay.android.api.ApiManager;
import com.fitpay.android.api.callbacks.ResultProvidingCallback;
import com.fitpay.android.api.enums.DeviceTypes;
import com.fitpay.android.api.models.Transaction;
import com.fitpay.android.api.models.apdu.ApduPackage;
import com.fitpay.android.api.models.card.Address;
import com.fitpay.android.api.models.card.CreditCard;
import com.fitpay.android.api.models.card.Reason;
import com.fitpay.android.api.models.card.VerificationMethod;
import com.fitpay.android.api.models.collection.Collections;
import com.fitpay.android.api.models.device.Device;
import com.fitpay.android.api.models.device.PaymentDevice;
import com.fitpay.android.api.models.security.OAuthToken;
import com.fitpay.android.api.models.user.LoginIdentity;
import com.fitpay.android.api.models.user.User;
import com.fitpay.android.api.models.user.UserCreateRequest;
import com.fitpay.android.paymentdevice.impl.mock.SecureElementDataProvider;
import com.fitpay.android.utils.FPLog;
import com.fitpay.android.utils.SecurityProvider;
import com.fitpay.android.utils.TimestampUtils;
import com.fitpay.android.utils.ValidationException;
import com.google.gson.Gson;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;

import java.security.Security;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import rx.Scheduler;
import rx.android.plugins.RxAndroidPlugins;
import rx.android.plugins.RxAndroidSchedulersHook;
import rx.plugins.RxJavaHooks;
import rx.schedulers.Schedulers;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;

public class TestActions {

    protected final int TIMEOUT = 30;

    protected String userName = null;
    protected String pin = null;
    protected LoginIdentity loginIdentity = null;

    protected User user;

    @BeforeClass
    public static void init() {
        FPLog.clean(); //in tests only one log impl should be used
        FPLog.addLogImpl(new FPLog.ILog() {
            @Override
            public void d(String tag, String text) {
                System.out.println(tag + " DEBUG (" + Thread.currentThread().getName() + "): " + text);
            }

            @Override
            public void i(String tag, String text) {
                System.out.println(tag + " INFO(" + Thread.currentThread().getName() + "): " + text);
            }

            @Override
            public void w(String tag, String text) {
                System.out.println(tag + " WARN(" + Thread.currentThread().getName() + "): " + text);
            }

            @Override
            public void e(String tag, Throwable throwable) {
                System.out.println(tag + " ERROR (" + Thread.currentThread().getName() + "): " + tag);

                if (throwable != null) {
                    throwable.printStackTrace();
                }
            }

            @Override
            public int logLevel() {
                return FPLog.DEBUG;
            }
        });
        FPLog.setShowHTTPLogs(false);

        SecurityProvider.getInstance().setProvider(new BouncyCastleProvider());
        ApiManager.init(TestConstants.getConfig());

        RxAndroidPlugins.getInstance().reset();
        RxAndroidPlugins.getInstance().registerSchedulersHook(new RxAndroidSchedulersHook() {
            @Override
            public Scheduler getMainThreadScheduler() {
                return Schedulers.immediate();
            }
        });

        RxJavaHooks.setOnIOScheduler(scheduler -> Schedulers.immediate());
        RxJavaHooks.setOnComputationScheduler(scheduler -> Schedulers.immediate());
        RxJavaHooks.setOnNewThreadScheduler(scheduler -> Schedulers.immediate());
    }

    @Before
    public void testActionsSetup() throws Exception {
        userName = TestUtils.getRandomLengthString(5, 10) + "@" + TestUtils.getRandomLengthString(5, 10) + "."
                + TestUtils.getRandomLengthString(4, 10);
        pin = TestUtils.getRandomLengthNumber(4, 4);

        this.user = createUser(getNewTestUser(userName, pin));
        assertNotNull(this.user);

        loginIdentity = getTestLoginIdentity(userName, pin);
        doLogin(loginIdentity);

        this.user = getUser();
        assertNotNull(user);
    }

    @After
    public void deleteUser() throws Exception {
        if (null != this.user) {
            final CountDownLatch latch = new CountDownLatch(1);
            ResultProvidingCallback<Void> callback = new ResultProvidingCallback<>(latch);
            this.user.deleteUser(callback);
            latch.await(TIMEOUT, TimeUnit.SECONDS);
        }
    }

    protected User createUser(UserCreateRequest user) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<User> callback = new ResultProvidingCallback<>(latch);
        ApiManager.getInstance().createUser(user, callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        return callback.getResult();
    }

    protected boolean doLogin(LoginIdentity loginIdentity) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<OAuthToken> callback = new ResultProvidingCallback<>(latch);
        ApiManager.getInstance().loginUser(loginIdentity, callback);
        boolean completed = latch.await(TIMEOUT, TimeUnit.SECONDS);
        assertTrue("login did not complete successfully", completed);
        assertEquals("login error code. (message: " + callback.getErrorMessage() + ")", -1,
                callback.getErrorCode());
        return completed;
    }

    protected User getUser() throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);

        ResultProvidingCallback<User> callback = new ResultProvidingCallback<>(latch);

        ApiManager.getInstance().getUser(callback);

        latch.await(TIMEOUT, TimeUnit.SECONDS);
        User user = callback.getResult();
        Assert.assertNotNull(user);
        return user;
    }

    protected LoginIdentity getTestLoginIdentity(String userName, String pin) throws ValidationException {

        LoginIdentity loginIdentity = new LoginIdentity.Builder().setUsername(userName).setPassword(pin).build();
        return loginIdentity;

    }

    protected UserCreateRequest getNewTestUser(String userName, String pin) throws ValidationException {
        return new UserCreateRequest.Builder().email(userName).pin(pin).build();
    }

    protected CreditCard getTestCreditCard(String pan) {
        String cardName = "TEST CARD";
        int expYear = 2018;
        int expMonth = 10;
        String city = "Boulder";
        String state = "CO";
        String postalCode = "80302";
        String countryCode = "US";
        String street1 = "1035 Pearl St";
        String cvv = "133";

        Address address = new Address();
        address.setCity(city);
        address.setState(state);
        address.setPostalCode(postalCode);
        address.setCountryCode(countryCode);
        address.setStreet1(street1);

        CreditCard creditCard = new CreditCard.Builder().setCVV(cvv).setPAN(pan).setExpDate(expYear, expMonth)
                .setAddress(address).setName(cardName).build();
        return creditCard;
    }

    public Device getTestDevice() {
        return getTestDevice(true);
    }

    public Device getTestDevice(boolean paymentDevice) {

        String manufacturerName = "X111";
        String deviceName = "TEST_DEVICE";
        String firmwareRevision = "111.111";
        String hardwareRevision = "1.1.1";
        String modelNumber = "AB111";
        String serialNumber = "1111AB";
        String softwareRevision = "1.1.1";
        String systemId = "0x111AA";
        String oSName = "A1111";
        String licenseKey = "aaaaaa-1111-1111-1111-111111111111";
        String bdAddress = "bbbbbb-1111-1111-1111-111111111111";
        long pairingTs = System.currentTimeMillis();

        Device.Builder builder = new Device.Builder().setDeviceType(DeviceTypes.ACTIVITY_TRACKER)
                .setManufacturerName(manufacturerName).setDeviceName(deviceName)
                .setFirmwareRevision(firmwareRevision).setHardwareRevision(hardwareRevision)
                .setModelNumber(modelNumber).setSerialNumber(serialNumber).setSoftwareRevision(softwareRevision)
                .setSystemId(systemId).setOSName(oSName).setLicenseKey(licenseKey).setBdAddress(bdAddress)
                .setPairingTs(pairingTs);

        if (paymentDevice) {
            builder = builder
                    .setSecureElement(new PaymentDevice.SecureElement(SecureElementDataProvider.generateCasd(),
                            SecureElementDataProvider.generateRandomSecureElementId()));
        }

        return builder.build();

    }

    public Device getPoorlyDefinedDevice() {

        String deviceName = "TEST_DEVICE";
        String firmwareRevision = "111.111";
        String hardwareRevision = "1.1.1";
        String modelNumber = "AB111";
        String serialNumber = "1111AB";
        String softwareRevision = "1.1.1";
        String systemId = "0x111AA";
        String oSName = "A1111";
        String licenseKey = "aaaaaa-1111-1111-1111-111111111111";
        String bdAddress = "bbbbbb-1111-1111-1111-111111111111";
        long pairingTs = System.currentTimeMillis();
        String stringTimestamp = TimestampUtils.getISO8601StringForTime(pairingTs);
        String secureElementId = "cccccc-1111-1111-1111-1111111111";
        Device newDevice = new Device.Builder().setDeviceName(deviceName).build();

        return newDevice;

    }

    public Device getPoorlyDeviceTestSmartStrapDevice() {

        String manufacturerName = "X111";
        String deviceName = "TEST_DEVICE";
        String firmwareRevision = "111.111";
        String hardwareRevision = "1.1.1";
        String modelNumber = "AB111";
        String serialNumber = "1111AB";
        String softwareRevision = "1.1.1";
        String systemId = "0x111AA";
        String oSName = "A1111";
        String licenseKey = "aaaaaa-1111-1111-1111-111111111111";
        String bdAddress = "bbbbbb-1111-1111-1111-111111111111";
        long pairingTs = System.currentTimeMillis();
        String stringTimestamp = TimestampUtils.getISO8601StringForTime(pairingTs);
        String secureElementId = "cccccc-1111-1111-1111-1111111111";
        Device newDevice = new Device.Builder().setDeviceType(DeviceTypes.SMART_STRAP).setDeviceName(deviceName)
                .build();

        return newDevice;

    }

    protected Device createDevice(User user, Device device) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<Device> callback = new ResultProvidingCallback<>(latch);
        user.createDevice(device, callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);

        return callback.getResult();
    }

    protected CreditCard createCreditCard(User user, CreditCard creditCard) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<CreditCard> callback = new ResultProvidingCallback<>(latch);
        user.createCreditCard(creditCard, callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        return callback.getResult();
    }

    protected CreditCard getCreditCard(CreditCard creditCard) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<CreditCard> callback = new ResultProvidingCallback<>(latch);
        creditCard.self(callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        assertEquals("get credit card had error code.  (message: " + callback.getErrorMessage() + ")", -1,
                callback.getErrorCode());
        return callback.getResult();
    }

    protected Collections.CreditCardCollection getCreditCards(User user) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<Collections.CreditCardCollection> callback = new ResultProvidingCallback<>(latch);
        user.getCreditCards(10, 0, callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        assertEquals("get credit cards had error code.  (message: " + callback.getErrorMessage() + ")", -1,
                callback.getErrorCode());
        return callback.getResult();
    }

    protected CreditCard acceptTerms(CreditCard creditCard) throws Exception {
        final CountDownLatch latch = new CountDownLatch(2);
        ResultProvidingCallback<CreditCard> callback = new ResultProvidingCallback<>(latch);
        creditCard.acceptTerms(callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);

        CreditCard acceptedCard = callback.getResult();

        if (acceptedCard == null) {
            return null;
        }

        TestConstants.waitSomeActionsOnServer();

        //getSelf
        ResultProvidingCallback<CreditCard> callbackSelf = new ResultProvidingCallback<>(latch);
        acceptedCard.self(callbackSelf);
        latch.await(TIMEOUT, TimeUnit.SECONDS);

        return callbackSelf.getResult();
    }

    protected CreditCard declineTerms(CreditCard creditCard) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<CreditCard> callback = new ResultProvidingCallback<>(latch);
        creditCard.declineTerms(callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        return callback.getResult();
    }

    protected CreditCard deactivateCard(CreditCard creditCard, Reason reason) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<CreditCard> callback = new ResultProvidingCallback<>(latch);
        creditCard.deactivate(reason, callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        return callback.getResult();
    }

    protected CreditCard reactivateCard(CreditCard creditCard, Reason reason) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<CreditCard> callback = new ResultProvidingCallback<>(latch);
        creditCard.reactivate(reason, callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        return callback.getResult();
    }

    protected void makeDefaultCard(CreditCard creditCard) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<Void> callback = new ResultProvidingCallback<>(latch);
        creditCard.makeDefault(callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        assertEquals("make default error code", -1, callback.getErrorCode());
    }

    protected void deleteCard(CreditCard creditCard) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<Void> callback = new ResultProvidingCallback<>(latch);
        creditCard.deleteCard(callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        assertEquals("delete error code", -1, callback.getErrorCode());
    }

    protected VerificationMethod selectVerificationMethod(VerificationMethod method) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<VerificationMethod> callback = new ResultProvidingCallback<>(latch);
        method.select(callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        return callback.getResult();
    }

    protected VerificationMethod verifyVerificationMethod(VerificationMethod method, String verificationCode)
            throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<VerificationMethod> callback = new ResultProvidingCallback<>(latch);
        method.verify(verificationCode, callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        return callback.getResult();
    }

    protected Collections.TransactionCollection getCardTransactions(CreditCard card) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<Collections.TransactionCollection> callback = new ResultProvidingCallback<>(latch);
        card.getTransactions(10, 0, callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        assertEquals("get device transactions error code.  (message: " + callback.getErrorMessage() + ")", -1,
                callback.getErrorCode());
        return callback.getResult();
    }

    protected Transaction getTransaction(Transaction transaction) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<Transaction> callback = new ResultProvidingCallback<>(latch);
        transaction.self(callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        assertEquals("get device transaction error code.  (message: " + callback.getErrorMessage() + ")", -1,
                callback.getErrorCode());
        return callback.getResult();
    }

    protected Collections.DeviceCollection getDevices(User user) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<Collections.DeviceCollection> callback = new ResultProvidingCallback<>(latch);
        user.getDevices(10, 0, callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        assertEquals("get devices error code.  (message: " + callback.getErrorMessage() + ")", -1,
                callback.getErrorCode());
        return callback.getResult();
    }

    protected Collections.CommitsCollection getCommits(Device device, String lastCommitId) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<Collections.CommitsCollection> callback = new ResultProvidingCallback<>(latch);
        device.getCommits(lastCommitId, callback);
        latch.await(TIMEOUT, TimeUnit.SECONDS);
        assertEquals("get commits error code.  (message: " + callback.getErrorMessage() + ")", -1,
                callback.getErrorCode());
        return callback.getResult();
    }

    protected Collections.CommitsCollection getAllCommits(Device device, String lastCommitId) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        ResultProvidingCallback<Collections.CommitsCollection> callback = new ResultProvidingCallback<>(latch);
        device.getAllCommits(lastCommitId, callback);
        latch.await(TIMEOUT * 3, TimeUnit.SECONDS);
        assertEquals("get commits error code.  (message: " + callback.getErrorMessage() + ")", -1,
                callback.getErrorCode());
        return callback.getResult();
    }

    protected ApduPackage getTestApduPackage() {

        String apduJson = "{  \n" + "   \"seIdType\":\"iccid\",\n"
                + "   \"targetDeviceType\":\"fitpay.gandd.model.Device\",\n"
                + "   \"targetDeviceId\":\"72425c1e-3a17-4e1a-b0a4-a41ffcd00a5a\",\n"
                + "   \"packageId\":\"baff08fb-0b73-5019-8877-7c490a43dc64\",\n"
                + "   \"seId\":\"333274689f09352405792e9493356ac880c44444442\",\n"
                + "   \"targetAid\":\"8050200008CF0AFB2A88611AD51C\",\n" + "   \"commandApdus\":[  \n"
                + "      {  \n" + "         \"commandId\":\"5f2acf6f-536d-4444-9cf4-7c83fdf394bf\",\n"
                + "         \"groupId\":0,\n" + "         \"sequence\":0,\n"
                + "         \"command\":\"00E01234567890ABCDEF\",\n" + "         \"type\":\"CREATE FILE\"\n"
                + "      },\n" + "      {  \n"
                + "         \"commandId\":\"00df5f39-7627-447d-9380-46d8574e0643\",\n" + "         \"groupId\":1,\n"
                + "         \"sequence\":1,\n" + "         \"command\":\"8050200008CF0AFB2A88611AD51C\",\n"
                + "         \"type\":\"UNKNOWN\"\n" + "      },\n" + "      {  \n"
                + "         \"commandId\":\"9c719928-8bb0-459c-b7c0-2bc48ec53f3c\",\n" + "         \"groupId\":1,\n"
                + "         \"sequence\":2,\n"
                + "         \"command\":\"84820300106BBC29E6A224522E83A9B26FD456111500\",\n"
                + "         \"type\":\"UNKNOWN\"\n" + "      },\n" + "      {  \n"
                + "         \"commandId\":\"b148bea5-6d98-4c83-8a20-575b4edd7a42\",\n" + "         \"groupId\":1,\n"
                + "         \"sequence\":3,\n"
                + "         \"command\":\"8800E01234567890ABCDEF84820300106BBC29E6A224522E83A9B26FD456111500\",\n"
                + "         \"type\":\"UNKNOWN\"\n" + "      },\n" + "      {  \n"
                + "         \"commandId\":\"905fc5ab-4b15-4704-889b-2c5ffcfb2d68\",\n" + "         \"groupId\":2,\n"
                + "         \"sequence\":4,\n"
                + "         \"command\":\"84F2200210F25397DCFB728E25FBEE52E748A116A800\",\n"
                + "         \"type\":\"UNKNOWN\"\n" + "      },\n" + "      {  \n"
                + "         \"commandId\":\"8e87ff12-dfc2-472a-bbf1-5f2e891e864c\",\n" + "         \"groupId\":3,\n"
                + "         \"sequence\":5,\n"
                + "         \"command\":\"84F2200210F25397DCFB728E25FBEE52E748A116A800\",\n"
                + "         \"type\":\"UNKNOWN\"\n" + "      }\n" + "   ],\n"
                + "   \"validUntil\":\"2020-12-11T21:22:58.691Z\",\n"
                + "   \"apduPackageUrl\":\"http://localhost:9103/transportservice/v1/apdupackages/baff08fb-0b73-5019-8877-7c490a43dc64\"\n"
                + "}";

        Gson gson = new Gson();
        ApduPackage apduPackage = gson.fromJson(apduJson, ApduPackage.class);
        return apduPackage;

    }

    protected ApduPackage getFailingTestApduPackage() {

        String apduJson = "{  \n" + "   \"seIdType\":\"iccid\",\n"
                + "   \"targetDeviceType\":\"fitpay.gandd.model.Device\",\n"
                + "   \"targetDeviceId\":\"72425c1e-3a17-4e1a-b0a4-a41ffcd00a5a\",\n"
                + "   \"packageId\":\"baff08fb-0b73-5019-8877-7c490a43dc64\",\n"
                + "   \"seId\":\"333274689f09352405792e9493356ac880c44444442\",\n"
                + "   \"targetAid\":\"8050200008CF0AFB2A88611AD51C\",\n" + "   \"commandApdus\":[  \n"
                + "      {  \n" + "         \"commandId\":\"5f2acf6f-536d-4444-9cf4-7c83fdf394bf\",\n"
                + "         \"groupId\":0,\n" + "         \"sequence\":0,\n"
                + "         \"command\":\"00E01234567890ABCDEF\",\n" + "         \"type\":\"CREATE FILE\"\n"
                + "      },\n" + "      {  \n"
                + "         \"commandId\":\"00df5f39-7627-447d-9380-46d8574e0643\",\n" + "         \"groupId\":1,\n"
                + "         \"sequence\":1,\n" + "         \"command\":\"8050200008CF0AFB2A88611AD51C\",\n"
                + "         \"type\":\"UNKNOWN\"\n" + "      },\n" + "      {  \n"
                + "         \"commandId\":\"9c719928-8bb0-459c-b7c0-2bc48ec53f3c\",\n" + "         \"groupId\":1,\n"
                + "         \"sequence\":2,\n" + "         \"command\":\"999900\",\n"
                + "         \"type\":\"UNKNOWN\"\n" + "      },\n" + "      {  \n"
                + "         \"commandId\":\"b148bea5-6d98-4c83-8a20-575b4edd7a42\",\n" + "         \"groupId\":1,\n"
                + "         \"sequence\":3,\n"
                + "         \"command\":\"9800E01234567890ABCDEF84820300106BBC29E6A224522E83A9B26FD456111500\",\n"
                + "         \"type\":\"UNKNOWN\"\n" + "      },\n" + "      {  \n"
                + "         \"commandId\":\"905fc5ab-4b15-4704-889b-2c5ffcfb2d68\",\n" + "         \"groupId\":2,\n"
                + "         \"sequence\":4,\n"
                + "         \"command\":\"84F2200210F25397DCFB728E25FBEE52E748A116A800\",\n"
                + "         \"type\":\"UNKNOWN\"\n" + "      },\n" + "      {  \n"
                + "         \"commandId\":\"8e87ff12-dfc2-472a-bbf1-5f2e891e864c\",\n" + "         \"groupId\":3,\n"
                + "         \"sequence\":5,\n"
                + "         \"command\":\"84F2200210F25397DCFB728E25FBEE52E748A116A800\",\n"
                + "         \"type\":\"UNKNOWN\"\n" + "      }\n" + "   ],\n"
                + "   \"validUntil\":\"2020-12-11T21:22:58.691Z\",\n"
                + "   \"apduPackageUrl\":\"http://localhost:9103/transportservice/v1/apdupackages/baff08fb-0b73-5019-8877-7c490a43dc64\"\n"
                + "}";

        Gson gson = new Gson();
        ApduPackage apduPackage = gson.fromJson(apduJson, ApduPackage.class);
        return apduPackage;

    }

    protected CreditCard waitForActivation(CreditCard card) throws Exception {
        assertNotNull("no card to wait for activation on", card);

        CreditCard retrievedCard = card;
        for (int x = 0; x < 30; x++) {
            retrievedCard = getCreditCard(retrievedCard);
            if ("ACTIVE".equals(retrievedCard.getState())) {
                break;
            }

            Thread.sleep(1000);
        }

        assertEquals("card never transitioned to ACTIVE state", "ACTIVE", retrievedCard.getState());
        return retrievedCard;
    }

}