killbill-memoizeit

junction: fix ordering of DefaultBillingEvent * Use custom

8/27/2012 3:29:07 PM

Details

diff --git a/api/src/main/java/com/ning/billing/entitlement/api/SubscriptionTransitionType.java b/api/src/main/java/com/ning/billing/entitlement/api/SubscriptionTransitionType.java
index a788ee0..939b56b 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/SubscriptionTransitionType.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/SubscriptionTransitionType.java
@@ -24,5 +24,9 @@ public enum SubscriptionTransitionType {
     RE_CREATE,
     CANCEL,
     UNCANCEL,
-    PHASE
+    PHASE,
+    // Transition to start of blocked billing overdue state
+    START_BILLING_DISABLED,
+    // Transition to end of blocked billing overdue state
+    END_BILLING_DISABLED
 }
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 6382707..0194e58 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
@@ -195,7 +195,7 @@ public class BlockingCalculator {
         final String description = "";
         final BillingModeType billingModeType = previousEvent.getBillingMode();
         final BillingPeriod billingPeriod = previousEvent.getBillingPeriod();
-        final SubscriptionTransitionType type = SubscriptionTransitionType.CANCEL;
+        final SubscriptionTransitionType type = SubscriptionTransitionType.START_BILLING_DISABLED;
         final Long totalOrdering = globaltotalOrder.getAndIncrement();
         final DateTimeZone tz = previousEvent.getTimeZone();
 
@@ -218,7 +218,7 @@ public class BlockingCalculator {
         final String description = "";
         final BillingModeType billingModeType = previousEvent.getBillingMode();
         final BillingPeriod billingPeriod = previousEvent.getBillingPeriod();
-        final SubscriptionTransitionType type = SubscriptionTransitionType.RE_CREATE;
+        final SubscriptionTransitionType type = SubscriptionTransitionType.END_BILLING_DISABLED;
         final Long totalOrdering = globaltotalOrder.getAndIncrement();
         final DateTimeZone tz = previousEvent.getTimeZone();
 
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEvent.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEvent.java
index a51f874..41eff04 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEvent.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEvent.java
@@ -107,7 +107,6 @@ public class DefaultBillingEvent implements BillingEvent {
         this.timeZone = timeZone;
     }
 
-
     @Override
     public int compareTo(final BillingEvent e1) {
         if (!getSubscription().getId().equals(e1.getSubscription().getId())) { // First order by subscription
@@ -116,7 +115,40 @@ public class DefaultBillingEvent implements BillingEvent {
             if (!getEffectiveDate().equals(e1.getEffectiveDate())) { // Secondly order by date
                 return getEffectiveDate().compareTo(e1.getEffectiveDate());
             } else { // dates and subscriptions are the same
-                return getTotalOrdering().compareTo(e1.getTotalOrdering());
+                // If an entitlement event and an overdue event happen at the exact same time,
+                // we assume we want the entitlement event before the overdue event when entering
+                // the overdue period, and vice-versa when exiting the overdue period
+                if (SubscriptionTransitionType.START_BILLING_DISABLED.equals(getTransitionType())) {
+                    if (SubscriptionTransitionType.END_BILLING_DISABLED.equals(e1.getTransitionType())) {
+                        // Make sure to always have START before END
+                        return -1;
+                    } else {
+                        return 1;
+                    }
+                } else if (SubscriptionTransitionType.START_BILLING_DISABLED.equals(e1.getTransitionType())) {
+                    if (SubscriptionTransitionType.END_BILLING_DISABLED.equals(getTransitionType())) {
+                        // Make sure to always have START before END
+                        return 1;
+                    } else {
+                        return -1;
+                    }
+                } else if (SubscriptionTransitionType.END_BILLING_DISABLED.equals(getTransitionType())) {
+                    if (SubscriptionTransitionType.START_BILLING_DISABLED.equals(e1.getTransitionType())) {
+                        // Make sure to always have START before END
+                        return 1;
+                    } else {
+                        return -1;
+                    }
+                } else if (SubscriptionTransitionType.END_BILLING_DISABLED.equals(e1.getTransitionType())) {
+                    if (SubscriptionTransitionType.START_BILLING_DISABLED.equals(getTransitionType())) {
+                        // Make sure to always have START before END
+                        return -1;
+                    } else {
+                        return 1;
+                    }
+                } else {
+                    return getTotalOrdering().compareTo(e1.getTotalOrdering());
+                }
             }
         }
     }
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 91c478f..705d8ac 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
@@ -27,13 +27,11 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
+import org.joda.time.LocalDate;
 import org.mockito.Mockito;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.BillCycleDay;
 import com.ning.billing.catalog.MockPlan;
@@ -55,14 +53,18 @@ import com.ning.billing.junction.api.DefaultBlockingState;
 import com.ning.billing.junction.dao.BlockingStateDao;
 import com.ning.billing.junction.plumbing.billing.BlockingCalculator.DisabledDuration;
 import com.ning.billing.mock.api.MockBillCycleDay;
-import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 
 public class TestBlockingCalculator extends JunctionTestSuite {
+
     private static final String DISABLED_BUNDLE = "disabled-bundle";
     private static final String CLEAR_BUNDLE = "clear-bundle";
 
@@ -74,10 +76,10 @@ public class TestBlockingCalculator extends JunctionTestSuite {
     private Subscription subscription4;
     private final UUID bundleId1 = UUID.randomUUID();
     private final UUID bundleId2 = UUID.randomUUID();
-    private Clock clock;
+    private ClockMock clock;
     private BlockingCalculator odc;
 
-    @BeforeClass
+    @BeforeClass(groups = "fast")
     public void setUpBeforeClass() throws Exception {
         clock = new ClockMock();
 
@@ -119,7 +121,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
     // S1 --A--[-------]--------------------------
     // S2 --B--[-------]--------------------------
     // S3 ------------------D---------------------
-    @Test
+    @Test(groups = "fast")
     public void testInsertBlockingEvents() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -148,14 +150,14 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         final SortedSet<BillingEvent> s1Events = odc.filter(billingEvents, subscription1);
         final Iterator<BillingEvent> it1 = s1Events.iterator();
         assertEquals(it1.next(), A);
-        assertEquals(it1.next().getTransitionType(), SubscriptionTransitionType.CANCEL);
-        assertEquals(it1.next().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+        assertEquals(it1.next().getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
+        assertEquals(it1.next().getTransitionType(), SubscriptionTransitionType.END_BILLING_DISABLED);
 
         final SortedSet<BillingEvent> s2Events = odc.filter(billingEvents, subscription2);
         final Iterator<BillingEvent> it2 = s2Events.iterator();
         assertEquals(it2.next(), B);
-        assertEquals(it2.next().getTransitionType(), SubscriptionTransitionType.CANCEL);
-        assertEquals(it2.next().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+        assertEquals(it2.next().getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
+        assertEquals(it2.next().getTransitionType(), SubscriptionTransitionType.END_BILLING_DISABLED);
 
         final SortedSet<BillingEvent> s3Events = odc.filter(billingEvents, subscription3);
         final Iterator<BillingEvent> it3 = s3Events.iterator();
@@ -164,7 +166,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
     // Open ended duration with a previous event
     // --X--[----------------------------------
-    @Test
+    @Test(groups = "fast")
     public void testEventsToRemoveOpenPrev() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -180,7 +182,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
     // Open with previous and following events
     // --X--[----Y-----------------------------
-    @Test
+    @Test(groups = "fast")
     public void testEventsToRemoveOpenPrevFollow() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -200,7 +202,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
     // Open with no previous event (only following)
     // -----[----X-----------------------------
-    @Test
+    @Test(groups = "fast")
     public void testEventsToRemoveOpenFollow() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -218,7 +220,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
     // Closed duration with a single previous event
     // --X--[------------]---------------------
-    @Test
+    @Test(groups = "fast")
     public void testEventsToRemoveClosedPrev() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -235,7 +237,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
     // Closed duration with a previous event and in-between event
     // --X--[------Y-----]---------------------
-    @Test
+    @Test(groups = "fast")
     public void testEventsToRemoveClosedPrevBetw() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -255,7 +257,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
     // Closed duration with a previous event and in-between event and following
     // --X--[------Y-----]-------Z-------------
-    @Test
+    @Test(groups = "fast")
     public void testEventsToRemoveClosedPrevBetwNext() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -277,7 +279,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
     // Closed with no previous event but in-between events
     // -----[------Y-----]---------------------
-    @Test
+    @Test(groups = "fast")
     public void testEventsToRemoveClosedBetwn() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -295,7 +297,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
     // Closed with no previous event but in-between events and following
     // -----[------Y-----]-------Z-------------
-    @Test
+    @Test(groups = "fast")
     public void testEventsToRemoveClosedBetweenFollow() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -316,7 +318,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
     // Closed duration with only following
     // -----[------------]-------Z-------------
-    @Test
+    @Test(groups = "fast")
     public void testEventsToRemoveClosedFollow() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -335,7 +337,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
     // Open ended duration with a previous event
     // --X--[----------------------------------
-    @Test
+    @Test(groups = "fast")
     public void testCreateNewEventsOpenPrev() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -349,12 +351,12 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         assertEquals(results.size(), 1);
         assertEquals(results.first().getEffectiveDate(), now);
         assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
-        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
     }
 
     // Open with previous and following events
     // --X--[----Y-----------------------------
-    @Test
+    @Test(groups = "fast")
     public void testCreateNewEventsOpenPrevFollow() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -369,12 +371,12 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         assertEquals(results.size(), 1);
         assertEquals(results.first().getEffectiveDate(), now);
         assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
-        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
     }
 
     // Open with no previous event (only following)
     // -----[----X-----------------------------
-    @Test
+    @Test(groups = "fast")
     public void testCreateNewEventsOpenFollow() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -390,7 +392,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
     // Closed duration with a single previous event
     // --X--[------------]---------------------
-    @Test
+    @Test(groups = "fast")
     public void testCreateNewEventsClosedPrev() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -404,15 +406,15 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         assertEquals(results.size(), 2);
         assertEquals(results.first().getEffectiveDate(), now);
         assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
-        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
         assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
         assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
-        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.END_BILLING_DISABLED);
     }
 
     // Closed duration with a previous event and in-between event
     // --X--[------Y-----]---------------------
-    @Test
+    @Test(groups = "fast")
     public void testCreateNewEventsClosedPrevBetw() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -427,15 +429,15 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         assertEquals(results.size(), 2);
         assertEquals(results.first().getEffectiveDate(), now);
         assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
-        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
         assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
         assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
-        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.END_BILLING_DISABLED);
     }
 
     // Closed duration with a previous event and in-between event and following
     // --X--[------Y-----]-------Z-------------
-    @Test
+    @Test(groups = "fast")
     public void testCreateNewEventsClosedPrevBetwNext() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -451,15 +453,15 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         assertEquals(results.size(), 2);
         assertEquals(results.first().getEffectiveDate(), now);
         assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
-        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
         assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
         assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
-        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.END_BILLING_DISABLED);
     }
 
     // Closed with no previous event but in-between events
     // -----[------Y-----]---------------------
-    @Test
+    @Test(groups = "fast")
     public void testCreateNewEventsClosedBetwn() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -473,12 +475,12 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         assertEquals(results.size(), 1);
         assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
         assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
-        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.END_BILLING_DISABLED);
     }
 
     // Closed with no previous event but in-between events and following
     // -----[------Y-----]-------Z-------------
