killbill-memoizeit
Changes
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestInvoiceNotifications.java 42(+37 -5)
Details
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index 5a996c0..7f2648f 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -672,6 +672,26 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
final BillingPeriod billingPeriod,
final List<PlanPhasePriceOverride> overrides,
final NextEvent... events) {
+ return createBaseEntitlementWithPriceOverrideAndCheckForCompletion(accountId,
+ bundleExternalKey,
+ productName,
+ productCategory,
+ billingPeriod,
+ overrides,
+ null,
+ PriceListSet.DEFAULT_PRICELIST_NAME,
+ events);
+ }
+
+ protected DefaultEntitlement createBaseEntitlementWithPriceOverrideAndCheckForCompletion(final UUID accountId,
+ final String bundleExternalKey,
+ final String productName,
+ final ProductCategory productCategory,
+ final BillingPeriod billingPeriod,
+ final List<PlanPhasePriceOverride> overrides,
+ final LocalDate billingEffectiveDate,
+ final String priceList,
+ final NextEvent... events) {
if (productCategory == ProductCategory.ADD_ON) {
throw new RuntimeException("Unxepected Call for creating ADD_ON");
}
@@ -680,8 +700,8 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
@Override
public Entitlement apply(@Nullable final Void dontcare) {
try {
- final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final UUID entitlementId = entitlementApi.createBaseEntitlement(accountId, spec, bundleExternalKey, overrides, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
+ final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, billingPeriod, priceList, null);
+ final UUID entitlementId = entitlementApi.createBaseEntitlement(accountId, spec, bundleExternalKey, overrides, null, billingEffectiveDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertNotNull(entitlementId);
return entitlementApi.getEntitlementForId(entitlementId, callContext);
} catch (final EntitlementApiException e) {
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestInvoiceNotifications.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestInvoiceNotifications.java
index 7cbed63..cabc048 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestInvoiceNotifications.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestInvoiceNotifications.java
@@ -70,7 +70,6 @@ public class TestInvoiceNotifications extends TestIntegrationBase {
addDaysAndCheckForCompletion(7, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
}
-
@Test(groups = "slow")
public void testInvoiceNotificationWithFutureSubscriptionEvents() throws Exception {
clock.setDay(new LocalDate(2018, 1, 31));
@@ -79,11 +78,9 @@ public class TestInvoiceNotifications extends TestIntegrationBase {
final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
accountChecker.checkAccount(account.getId(), accountData, callContext);
-
final LocalDate billingDate = new LocalDate(2018, 2, 28);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("pistol-monthly-notrial");
-
busHandler.pushExpectedEvents(NextEvent.BLOCK);
final UUID entitlementId = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleKey", null, null, billingDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
busHandler.assertListenerStatus();
@@ -103,11 +100,46 @@ public class TestInvoiceNotifications extends TestIntegrationBase {
// Move to the notification before the start date => 2018, 3, 21
addDaysAndCheckForCompletion(21, NextEvent.INVOICE_NOTIFICATION);
-
// Move to the change date => 2018, 3, 28
addDaysAndCheckForCompletion(7, NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.NULL_INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
-
}
+ @Test(groups = "slow")
+ public void testInvoiceNotificationInThePast() throws Exception {
+ // We take april as it has 30 days (easier to play with BCD)
+ // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
+ clock.setDay(new LocalDate(2012, 4, 1));
+ final AccountData accountData = getAccountData(1);
+ final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
+ accountChecker.checkAccount(account.getId(), accountData, callContext);
+
+ // Future create the entitlement
+ // Note: we need to use a plan without a trial to verify the fix, because we don't send invoice notifications for $0 invoices
+ // Also, even though we have the 7d dryRunNotificationSchedule configured, the system will not to set a dry run notification in the past (3/26/2012)
+ final DefaultEntitlement bpSubscription = createBaseEntitlementWithPriceOverrideAndCheckForCompletion(account.getId(),
+ "bundleKey",
+ "Pistol",
+ ProductCategory.BASE,
+ BillingPeriod.MONTHLY,
+ null,
+ new LocalDate(2012, 4, 2),
+ "notrial",
+ NextEvent.BLOCK);
+
+ // Move to subscription start date
+ addDaysAndCheckForCompletion(1, NextEvent.CREATE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+
+ // Move to notification date
+ addDaysAndCheckForCompletion(23, NextEvent.INVOICE_NOTIFICATION);
+
+ // Move to next invoice
+ addDaysAndCheckForCompletion(7, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+
+ // Move to notification date
+ addDaysAndCheckForCompletion(24, NextEvent.INVOICE_NOTIFICATION);
+
+ // Move to next invoice
+ addDaysAndCheckForCompletion(7, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ }
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/api/InvoiceApiHelper.java b/invoice/src/main/java/org/killbill/billing/invoice/api/InvoiceApiHelper.java
index 7558dd5..c692f73 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/api/InvoiceApiHelper.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/api/InvoiceApiHelper.java
@@ -39,8 +39,8 @@ import org.killbill.billing.invoice.dao.InvoiceDao;
import org.killbill.billing.invoice.dao.InvoiceItemModelDao;
import org.killbill.billing.invoice.dao.InvoiceModelDao;
import org.killbill.billing.invoice.model.DefaultInvoice;
+import org.killbill.billing.invoice.model.InvoiceItemCatalogBase;
import org.killbill.billing.invoice.model.InvoiceItemFactory;
-import org.killbill.billing.invoice.model.ItemAdjInvoiceItem;
import org.killbill.billing.util.UUIDs;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
@@ -186,16 +186,27 @@ public class InvoiceApiHelper {
// If we pass that stage, it means the validation succeeded so we just need to extract resulting amount and negate the result.
final BigDecimal amountToAdjust = output.get(invoiceItemId).negate();
// Finally, create the adjustment
- return new ItemAdjInvoiceItem(UUIDs.randomUUID(),
- context.getCreatedDate(),
- invoiceItemToBeAdjusted.getInvoiceId(),
- invoiceItemToBeAdjusted.getAccountId(),
- effectiveDate,
- description,
- amountToAdjust,
- currencyForAdjustment,
- invoiceItemToBeAdjusted.getId(),
- itemDetails);
+
+ return new InvoiceItemCatalogBase(UUIDs.randomUUID(),
+ context.getCreatedDate(),
+ invoiceItemToBeAdjusted.getInvoiceId(),
+ invoiceItemToBeAdjusted.getAccountId(),
+ null,
+ null,
+ description,
+ invoiceItemToBeAdjusted.getProductName(),
+ invoiceItemToBeAdjusted.getPlanName(),
+ invoiceItemToBeAdjusted.getPhaseName(),
+ invoiceItemToBeAdjusted.getUsageName(),
+ effectiveDate,
+ effectiveDate,
+ amountToAdjust,
+ null,
+ currencyForAdjustment,
+ invoiceItemToBeAdjusted.getId(),
+ null,
+ itemDetails,
+ InvoiceItemType.ITEM_ADJ);
}
private List<InvoiceItem> fromInvoiceItemModelDao(final Collection<InvoiceItemModelDao> invoiceItemModelDaos) {
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
index e5f8132..5cd89af 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
@@ -1014,8 +1014,10 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
if (dryRunNotificationTime > 0) {
for (final LocalDate notificationDate : callbackDateTimePerSubscriptions.getNotificationsForDryRun().keySet()) {
final DateTime notificationDateTime = internalCallContext.toUTCDateTime(notificationDate);
- final Set<UUID> subscriptionIds = callbackDateTimePerSubscriptions.getNotificationsForDryRun().get(notificationDate);
- nextBillingDatePoster.insertNextBillingDryRunNotificationFromTransaction(entitySqlDaoWrapperFactory, accountId, subscriptionIds, notificationDateTime, notificationDateTime.plusMillis((int) dryRunNotificationTime), internalCallContext);
+ if (notificationDateTime.compareTo(internalCallContext.getCreatedDate()) > 0) {
+ final Set<UUID> subscriptionIds = callbackDateTimePerSubscriptions.getNotificationsForDryRun().get(notificationDate);
+ nextBillingDatePoster.insertNextBillingDryRunNotificationFromTransaction(entitySqlDaoWrapperFactory, accountId, subscriptionIds, notificationDateTime, notificationDateTime.plusMillis((int) dryRunNotificationTime), internalCallContext);
+ }
}
}
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDaoHelper.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDaoHelper.java
index b89497e..5d57bd1 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDaoHelper.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDaoHelper.java
@@ -219,7 +219,8 @@ public class InvoiceDaoHelper {
// Finally, create the adjustment
// Note! The amount is negated here!
return new InvoiceItemModelDao(context.getCreatedDate(), InvoiceItemType.ITEM_ADJ, invoiceItemToBeAdjusted.getInvoiceId(), invoiceItemToBeAdjusted.getAccountId(),
- null, null, null, null, null, null, null, effectiveDate, effectiveDate, amountToAdjust.negate(), null, currencyForAdjustment, invoiceItemToBeAdjusted.getId());
+ null, null, null, invoiceItemToBeAdjusted.getProductName(), invoiceItemToBeAdjusted.getPlanName(), invoiceItemToBeAdjusted.getPhaseName(),
+ invoiceItemToBeAdjusted.getUsageName(), effectiveDate, effectiveDate, amountToAdjust.negate(), null, currencyForAdjustment, invoiceItemToBeAdjusted.getId());
}
public void populateChildren(final InvoiceModelDao invoice, final List<Tag> invoicesTags, final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final InternalTenantContext context) {
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/notification/TestNextBillingDatePoster.java b/invoice/src/test/java/org/killbill/billing/invoice/notification/TestNextBillingDatePoster.java
index b9bf095..ad6b9bf 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/notification/TestNextBillingDatePoster.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/notification/TestNextBillingDatePoster.java
@@ -23,7 +23,6 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
-import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.Account;
@@ -57,22 +56,14 @@ public class TestNextBillingDatePoster extends InvoiceTestSuiteWithEmbeddedDB {
final Account account = invoiceUtil.createAccount(callContext);
final Long accountRecordId = nonEntityDao.retrieveAccountRecordIdFromObject(account.getId(), ObjectType.ACCOUNT, null);
- final DateTime now = clock.getUTCNow();
- final LocalDate nowLocal = internalCallContext.toLocalDate(now);
+ final LocalDate notificationDate = clock.getUTCToday().plusDays(30);
final SubscriptionBase subscription = invoiceUtil.createSubscription();
final UUID subscriptionId = subscription.getId();
- final FutureAccountNotifications futureAccountNotifications = createFutureAccountNotifications(subscriptionId, nowLocal);
-
- // Add 3 seconds to make it more interesting
- clock.addDeltaFromReality(3000);
+ final FutureAccountNotifications futureAccountNotifications = createFutureAccountNotifications(subscriptionId, notificationDate);
invoiceDao.setFutureAccountNotificationsForEmptyInvoice(account.getId(), futureAccountNotifications, internalCallContext);
-
-
- // Add 3 seconds to make it more interesting
- clock.addDeltaFromReality(3000);
invoiceDao.setFutureAccountNotificationsForEmptyInvoice(account.getId(), futureAccountNotifications, internalCallContext);
final NotificationQueue nextBillingQueue = notificationQueueService.getNotificationQueue(DefaultInvoiceService.INVOICE_SERVICE_NAME,
@@ -83,7 +74,7 @@ public class TestNextBillingDatePoster extends InvoiceTestSuiteWithEmbeddedDB {
// We expect only one notification for which effectiveDate matches our original effectiveDate (conversion DateTime -> LocalDate -> DateTime)
final NotificationEventWithMetadata<NextBillingDateNotificationKey> notification = futureNotificationsList.get(0);
- Assert.assertEquals(notification.getEffectiveDate(), internalCallContext.toUTCDateTime(nowLocal));
+ Assert.assertEquals(notification.getEffectiveDate(), internalCallContext.toUTCDateTime(notificationDate));
final Iterable<UUID> uuidKeys = notification.getEvent().getUuidKeys();
Assert.assertFalse(Iterables.isEmpty(uuidKeys));
@@ -97,19 +88,18 @@ public class TestNextBillingDatePoster extends InvoiceTestSuiteWithEmbeddedDB {
final Account account = invoiceUtil.createAccount(callContext);
final Long accountRecordId = nonEntityDao.retrieveAccountRecordIdFromObject(account.getId(), ObjectType.ACCOUNT, null);
- final DateTime now = clock.getUTCNow();
- final LocalDate nowLocal = internalCallContext.toLocalDate(now);
+ final LocalDate notificationDate = clock.getUTCToday().plusDays(30);
final SubscriptionBase subscription1 = invoiceUtil.createSubscription();
final UUID subscriptionId1 = subscription1.getId();
- final FutureAccountNotifications futureAccountNotifications1 = createFutureAccountNotifications(subscriptionId1, nowLocal);
+ final FutureAccountNotifications futureAccountNotifications1 = createFutureAccountNotifications(subscriptionId1, notificationDate);
invoiceDao.setFutureAccountNotificationsForEmptyInvoice(account.getId(), futureAccountNotifications1, internalCallContext);
final SubscriptionBase subscription2 = invoiceUtil.createSubscription();
final UUID subscriptionId2 = subscription2.getId();
- final FutureAccountNotifications futureAccountNotifications2 = createFutureAccountNotifications(subscriptionId2, nowLocal);
+ final FutureAccountNotifications futureAccountNotifications2 = createFutureAccountNotifications(subscriptionId2, notificationDate);
invoiceDao.setFutureAccountNotificationsForEmptyInvoice(account.getId(), futureAccountNotifications2, internalCallContext);
@@ -122,7 +112,7 @@ public class TestNextBillingDatePoster extends InvoiceTestSuiteWithEmbeddedDB {
// We expect only one notification but this time we should see a list with both subscriptionIds.
final NotificationEventWithMetadata<NextBillingDateNotificationKey> notification = futureNotificationsList.get(0);
- Assert.assertEquals(notification.getEffectiveDate(), internalCallContext.toUTCDateTime(nowLocal));
+ Assert.assertEquals(notification.getEffectiveDate(), internalCallContext.toUTCDateTime(notificationDate));
final Iterable<UUID> uuidKeys = notification.getEvent().getUuidKeys();
Assert.assertFalse(Iterables.isEmpty(uuidKeys));
@@ -138,25 +128,22 @@ public class TestNextBillingDatePoster extends InvoiceTestSuiteWithEmbeddedDB {
final Account account = invoiceUtil.createAccount(callContext);
final Long accountRecordId = nonEntityDao.retrieveAccountRecordIdFromObject(account.getId(), ObjectType.ACCOUNT, null);
- final DateTime now = clock.getUTCNow();
- final LocalDate nowLocal = internalCallContext.toLocalDate(now);
+ final LocalDate notificationDate1 = clock.getUTCToday().plusDays(30);
final SubscriptionBase subscription = invoiceUtil.createSubscription();
final UUID subscriptionId = subscription.getId();
- final FutureAccountNotifications futureAccountNotifications1 = createFutureAccountNotifications(subscriptionId, nowLocal);
+ final FutureAccountNotifications futureAccountNotifications1 = createFutureAccountNotifications(subscriptionId, notificationDate1);
// Add 3 seconds to make it more interesting
clock.addDeltaFromReality(3000);
invoiceDao.setFutureAccountNotificationsForEmptyInvoice(account.getId(), futureAccountNotifications1, internalCallContext);
-
clock.addDays(1);
- final DateTime newNow = clock.getUTCNow();
- final LocalDate newNowLocal = internalCallContext.toLocalDate(newNow);
+ final LocalDate notificationDate2 = clock.getUTCToday().plusDays(30);
- final FutureAccountNotifications futureAccountNotifications2 = createFutureAccountNotifications(subscriptionId, newNowLocal);
+ final FutureAccountNotifications futureAccountNotifications2 = createFutureAccountNotifications(subscriptionId, notificationDate2);
invoiceDao.setFutureAccountNotificationsForEmptyInvoice(account.getId(), futureAccountNotifications2, internalCallContext);
@@ -169,7 +156,7 @@ public class TestNextBillingDatePoster extends InvoiceTestSuiteWithEmbeddedDB {
Assert.assertEquals(futureNotificationsList.size(), 2);
final NotificationEventWithMetadata<NextBillingDateNotificationKey> notification1 = futureNotificationsList.get(0);
- Assert.assertEquals(notification1.getEffectiveDate(), internalCallContext.toUTCDateTime(nowLocal));
+ Assert.assertEquals(notification1.getEffectiveDate(), internalCallContext.toUTCDateTime(notificationDate1));
final Iterable<UUID> uuidKeys1 = notification1.getEvent().getUuidKeys();
Assert.assertFalse(Iterables.isEmpty(uuidKeys1));
@@ -179,7 +166,7 @@ public class TestNextBillingDatePoster extends InvoiceTestSuiteWithEmbeddedDB {
final NotificationEventWithMetadata<NextBillingDateNotificationKey> notification2 = futureNotificationsList.get(1);
- Assert.assertEquals(notification2.getEffectiveDate(), internalCallContext.toUTCDateTime(newNowLocal));
+ Assert.assertEquals(notification2.getEffectiveDate(), internalCallContext.toUTCDateTime(notificationDate2));
final Iterable<UUID> uuidKeys2 = notification2.getEvent().getUuidKeys();
Assert.assertFalse(Iterables.isEmpty(uuidKeys2));
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
index e5ef206..a8f886a 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
@@ -45,6 +45,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.IHookCallBack;
import org.testng.IHookable;
+import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
@@ -234,7 +235,8 @@ public class GuicyKillbillTestSuite implements IHookable {
log.info("***************************************************************************************************");
if (!hasFailed && !result.isSuccess()) {
// Ignore if the current test method is flaky
- final boolean isFlakyTest = result.getMethod().getRetryAnalyzer() != null && result.getMethod().getRetryAnalyzer() instanceof FlakyRetryAnalyzer;
+ final ITestNGMethod testNGMethod = result.getMethod();
+ final boolean isFlakyTest = testNGMethod != null && testNGMethod.getRetryAnalyzer() != null && testNGMethod.getRetryAnalyzer() instanceof FlakyRetryAnalyzer;
if (!isFlakyTest) {
hasFailed = true;
}
diff --git a/util/src/test/java/org/killbill/billing/util/broadcast/TestBroadcastService.java b/util/src/test/java/org/killbill/billing/util/broadcast/TestBroadcastService.java
index 8bb02b2..3868a56 100644
--- a/util/src/test/java/org/killbill/billing/util/broadcast/TestBroadcastService.java
+++ b/util/src/test/java/org/killbill/billing/util/broadcast/TestBroadcastService.java
@@ -52,6 +52,10 @@ public class TestBroadcastService extends UtilTestSuiteWithEmbeddedDB {
@AfterMethod(groups = "slow")
public void afterMethod() throws Exception {
+ if (hasFailed()) {
+ return;
+ }
+
((DefaultBroadcastService) broadcastService).stop();
super.afterMethod();
}
diff --git a/util/src/test/java/org/killbill/billing/util/security/shiro/realm/TestKillBillJdbcRealm.java b/util/src/test/java/org/killbill/billing/util/security/shiro/realm/TestKillBillJdbcRealm.java
index 167d3bd..4669ff0 100644
--- a/util/src/test/java/org/killbill/billing/util/security/shiro/realm/TestKillBillJdbcRealm.java
+++ b/util/src/test/java/org/killbill/billing/util/security/shiro/realm/TestKillBillJdbcRealm.java
@@ -62,14 +62,16 @@ public class TestKillBillJdbcRealm extends UtilTestSuiteWithEmbeddedDB {
@AfterMethod(groups = "slow")
public void afterMethod() throws Exception {
+ if (hasFailed()) {
+ return;
+ }
+
super.afterMethod();
ThreadContext.unbindSecurityManager();
-
}
@Test(groups = "slow")
public void testAuthentication() throws SecurityApiException {
-
final String username = "toto";
final String password = "supperCompli43cated";