killbill-memoizeit

Details

diff --git a/payment/src/test/java/com/ning/billing/payment/core/TestPaymentMethodProcessorRefreshWithDB.java b/payment/src/test/java/com/ning/billing/payment/core/TestPaymentMethodProcessorRefreshWithDB.java
new file mode 100644
index 0000000..d0967a1
--- /dev/null
+++ b/payment/src/test/java/com/ning/billing/payment/core/TestPaymentMethodProcessorRefreshWithDB.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.payment.core;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.payment.PaymentTestSuiteWithEmbeddedDB;
+import com.ning.billing.payment.TestPaymentHelper;
+import com.ning.billing.payment.api.PaymentMethod;
+import com.ning.billing.payment.dao.PaymentMethodModelDao;
+import com.ning.billing.payment.plugin.api.PaymentPluginApi;
+import com.ning.billing.payment.provider.DefaultNoOpPaymentMethodPlugin;
+
+public class TestPaymentMethodProcessorRefreshWithDB extends PaymentTestSuiteWithEmbeddedDB {
+
+    @Test(groups = "slow")
+    public void testRefreshWithNewPaymentMethod() throws Exception {
+
+        final Account account = testHelper.createTestAccount("foo@bar.com", true);
+        Assert.assertEquals(getPluginApi().getPaymentMethods(account.getId(), true, callContext).size(), 1);
+        final UUID existingPMId = account.getPaymentMethodId();
+
+        // Add new payment in plugin directly
+        final UUID newPmId = UUID.randomUUID();
+        getPluginApi().addPaymentMethod(newPmId, null, false, callContext);
+
+        // Verify that the refresh does indeed show 2 PMs
+        final List<PaymentMethod> methods = paymentMethodProcessor.refreshPaymentMethods(TestPaymentHelper.PLUGIN_TEST_NAME, account, internalCallContext);
+        Assert.assertEquals(methods.size(), 2);
+        checkPaymentMethodExistsWithStatus(methods, existingPMId, true);
+        checkPaymentMethodExistsWithStatus(methods, newPmId, true);
+    }
+
+
+    @Test(groups = "slow")
+    public void testRefreshWithDeletedPaymentMethod() throws Exception {
+
+        final Account account = testHelper.createTestAccount("foo@bar.com", true);
+        Assert.assertEquals(getPluginApi().getPaymentMethods(account.getId(), true, callContext).size(), 1);
+        final UUID firstPmId = account.getPaymentMethodId();
+
+        final UUID secondPmId = paymentApi.addPaymentMethod(TestPaymentHelper.PLUGIN_TEST_NAME, account, true, new DefaultNoOpPaymentMethodPlugin(UUID.randomUUID().toString(), false, null), callContext);
+        Assert.assertEquals(getPluginApi().getPaymentMethods(account.getId(), true, callContext).size(), 2);
+        Assert.assertEquals(paymentApi.getPaymentMethods(account, callContext).size(), 2);
+
+        // Remove second PM from plugin
+        getPluginApi().deletePaymentMethod(secondPmId, callContext);
+        Assert.assertEquals(getPluginApi().getPaymentMethods(account.getId(), true, callContext).size(), 1);
+        Assert.assertEquals(paymentApi.getPaymentMethods(account, callContext).size(), 2);
+
+        // Verify that the refresh sees that PM as being deleted now
+        final List<PaymentMethod> methods = paymentMethodProcessor.refreshPaymentMethods(TestPaymentHelper.PLUGIN_TEST_NAME, account, internalCallContext);
+        Assert.assertEquals(methods.size(), 1);
+        checkPaymentMethodExistsWithStatus(methods, firstPmId, true);
+
+        PaymentMethodModelDao deletedPMModel =  paymentDao.getPaymentMethodIncludedDeleted(secondPmId, internalCallContext);
+        Assert.assertNotNull(deletedPMModel);
+        Assert.assertFalse(deletedPMModel.isActive());
+    }
+
+
+    private void checkPaymentMethodExistsWithStatus(final List<PaymentMethod> methods, UUID expectedPaymentMethodId, boolean expectedActive) {
+        PaymentMethod foundPM = null;
+        for (PaymentMethod cur : methods) {
+            if (cur.getId().equals(expectedPaymentMethodId)) {
+                foundPM = cur;
+                break;
+            }
+        }
+        Assert.assertNotNull(foundPM);
+        Assert.assertEquals(foundPM.isActive().booleanValue(), expectedActive);
+    }
+
+
+    private PaymentPluginApi getPluginApi() {
+        final PaymentPluginApi pluginApi = registry.getServiceForName(TestPaymentHelper.PLUGIN_TEST_NAME);
+        Assert.assertNotNull(pluginApi);
+        return pluginApi;
+    }
+}
diff --git a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
index cbda487..6fc0f11 100644
--- a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
+++ b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
@@ -16,14 +16,151 @@
 
 package com.ning.billing.payment.provider;
 