-    @Test
+    @Test(groups = "fast")
     public void testCreateNewEventsClosedBetweenFollow() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -492,12 +494,12 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         assertEquals(results.size(), 1);
         assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
         assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
-        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.END_BILLING_DISABLED);
     }
 
     // Closed duration with only following
     // -----[------------]-------Z-------------
-    @Test
+    @Test(groups = "fast")
     public void testCreateNewEventsClosedFollow() {
         final DateTime now = clock.getUTCNow();
         final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
@@ -511,7 +513,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         assertEquals(results.size(), 0);
     }
 
-    @Test
+    @Test(groups = "fast")
     public void testPrecedingBillingEventForSubscription() {
         final DateTime now = new DateTime();
 
@@ -533,6 +535,10 @@ public class TestBlockingCalculator extends JunctionTestSuite {
     }
 
     protected BillingEvent createRealEvent(final DateTime effectiveDate, final Subscription subscription) {
+        return createRealEvent(effectiveDate, subscription, SubscriptionTransitionType.CHANGE);
+    }
+
+    protected BillingEvent createRealEvent(final DateTime effectiveDate, final Subscription subscription, final SubscriptionTransitionType type) {
         final Account account = this.account;
         final BillCycleDay billCycleDay = new MockBillCycleDay(1);
         final PlanPhase planPhase = new MockPlanPhase();
@@ -543,7 +549,6 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         final String description = "";
         final BillingModeType billingModeType = BillingModeType.IN_ADVANCE;
         final BillingPeriod billingPeriod = BillingPeriod.MONTHLY;
-        final SubscriptionTransitionType type = SubscriptionTransitionType.CHANGE;
         final Long totalOrdering = 0L;
         final DateTimeZone tz = DateTimeZone.UTC;
 
@@ -553,7 +558,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
                                        description, totalOrdering, type, tz);
     }
 
