Skip to content

Commit

Permalink
invoice: add test to reproduce NPE after fixed item adjustment
Browse files Browse the repository at this point in the history
See https://groups.google.com/forum/#!msg/killbilling-users/skvadaKDVXI/vSIBb7G_AgAJ.

Signed-off-by: Pierre-Alexandre Meyer <pierre@mouraf.org>
  • Loading branch information
pierre committed Jan 2, 2018
1 parent 46dcb08 commit f62fb60
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 16 deletions.
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
* Copyright 2014-2017 Groupon, Inc
* Copyright 2014-2017 The Billing Project, LLC
* Copyright 2014-2018 Groupon, Inc
* Copyright 2014-2018 The Billing Project, LLC
*
* The Billing Project 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
Expand Down Expand Up @@ -78,7 +78,6 @@
import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.config.definition.InvoiceConfig;
Expand Down Expand Up @@ -199,6 +198,12 @@ public TestInvoiceHelper(final InvoiceGenerator generator, final IDBI dbi,
}

public UUID generateRegularInvoice(final Account account, final LocalDate targetDate, final CallContext callContext) throws Exception {
final BigDecimal fixedPrice = null;
final BigDecimal recurringPrice = BigDecimal.ONE;
return generateRegularInvoice(account, fixedPrice, recurringPrice, targetDate, callContext);
}

public UUID generateRegularInvoice(final Account account, final BigDecimal fixedPrice, final BigDecimal recurringPrice, final LocalDate targetDate, final CallContext callContext) throws Exception {
final SubscriptionBase subscription = Mockito.mock(SubscriptionBase.class);
Mockito.when(subscription.getId()).thenReturn(UUID.randomUUID());
Mockito.when(subscription.getBundleId()).thenReturn(new UUID(0L, 0L));
Expand All @@ -207,27 +212,21 @@ public UUID generateRegularInvoice(final Account account, final LocalDate target
final PlanPhase planPhase = MockPlanPhase.create1USDMonthlyEvergreen();
final DateTime effectiveDate = new DateTime().minusDays(1);
final Currency currency = Currency.USD;
final BigDecimal fixedPrice = null;
events.add(createMockBillingEvent(account, subscription, effectiveDate, plan, planPhase,
fixedPrice, BigDecimal.ONE, currency, BillingPeriod.MONTHLY, 1,
fixedPrice, recurringPrice, currency, BillingPeriod.MONTHLY, 1,
BillingMode.IN_ADVANCE, "", 1L, SubscriptionBaseTransitionType.CREATE));

Mockito.when(billingApi.getBillingEventsForAccountAndUpdateAccountBCD(Mockito.<UUID>any(), Mockito.<DryRunArguments>any(), Mockito.<InternalCallContext>any())).thenReturn(events);

final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi,
invoiceDao, internalCallContextFactory, invoiceNotifier, invoicePluginDispatcher, locker, busService.getBus(),
notificationQueueService, invoiceConfig, clock, parkedAccountsManager);
final InternalCallContext context = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);

Invoice invoice = dispatcher.processAccountFromNotificationOrBusEvent(account.getId(), targetDate, new DryRunFutureDateArguments(), internalCallContext);
Invoice invoice = generateInvoice(account.getId(), targetDate, new DryRunFutureDateArguments(), context);
Assert.assertNotNull(invoice);

final InternalCallContext context = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);

List<InvoiceModelDao> invoices = invoiceDao.getInvoicesByAccount(context);
Assert.assertEquals(invoices.size(), 0);

invoice = dispatcher.processAccountFromNotificationOrBusEvent(account.getId(), targetDate, null, context);
invoice = generateInvoice(account.getId(), targetDate, null, context);
Assert.assertNotNull(invoice);

invoices = invoiceDao.getInvoicesByAccount(context);
Expand All @@ -236,6 +235,15 @@ public UUID generateRegularInvoice(final Account account, final LocalDate target
return invoice.getId();
}

public Invoice generateInvoice(final UUID accountId, @Nullable final LocalDate targetDate, @Nullable final DryRunArguments dryRunArguments, final InternalCallContext internalCallContext) throws InvoiceApiException {
final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi,
invoiceDao, internalCallContextFactory, invoiceNotifier, invoicePluginDispatcher, locker, busService.getBus(),
notificationQueueService, invoiceConfig, clock, parkedAccountsManager);

return dispatcher.processAccountFromNotificationOrBusEvent(accountId, targetDate, dryRunArguments, internalCallContext);
}

public SubscriptionBase createSubscription() throws SubscriptionBaseApiException {
final UUID uuid = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
Expand Down
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
* Copyright 2014-2016 Groupon, Inc
* Copyright 2014-2016 The Billing Project, LLC
* Copyright 2014-2018 Groupon, Inc
* Copyright 2014-2018 The Billing Project, LLC
*
* The Billing Project 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
Expand Down Expand Up @@ -31,6 +31,7 @@
import org.killbill.billing.callcontext.DefaultCallContext;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.invoice.InvoiceTestSuiteWithEmbeddedDB;
import org.killbill.billing.invoice.TestInvoiceHelper.DryRunFutureDateArguments;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceApiException;
import org.killbill.billing.invoice.api.InvoiceItem;
Expand Down Expand Up @@ -237,7 +238,22 @@ public void testAdjustFullInvoiceItem() throws Exception {
}

@Test(groups = "slow")
public void testAdjustPartialInvoiceItem() throws Exception {
public void testAdjustPartialRecurringInvoiceItem() throws Exception {
testAdjustPartialInvoiceItem(true);
}

@Test(groups = "slow", description = "https://github.com/killbill/killbill/pull/831")
public void testAdjustPartialFixedInvoiceItem() throws Exception {
testAdjustPartialInvoiceItem(false);
}

private void testAdjustPartialInvoiceItem(final boolean recurring) throws Exception {
final Account account = invoiceUtil.createAccount(callContext);
final UUID accountId = account.getId();
final BigDecimal fixedPrice = recurring ? null : BigDecimal.ONE;
final BigDecimal recurringPrice = !recurring ? null : BigDecimal.ONE;
final UUID invoiceId = invoiceUtil.generateRegularInvoice(account, fixedPrice, recurringPrice, null, callContext);

final InvoiceItem invoiceItem = invoiceUserApi.getInvoice(invoiceId, callContext).getInvoiceItems().get(0);
// Verify we picked a non zero item
Assert.assertEquals(invoiceItem.getAmount().compareTo(BigDecimal.ZERO), 1);
Expand Down Expand Up @@ -269,6 +285,10 @@ public void testAdjustPartialInvoiceItem() throws Exception {
// Verify the adjusted account balance
final BigDecimal adjustedAccountBalance = invoiceUserApi.getAccountBalance(accountId, callContext);
Assert.assertEquals(adjustedAccountBalance, adjustedInvoiceBalance);

// Verify future invoice generation
final Invoice invoice = invoiceUtil.generateInvoice(account.getId(), clock.getUTCToday().plusMonths(1), new DryRunFutureDateArguments(), internalCallContext);
Assert.assertNotNull(invoice);
}

@Test(groups = "slow")
Expand Down

1 comment on commit f62fb60

@sbrossie
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Please sign in to comment.