+import java.math.BigDecimal;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.Multimap;
 import com.google.inject.Inject;
+
+import com.ning.billing.payment.api.PaymentMethodPlugin;
+import com.ning.billing.payment.plugin.api.NoOpPaymentPluginApi;
+import com.ning.billing.payment.plugin.api.PaymentInfoPlugin;
+import com.ning.billing.payment.plugin.api.PaymentInfoPlugin.PaymentPluginStatus;
+import com.ning.billing.payment.plugin.api.PaymentMethodInfoPlugin;
 import com.ning.billing.payment.plugin.api.PaymentPluginApi;
+import com.ning.billing.payment.plugin.api.PaymentPluginApiException;
+import com.ning.billing.payment.plugin.api.RefundInfoPlugin;
+import com.ning.billing.payment.plugin.api.RefundInfoPlugin.RefundPluginStatus;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.TenantContext;
 import com.ning.billing.util.clock.Clock;
 
-public class MockPaymentProviderPlugin extends DefaultNoOpPaymentProviderPlugin implements PaymentPluginApi {
+/**
+ * This MockPaymentProviderPlugin only works for a single accounts as we don't specify the accountId
+ * for opeartions such as addPaymentMethod.
+ */
+public class MockPaymentProviderPlugin implements NoOpPaymentPluginApi {
+
+    private static final String PLUGIN_NAME = "__NO_OP__";
+
+    private final AtomicBoolean makeNextInvoiceFailWithError = new AtomicBoolean(false);
+    private final AtomicBoolean makeNextInvoiceFailWithException = new AtomicBoolean(false);
+    private final AtomicBoolean makeAllInvoicesFailWithError = new AtomicBoolean(false);
+
+    private final Map<String, PaymentInfoPlugin> payments = new ConcurrentHashMap<String, PaymentInfoPlugin>();
+    // Note: we can't use HashMultiMap as we care about storing duplicate key/value pairs
+    private final Multimap<String, RefundInfoPlugin> refunds = LinkedListMultimap.<String, RefundInfoPlugin>create();
+    private final Map<String, PaymentMethodInfoPlugin> paymentMethods = new ConcurrentHashMap<String, PaymentMethodInfoPlugin>();
+
+    private final Clock clock;
 
     @Inject
     public MockPaymentProviderPlugin(final Clock clock) {
-        super(clock);
+        this.clock = clock;
+        clear();
+    }
+
+    @Override
+    public void clear() {
+        makeNextInvoiceFailWithException.set(false);
+        makeAllInvoicesFailWithError.set(false);
+        makeNextInvoiceFailWithError.set(false);
+    }
+
+    @Override
+    public void makeNextPaymentFailWithError() {
+        makeNextInvoiceFailWithError.set(true);
+    }
+
+    @Override
+    public void makeNextPaymentFailWithException() {
+        makeNextInvoiceFailWithException.set(true);
+    }
+
+    @Override
+    public void makeAllInvoicesFailWithError(final boolean failure) {
+        makeAllInvoicesFailWithError.set(failure);
+    }
+
+    @Override
+    public String getName() {
+        return PLUGIN_NAME;
+    }
+
+    @Override
+    public PaymentInfoPlugin processPayment(final UUID kbPaymentId, final UUID kbPaymentMethodId, final BigDecimal amount, final CallContext context) throws PaymentPluginApiException {
+        if (makeNextInvoiceFailWithException.getAndSet(false)) {
+            throw new PaymentPluginApiException("", "test error");
+        }
+
+        final PaymentPluginStatus status = (makeAllInvoicesFailWithError.get() || makeNextInvoiceFailWithError.getAndSet(false)) ? PaymentPluginStatus.ERROR : PaymentPluginStatus.PROCESSED;
+        final PaymentInfoPlugin result = new DefaultNoOpPaymentInfoPlugin(amount, clock.getUTCNow(), clock.getUTCNow(), status, null);
+        payments.put(kbPaymentId.toString(), result);
+        return result;
+    }
+
+    @Override
+    public PaymentInfoPlugin getPaymentInfo(final UUID kbPaymentId, final TenantContext context) throws PaymentPluginApiException {
+        final PaymentInfoPlugin payment = payments.get(kbPaymentId.toString());
+        if (payment == null) {
+            throw new PaymentPluginApiException("", "No payment found for payment id " + kbPaymentId.toString());
+        }
+        return payment;
+    }
+
+
+    @Override
+    public void addPaymentMethod(final UUID kbPaymentMethodId, final PaymentMethodPlugin paymentMethodProps, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
+        // both AccountId and externalPaymentMethodId are set to random values
+        final PaymentMethodInfoPlugin realWithID = new DefaultPaymentMethodInfoPlugin(UUID.randomUUID(), kbPaymentMethodId, setDefault, UUID.randomUUID().toString());
+        paymentMethods.put(kbPaymentMethodId.toString(), realWithID);
+    }
+
+    @Override
+    public void deletePaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
+        paymentMethods.remove(kbPaymentMethodId.toString());
+    }
+
+    @Override
+    public void setDefaultPaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
+    }
+
+    @Override
+    public List<PaymentMethodInfoPlugin> getPaymentMethods(final UUID kbAccountId, final boolean refreshFromGateway, final CallContext context) {
+        return ImmutableList.<PaymentMethodInfoPlugin>copyOf(paymentMethods.values());
+    }
+
+    @Override
+    public void resetPaymentMethods(final List<PaymentMethodInfoPlugin> paymentMethods) {
+        paymentMethods.clear();
+    }
+
+    @Override
+    public RefundInfoPlugin processRefund(final UUID kbPaymentId, final BigDecimal refundAmount, final CallContext context) throws PaymentPluginApiException {
+        final PaymentInfoPlugin paymentInfoPlugin = getPaymentInfo(kbPaymentId, context);
+        if (paymentInfoPlugin == null) {
+            throw new PaymentPluginApiException("", String.format("No payment found for payment id %s (plugin %s)", kbPaymentId.toString(), getName()));
+        }
+
+        BigDecimal maxAmountRefundable = paymentInfoPlugin.getAmount();
+        for (final RefundInfoPlugin refund : refunds.get(kbPaymentId.toString())) {
+            maxAmountRefundable = maxAmountRefundable.add(refund.getAmount().negate());
+        }
+        if (maxAmountRefundable.compareTo(refundAmount) < 0) {
+            throw new PaymentPluginApiException("", String.format("Refund amount of %s for payment id %s is bigger than the payment amount %s (plugin %s)",
+                                                                  refundAmount, kbPaymentId.toString(), paymentInfoPlugin.getAmount(), getName()));
+        }
+
+        final DefaultNoOpRefundInfoPlugin refundInfoPlugin = new DefaultNoOpRefundInfoPlugin(refundAmount, clock.getUTCNow(), clock.getUTCNow(), RefundPluginStatus.PROCESSED, null);
+        refunds.put(kbPaymentId.toString(), refundInfoPlugin);
+
+        return refundInfoPlugin;
     }
 }