-    @Test
+    @Test(groups = "fast")
     public void testFilter() {
         final SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
 
@@ -574,7 +579,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         assertEquals(result3.size(), 0);
     }
 
-    @Test
+    @Test(groups = "fast")
     public void testCreateNewDisableEvent() {
         final DateTime now = clock.getUTCNow();
         final BillingEvent event = new MockBillingEvent();
@@ -590,11 +595,11 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         assertEquals(result.getDescription(), "");
         assertEquals(result.getBillingMode(), event.getBillingMode());
         assertEquals(result.getBillingPeriod(), event.getBillingPeriod());
-        assertEquals(result.getTransitionType(), SubscriptionTransitionType.CANCEL);
+        assertEquals(result.getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
         assertEquals(result.getTotalOrdering(), new Long(0));
     }
 
-    @Test
+    @Test(groups = "fast")
     public void testCreateNewReenableEvent() {
         final DateTime now = clock.getUTCNow();
         final BillingEvent event = new MockBillingEvent();
@@ -610,18 +615,19 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         assertEquals(result.getDescription(), "");
         assertEquals(result.getBillingMode(), event.getBillingMode());
         assertEquals(result.getBillingPeriod(), event.getBillingPeriod());
-        assertEquals(result.getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+        assertEquals(result.getTransitionType(), SubscriptionTransitionType.END_BILLING_DISABLED);
         assertEquals(result.getTotalOrdering(), new Long(0));
     }
 
     private class MockBillingEvent extends DefaultBillingEvent {
+
         public MockBillingEvent() {
             super(account, subscription1, clock.getUTCNow(), null, null, BigDecimal.ZERO, BigDecimal.TEN, Currency.USD, BillingPeriod.ANNUAL,
                   new MockBillCycleDay(4), BillingModeType.IN_ADVANCE, "", 3L, SubscriptionTransitionType.CREATE, DateTimeZone.UTC);
         }
     }
 
-    @Test
+    @Test(groups = "fast")
     public void testCreateBundleSubscriptionMap() {
         final SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
         events.add(createBillingEvent(subscription1));
@@ -645,7 +651,7 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         return result;
     }
 
-    @Test
+    @Test(groups = "fast")
     public void testCreateDisablePairs() {
         List<BlockingState> blockingEvents;
         final UUID ovdId = UUID.randomUUID();
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultBillingEvent.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
index b760d0b..8d93050 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
@@ -16,13 +16,14 @@
 
 package com.ning.billing.junction.plumbing.billing;
 
-import javax.annotation.Nullable;
 import java.math.BigDecimal;
 import java.util.Iterator;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.UUID;
 
+import javax.annotation.Nullable;
+
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.mockito.Mockito;
@@ -46,13 +47,57 @@ import com.ning.billing.junction.JunctionTestSuite;
 import com.ning.billing.mock.api.MockBillCycleDay;
 
 public class TestDefaultBillingEvent extends JunctionTestSuite {
-    public static final UUID ID_ZERO = new UUID(0L, 0L);
-    public static final UUID ID_ONE = new UUID(0L, 1L);
-    public static final UUID ID_TWO = new UUID(0L, 2L);
+
+    private static final UUID ID_ZERO = new UUID(0L, 0L);
+    private static final UUID ID_ONE = new UUID(0L, 1L);
+    private static final UUID ID_TWO = new UUID(0L, 2L);
 
     @Test(groups = "fast")
-    public void testEventOrderingSubscription() {
+    public void testEntitlementEventsHappeningAtTheSameTimeAsOverdueEvents() throws Exception {
+        final BillingEvent event0 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-31T00:02:04.000Z"), SubscriptionTransitionType.START_BILLING_DISABLED);
+        final BillingEvent event1 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-31T00:02:04.000Z"), SubscriptionTransitionType.CREATE);
+        final BillingEvent event2 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-31T00:02:05.000Z"), SubscriptionTransitionType.CHANGE);
+        final BillingEvent event3 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-31T00:02:05.000Z"), SubscriptionTransitionType.END_BILLING_DISABLED);
+
+        final SortedSet<BillingEvent> set = new TreeSet<BillingEvent>();
+        set.add(event0);
+        set.add(event1);
+        set.add(event2);
+        set.add(event3);
+
+        final Iterator<BillingEvent> it = set.iterator();
+
+        Assert.assertEquals(event1, it.next());
+        Assert.assertEquals(event0, it.next());
+        Assert.assertEquals(event3, it.next());
+        Assert.assertEquals(event2, it.next());
+    }
 
+    @Test(groups = "fast")
+    public void testEdgeCaseAllEventsHappenAtTheSameTime() throws Exception {
+        final BillingEvent event0 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-31T00:02:04.000Z"), SubscriptionTransitionType.START_BILLING_DISABLED);
+        final BillingEvent event1 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-31T00:02:04.000Z"), SubscriptionTransitionType.CREATE, 1);
+        final BillingEvent event2 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-31T00:02:04.000Z"), SubscriptionTransitionType.CHANGE, 2);
+        // Note the time delta here. Having a blocking duration of zero and events at the same time won't work as the backing tree set does local
+        // comparisons (and not global), making the END_BILLING_DISABLED start the first one in the set
+        final BillingEvent event3 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-31T00:02:05.000Z"), SubscriptionTransitionType.END_BILLING_DISABLED);
+
+        final SortedSet<BillingEvent> set = new TreeSet<BillingEvent>();
+        set.add(event0);
+        set.add(event1);
+        set.add(event2);
+        set.add(event3);
+
+        final Iterator<BillingEvent> it = set.iterator();
+
+        Assert.assertEquals(event1, it.next());
+        Assert.assertEquals(event2, it.next());
+        Assert.assertEquals(event0, it.next());
+        Assert.assertEquals(event3, it.next());
+    }
+
+    @Test(groups = "fast")
+    public void testEventOrderingSubscription() {
         final BillingEvent event0 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-31T00:02:04.000Z"), SubscriptionTransitionType.CREATE);
         final BillingEvent event1 = createEvent(subscription(ID_ONE), new DateTime("2012-01-31T00:02:04.000Z"), SubscriptionTransitionType.CREATE);
         final BillingEvent event2 = createEvent(subscription(ID_TWO), new DateTime("2012-01-31T00:02:04.000Z"), SubscriptionTransitionType.CREATE);