killbill-uncached

junction: fix two bugs in BlockingCalculator * fix date comparison *

8/27/2012 3:32:31 PM

Details

diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
index 0194e58..3070fd2 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
@@ -28,7 +28,6 @@ import java.util.concurrent.atomic.AtomicLong;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 
-import com.google.inject.Inject;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.BillCycleDay;
 import com.ning.billing.catalog.api.BillingPeriod;
@@ -41,7 +40,8 @@ import com.ning.billing.entitlement.api.billing.BillingModeType;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.junction.api.BlockingApi;
 import com.ning.billing.junction.api.BlockingState;
-import com.ning.billing.junction.api.DefaultBlockingState;
+
+import com.google.inject.Inject;
 
 public class BlockingCalculator {
     private static final AtomicLong globaltotalOrder = new AtomicLong();
@@ -72,6 +72,11 @@ public class BlockingCalculator {
         this.blockingApi = blockingApi;
     }
 
+    /**
+     * Given a set of billing events, add corresponding blocking (overdue) billing events.
+     *
+     * @param billingEvents the original list of billing events to update (without overdue events)
+     */
     public void insertBlockingEvents(final SortedSet<BillingEvent> billingEvents) {
         if (billingEvents.size() <= 0) {
             return;
@@ -102,7 +107,6 @@ public class BlockingCalculator {
         for (final BillingEvent eventToRemove : billingEventsToRemove) {
             billingEvents.remove(eventToRemove);
         }
-
     }
 
     protected SortedSet<BillingEvent> eventsToRemove(final List<DisabledDuration> disabledDuration,
@@ -127,7 +131,9 @@ public class BlockingCalculator {
     protected SortedSet<BillingEvent> createNewEvents(final List<DisabledDuration> disabledDuration, final SortedSet<BillingEvent> billingEvents, final Account account, final Subscription subscription) {
         final SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
         for (final DisabledDuration duration : disabledDuration) {
+            // The first one before the blocked duration
             final BillingEvent precedingInitialEvent = precedingBillingEventForSubscription(duration.getStart(), billingEvents, subscription);
+            // The last one during of before the duration
             final BillingEvent precedingFinalEvent = precedingBillingEventForSubscription(duration.getEnd(), billingEvents, subscription);
 
             if (precedingInitialEvent != null) { // there is a preceding billing event
@@ -163,7 +169,7 @@ public class BlockingCalculator {
         }
 
         for (final BillingEvent event : filteredBillingEvents) {
-            if (event.getEffectiveDate().isAfter(datetime)) { // found it its the previous event
+            if (!event.getEffectiveDate().isBefore(datetime)) { // found it its the previous event
                 return result;
             } else { // still looking
                 result = event;
@@ -237,7 +243,7 @@ public class BlockingCalculator {
                 subs = new ArrayList<Subscription>();
                 result.put(bundleId, subs);
             }
-            if (!result.contains(event.getSubscription())) {
+            if (!result.get(bundleId).contains(event.getSubscription())) {
                 subs.add(event.getSubscription());
             }
         }
@@ -245,14 +251,18 @@ public class BlockingCalculator {
     }
 
 
+    // In ascending order
     protected List<DisabledDuration> createBlockingDurations(final List<BlockingState> overdueBundleEvents) {
         final List<DisabledDuration> result = new ArrayList<BlockingCalculator.DisabledDuration>();
+        // Earliest blocking event
         BlockingState first = null;
 
         for (final BlockingState e : overdueBundleEvents) {
-            if (e.isBlockBilling() && first == null) { // found a transition to disabled
+            if (e.isBlockBilling() && first == null) {
+                // First blocking event of contiguous series of blocking events
                 first = e;
-            } else if (first != null && !e.isBlockBilling()) { // found a transition from disabled
+            } else if (first != null && !e.isBlockBilling()) {
+                // End of the interval
                 result.add(new DisabledDuration(first.getTimestamp(), e.getTimestamp()));
                 first = null;
             }
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
index 705d8ac..466900d 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
@@ -722,4 +722,40 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         assertNotNull(pairs.get(0).getEnd());
         assertEquals(pairs.get(0).getEnd(), now.plusDays(4));
     }
+
+    @Test(groups = "fast")
+    public void testSimpleWithClearBlockingDuration() throws Exception {
+        final UUID ovdId = UUID.randomUUID();
+
+        final BillingEvent trial = createRealEvent(new LocalDate(2012, 5, 1).toDateTimeAtStartOfDay(DateTimeZone.UTC), subscription1, SubscriptionTransitionType.CREATE);
+        final BillingEvent phase = createRealEvent(new LocalDate(2012, 5, 31).toDateTimeAtStartOfDay(DateTimeZone.UTC), subscription1, SubscriptionTransitionType.PHASE);
+        final BillingEvent upgrade = createRealEvent(new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC), subscription1, SubscriptionTransitionType.CHANGE);
+        final SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+        billingEvents.add(trial);
+        billingEvents.add(phase);
+        billingEvents.add(upgrade);
+
+        final List<BlockingState> blockingEvents = new ArrayList<BlockingState>();
+        blockingEvents.add(new DefaultBlockingState(ovdId, DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE, "test", true, false, false, new LocalDate(2012, 7, 5).toDateTimeAtStartOfDay(DateTimeZone.UTC)));
+        blockingEvents.add(new DefaultBlockingState(ovdId, DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE, "test", true, true, true, new LocalDate(2012, 7, 15).toDateTimeAtStartOfDay(DateTimeZone.UTC)));
+        blockingEvents.add(new DefaultBlockingState(ovdId, DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE, "test", true, true, true, new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC)));
+        blockingEvents.add(new DefaultBlockingState(ovdId, CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE, "test", false, false, false, new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC)));
+
+        Mockito.when(blockingApi.getBlockingHistory(bundleId1)).thenReturn(blockingEvents);
+
+        odc.insertBlockingEvents(billingEvents);
+
+        assertEquals(billingEvents.size(), 5);
+        final List<BillingEvent> events = new ArrayList<BillingEvent>(billingEvents);
+        assertEquals(events.get(0).getEffectiveDate(), new LocalDate(2012, 5, 1).toDateTimeAtStartOfDay(DateTimeZone.UTC));
+        assertEquals(events.get(0).getTransitionType(), SubscriptionTransitionType.CREATE);
+        assertEquals(events.get(1).getEffectiveDate(), new LocalDate(2012, 5, 31).toDateTimeAtStartOfDay(DateTimeZone.UTC));
+        assertEquals(events.get(1).getTransitionType(), SubscriptionTransitionType.PHASE);
+        assertEquals(events.get(2).getEffectiveDate(), new LocalDate(2012, 7, 15).toDateTimeAtStartOfDay(DateTimeZone.UTC));
+        assertEquals(events.get(2).getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
+        assertEquals(events.get(3).getEffectiveDate(), new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC));
+        assertEquals(events.get(3).getTransitionType(), SubscriptionTransitionType.END_BILLING_DISABLED);
+        assertEquals(events.get(4).getEffectiveDate(), new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC));
+        assertEquals(events.get(4).getTransitionType(), SubscriptionTransitionType.CHANGE);
+    }
 }