killbill-memoizeit
entitlement: simplify ordering building logic of SubscriptionEvent Signed-off-by: …
5/1/2017 2:09:34 AM
Changes
entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java 105(+93 -12)
entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java 142(+5 -137)
Details
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java
index 0c1c5b7..6648e03 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -19,6 +19,7 @@ package org.killbill.billing.entitlement.api;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -42,6 +43,7 @@ import org.killbill.billing.entitlement.block.BlockingChecker.BlockingAggregator
import org.killbill.billing.entitlement.block.DefaultBlockingChecker.DefaultBlockingAggregator;
import org.killbill.billing.junction.DefaultBlockingState;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
@@ -53,13 +55,13 @@ import com.google.common.collect.Sets;
// Given an event stream (across one or multiple entitlements), insert the blocking events at the right place
public class BlockingStateOrdering extends EntitlementOrderingBase {
- private static final BlockingStateOrdering INSTANCE = new BlockingStateOrdering();
+ @VisibleForTesting
+ static final BlockingStateOrdering INSTANCE = new BlockingStateOrdering();
private BlockingStateOrdering() {}
public static void insertSorted(final Iterable<Entitlement> entitlements, final InternalTenantContext internalTenantContext, final LinkedList<SubscriptionEvent> inputAndOutputResult) {
INSTANCE.computeEvents(entitlements, internalTenantContext, inputAndOutputResult);
-
}
private void computeEvents(final Iterable<Entitlement> entitlements, final InternalTenantContext internalTenantContext, final LinkedList<SubscriptionEvent> inputAndOutputResult) {
@@ -71,6 +73,14 @@ public class BlockingStateOrdering extends EntitlementOrderingBase {
blockingStates.addAll(((DefaultEntitlement) entitlement).getEventsStream().getBlockingStates());
}
+ computeEvents(new LinkedList<UUID>(allEntitlementUUIDs), blockingStates, internalTenantContext, inputAndOutputResult);
+ }
+
+ @VisibleForTesting
+ void computeEvents(final LinkedList<UUID> allEntitlementUUIDs, final Collection<BlockingState> blockingStates, final InternalTenantContext internalTenantContext, final LinkedList<SubscriptionEvent> inputAndOutputResult) {
+ // Make sure the ordering is stable
+ Collections.sort(allEntitlementUUIDs);
+
final SupportForOlderVersionThan_0_17_X backwardCompatibleContext = new SupportForOlderVersionThan_0_17_X(inputAndOutputResult, blockingStates);
// Trust the incoming ordering here: blocking states were sorted using ProxyBlockingStateDao#sortedCopy
@@ -107,12 +117,7 @@ public class BlockingStateOrdering extends EntitlementOrderingBase {
shouldContinue = false;
break;
case 0:
- // In case of exact same date, we want to make sure that a START_ENTITLEMENT event gets correctly populated when the STOP_BILLING is also on the same date
- if (currentBlockingState.getStateName().equals(DefaultEntitlementApi.ENT_STATE_START) && cur.getSubscriptionEventType() != SubscriptionEventType.STOP_BILLING) {
- shouldContinue = false;
- } else {
- shouldContinue = true;
- }
+ shouldContinue = compareBlockingStateWithNextSubscriptionEvent(currentBlockingState, cur) > 0;
break;
case 1:
shouldContinue = true;
@@ -169,9 +174,75 @@ public class BlockingStateOrdering extends EntitlementOrderingBase {
outputNewEvents.add(toSubscriptionEvent(prevNext[0], prevNext[1], targetEntitlementId, currentBlockingState, t, internalTenantContext));
}
}
+
return index;
}
+ private int compareBlockingStateWithNextSubscriptionEvent(final BlockingState blockingState, final SubscriptionEvent next) {
+ final String serviceName = blockingState.getService();
+
+ // For consistency, make sure entitlement-service and billing-service events always happen in a
+ // deterministic order (e.g. after other services for STOP events and before for START events)
+ if ((DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME.equals(serviceName) ||
+ BILLING_SERVICE_NAME.equals(serviceName) ||
+ ENT_BILLING_SERVICE_NAME.equals(serviceName)) &&
+ !(DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME.equals(next.getServiceName()) ||
+ BILLING_SERVICE_NAME.equals(next.getServiceName()) ||
+ ENT_BILLING_SERVICE_NAME.equals(next.getServiceName()))) {
+ // first is an entitlement-service or billing-service event, but not second
+ if (blockingState.isBlockBilling() || blockingState.isBlockEntitlement()) {
+ // PAUSE_ and STOP_ events go last
+ return 1;
+ } else {
+ return -1;
+ }
+ } else if ((DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME.equals(next.getServiceName()) ||
+ BILLING_SERVICE_NAME.equals(next.getServiceName()) ||
+ ENT_BILLING_SERVICE_NAME.equals(next.getServiceName())) &&
+ !(DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME.equals(serviceName) ||
+ BILLING_SERVICE_NAME.equals(serviceName) ||
+ ENT_BILLING_SERVICE_NAME.equals(serviceName))) {
+ // second is an entitlement-service or billing-service event, but not first
+ if (next.getSubscriptionEventType().equals(SubscriptionEventType.START_ENTITLEMENT) ||
+ next.getSubscriptionEventType().equals(SubscriptionEventType.START_BILLING) ||
+ next.getSubscriptionEventType().equals(SubscriptionEventType.RESUME_ENTITLEMENT) ||
+ next.getSubscriptionEventType().equals(SubscriptionEventType.RESUME_BILLING) ||
+ next.getSubscriptionEventType().equals(SubscriptionEventType.PHASE) ||
+ next.getSubscriptionEventType().equals(SubscriptionEventType.CHANGE)) {
+ return 1;
+ } else if (next.getSubscriptionEventType().equals(SubscriptionEventType.PAUSE_ENTITLEMENT) ||
+ next.getSubscriptionEventType().equals(SubscriptionEventType.PAUSE_BILLING) ||
+ next.getSubscriptionEventType().equals(SubscriptionEventType.STOP_ENTITLEMENT) ||
+ next.getSubscriptionEventType().equals(SubscriptionEventType.STOP_BILLING)) {
+ return -1;
+ } else {
+ // Default behavior
+ return 1;
+ }
+ } else if (isStartEntitlement(blockingState)) {
+ // START_ENTITLEMENT is always first
+ return -1;
+ } else if (next.getSubscriptionEventType().equals(SubscriptionEventType.START_ENTITLEMENT)) {
+ // START_ENTITLEMENT is always first
+ return 1;
+ } else if (next.getSubscriptionEventType().equals(SubscriptionEventType.STOP_BILLING)) {
+ // STOP_BILLING is always last
+ return -1;
+ } else if (next.getSubscriptionEventType().equals(SubscriptionEventType.START_BILLING)) {
+ // START_BILLING is first after START_ENTITLEMENT
+ return 1;
+ } else if (isStopEntitlement(blockingState)) {
+ // STOP_ENTITLEMENT is last after STOP_BILLING
+ return 1;
+ } else if (next.getSubscriptionEventType().equals(SubscriptionEventType.STOP_ENTITLEMENT)) {
+ // STOP_ENTITLEMENT is last after STOP_BILLING
+ return -1;
+ } else {
+ // Trust the current ordering
+ return 1;
+ }
+ }
+
// Extract prev and next events in the stream events for that particular target subscription from the insertionEvent
private SubscriptionEvent[] findPrevNext(final List<SubscriptionEvent> events, final UUID targetEntitlementId, final SubscriptionEvent insertionEvent) {
// Find prev/next event for the same entitlement
@@ -390,11 +461,11 @@ public class BlockingStateOrdering extends EntitlementOrderingBase {
bs.getEffectiveDate());
final List<SubscriptionEventType> result = new ArrayList<SubscriptionEventType>(4);
- if (fixedBlockingState.getStateName().equals(DefaultEntitlementApi.ENT_STATE_START)) {
+ if (isStartEntitlement(fixedBlockingState)) {
isEntitlementStarted = true;
result.add(SubscriptionEventType.START_ENTITLEMENT);
return result;
- } else if (fixedBlockingState.getStateName().equals(DefaultEntitlementApi.ENT_STATE_CANCELLED)) {
+ } else if (isStopEntitlement(fixedBlockingState)) {
isEntitlementStopped = true;
result.add(SubscriptionEventType.STOP_ENTITLEMENT);
return result;
@@ -450,6 +521,16 @@ public class BlockingStateOrdering extends EntitlementOrderingBase {
}
}
+ private static boolean isStartEntitlement(final BlockingState blockingState) {
+ return DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME.equals(blockingState.getService()) &&
+ DefaultEntitlementApi.ENT_STATE_START.equals(blockingState.getStateName());
+ }
+
+ private static boolean isStopEntitlement(final BlockingState blockingState) {
+ return DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME.equals(blockingState.getService()) &&
+ DefaultEntitlementApi.ENT_STATE_CANCELLED.equals(blockingState.getStateName());
+ }
+
//
// The logic to add the missing START_ENTITLEMENT for older subscriptions is contained in this class. When we want/need to drop backward compatibility we can
// simply drop this class and where it is called.
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java
index 9283363..96b3d26 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -17,7 +17,6 @@
package org.killbill.billing.entitlement.api;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
@@ -25,7 +24,6 @@ import java.util.List;
import java.util.Map;
import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.entitlement.DefaultEntitlementService;
import org.killbill.billing.subscription.api.SubscriptionBase;
import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
import org.killbill.billing.subscription.api.user.SubscriptionBaseTransition;
@@ -42,8 +40,7 @@ import com.google.common.collect.ImmutableList;
//
public class SubscriptionEventOrdering extends EntitlementOrderingBase {
- @VisibleForTesting
- static final SubscriptionEventOrdering INSTANCE = new SubscriptionEventOrdering();
+ private static final SubscriptionEventOrdering INSTANCE = new SubscriptionEventOrdering();
private SubscriptionEventOrdering() {}
@@ -63,7 +60,6 @@ public class SubscriptionEventOrdering extends EntitlementOrderingBase {
BlockingStateOrdering.insertSorted(entitlements, internalTenantContext, result);
// Final cleanups
- reOrderSubscriptionEventsOnSameDateByType(result);
removeOverlappingSubscriptionEvents(result);
return result;
@@ -146,7 +142,8 @@ public class SubscriptionEventOrdering extends EntitlementOrderingBase {
result.add(index, event);
}
- private SubscriptionEvent toSubscriptionEvent(final SubscriptionBaseTransition in, final SubscriptionEventType eventType, final InternalTenantContext internalTenantContext) {
+ @VisibleForTesting
+ static SubscriptionEvent toSubscriptionEvent(final SubscriptionBaseTransition in, final SubscriptionEventType eventType, final InternalTenantContext internalTenantContext) {
return new DefaultSubscriptionEvent(in.getId(),
in.getSubscriptionId(),
in.getEffectiveTransitionTime(),
@@ -169,47 +166,6 @@ public class SubscriptionEventOrdering extends EntitlementOrderingBase {
internalTenantContext);
}
- //
- // All events have been inserted and should be at the right place, except that we want to ensure that events for a given subscription,
- // and for a given time are ordered by SubscriptionEventType.
- //
- // All this seems a little over complicated, and one wonders why we don't just shove all events and call Collections.sort on the list prior
- // to return:
- // - One explanation is that we don't know the events in advance and each time the new events to be inserted are computed from the current state
- // of the stream, which requires ordering all along
- // - A careful reader will notice that the algorithm is N^2, -- so that we care so much considering we have very events -- but in addition to that
- // the recursive path will be used very infrequently and when it is used, this will be probably just reorder with the prev event and that's it.
- //
- @VisibleForTesting
- protected void reOrderSubscriptionEventsOnSameDateByType(final List<SubscriptionEvent> events) {
- final int size = events.size();
- for (int i = 0; i < size; i++) {
- final SubscriptionEvent cur = events.get(i);
- final SubscriptionEvent next = (i < (size - 1)) ? events.get(i + 1) : null;
-
- final boolean shouldSwap = (next != null && shouldSwap(cur, next, true));
- final boolean shouldReverseSort = (next == null || shouldSwap);
-
- int currentIndex = i;
- if (shouldSwap) {
- Collections.swap(events, i, i + 1);
- }
- if (shouldReverseSort) {
- while (currentIndex >= 1) {
- final SubscriptionEvent revCur = events.get(currentIndex);
- final SubscriptionEvent other = events.get(currentIndex - 1);
- if (shouldSwap(revCur, other, false)) {
- Collections.swap(events, currentIndex, currentIndex - 1);
- }
- if (revCur.getEffectiveDate().compareTo(other.getEffectiveDate()) != 0) {
- break;
- }
- currentIndex--;
- }
- }
- }
- }
-
// Make sure the argument supports the remove operation - hence expect a LinkedList, not a List
private void removeOverlappingSubscriptionEvents(final LinkedList<SubscriptionEvent> events) {
final Iterator<SubscriptionEvent> iterator = events.iterator();
@@ -228,92 +184,4 @@ public class SubscriptionEventOrdering extends EntitlementOrderingBase {
}
}
}
-
- private boolean shouldSwap(final SubscriptionEvent cur, final SubscriptionEvent other, final boolean isAscending) {
- // For a given date, order by subscriptionId, and within subscription by event type
- final int idComp = cur.getEntitlementId().compareTo(other.getEntitlementId());
- final Integer comparison = compareSubscriptionEventsForSameEffectiveDateAndEntitlementId(cur, other);
- return (cur.getEffectiveDate().compareTo(other.getEffectiveDate()) == 0 &&
- ((isAscending &&
- ((idComp > 0) ||
- (idComp == 0 && comparison != null && comparison > 0))) ||
- (!isAscending &&
- ((idComp < 0) ||
- (idComp == 0 && comparison != null && comparison < 0)))));
- }
-
- private Integer compareSubscriptionEventsForSameEffectiveDateAndEntitlementId(final SubscriptionEvent first, final SubscriptionEvent second) {
- // For consistency, make sure entitlement-service and billing-service events always happen in a
- // deterministic order (e.g. after other services for STOP events and before for START events)
- if ((DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME.equals(first.getServiceName()) ||
- BILLING_SERVICE_NAME.equals(first.getServiceName())) &&
- !(DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME.equals(second.getServiceName()) ||
- BILLING_SERVICE_NAME.equals(second.getServiceName()))) {
- // first is an entitlement-service or billing-service event, but not second
- if (first.getSubscriptionEventType().equals(SubscriptionEventType.START_ENTITLEMENT) ||
- first.getSubscriptionEventType().equals(SubscriptionEventType.START_BILLING) ||
- first.getSubscriptionEventType().equals(SubscriptionEventType.RESUME_ENTITLEMENT) ||
- first.getSubscriptionEventType().equals(SubscriptionEventType.RESUME_BILLING) ||
- first.getSubscriptionEventType().equals(SubscriptionEventType.PHASE) ||
- first.getSubscriptionEventType().equals(SubscriptionEventType.CHANGE)) {
- return -1;
- } else if (first.getSubscriptionEventType().equals(SubscriptionEventType.PAUSE_ENTITLEMENT) ||
- first.getSubscriptionEventType().equals(SubscriptionEventType.PAUSE_BILLING) ||
- first.getSubscriptionEventType().equals(SubscriptionEventType.STOP_ENTITLEMENT) ||
- first.getSubscriptionEventType().equals(SubscriptionEventType.STOP_BILLING)) {
- return 1;
- } else {
- // Default behavior
- return -1;
- }
- } else if ((DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME.equals(second.getServiceName()) ||
- BILLING_SERVICE_NAME.equals(second.getServiceName())) &&
- !(DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME.equals(first.getServiceName()) ||
- BILLING_SERVICE_NAME.equals(first.getServiceName()))) {
- // second is an entitlement-service or billing-service event, but not first
- if (second.getSubscriptionEventType().equals(SubscriptionEventType.START_ENTITLEMENT) ||
- second.getSubscriptionEventType().equals(SubscriptionEventType.START_BILLING) ||
- second.getSubscriptionEventType().equals(SubscriptionEventType.RESUME_ENTITLEMENT) ||
- second.getSubscriptionEventType().equals(SubscriptionEventType.RESUME_BILLING) ||
- second.getSubscriptionEventType().equals(SubscriptionEventType.PHASE) ||
- second.getSubscriptionEventType().equals(SubscriptionEventType.CHANGE)) {
- return 1;
- } else if (second.getSubscriptionEventType().equals(SubscriptionEventType.PAUSE_ENTITLEMENT) ||
- second.getSubscriptionEventType().equals(SubscriptionEventType.PAUSE_BILLING) ||
- second.getSubscriptionEventType().equals(SubscriptionEventType.STOP_ENTITLEMENT) ||
- second.getSubscriptionEventType().equals(SubscriptionEventType.STOP_BILLING)) {
- return -1;
- } else {
- // Default behavior
- return 1;
- }
- } else if (first.getSubscriptionEventType().equals(SubscriptionEventType.START_ENTITLEMENT)) {
- // START_ENTITLEMENT is always first
- return -1;
- } else if (second.getSubscriptionEventType().equals(SubscriptionEventType.START_ENTITLEMENT)) {
- // START_ENTITLEMENT is always first
- return 1;
- } else if (first.getSubscriptionEventType().equals(SubscriptionEventType.STOP_BILLING)) {
- // STOP_BILLING is always last
- return 1;
- } else if (second.getSubscriptionEventType().equals(SubscriptionEventType.STOP_BILLING)) {
- // STOP_BILLING is always last
- return -1;
- } else if (first.getSubscriptionEventType().equals(SubscriptionEventType.START_BILLING)) {
- // START_BILLING is first after START_ENTITLEMENT
- return -1;
- } else if (second.getSubscriptionEventType().equals(SubscriptionEventType.START_BILLING)) {
- // START_BILLING is first after START_ENTITLEMENT
- return 1;
- } else if (first.getSubscriptionEventType().equals(SubscriptionEventType.STOP_ENTITLEMENT)) {
- // STOP_ENTITLEMENT is last after STOP_BILLING
- return 1;
- } else if (second.getSubscriptionEventType().equals(SubscriptionEventType.STOP_ENTITLEMENT)) {
- // STOP_ENTITLEMENT is last after STOP_BILLING
- return -1;
- } else {
- // Trust the current ordering
- return null;
- }
- }
}
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestBlockingStateOrdering.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestBlockingStateOrdering.java
new file mode 100644
index 0000000..02a7581
--- /dev/null
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestBlockingStateOrdering.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
+ * 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 org.killbill.billing.entitlement.api;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.killbill.billing.entitlement.DefaultEntitlementService;
+import org.killbill.billing.entitlement.EntitlementTestSuiteNoDB;
+import org.killbill.billing.junction.DefaultBlockingState;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseTransition;
+import org.mockito.Mockito;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// invocationCount > 1 to verify flakiness
+public class TestBlockingStateOrdering extends EntitlementTestSuiteNoDB {
+
+ private long globalOrdering = 0;
+
+ @Test(groups = "fast", invocationCount = 10)
+ public void testIgnore_ENTITLEMENT_SERVICE_NAME_WithNoFlag() throws Exception {
+ final DateTime now = clock.getUTCNow();
+ final UUID subscriptionId1 = UUID.randomUUID();
+
+ final Collection<BlockingState> blockingStates = new LinkedList<BlockingState>();
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, now));
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, "stuff", DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, now.plusDays(1)));
+
+ final LinkedList<SubscriptionEvent> allEvents = new LinkedList<SubscriptionEvent>();
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.START_BILLING, now));
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.PHASE, now.plusDays(30)));
+
+ computeEvents(allEvents, blockingStates);
+
+ Assert.assertEquals(allEvents.size(), 3);
+ Assert.assertEquals(allEvents.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+ Assert.assertEquals(allEvents.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
+ }
+
+ @Test(groups = "fast", invocationCount = 10)
+ public void test_ENT_STATE_IsNotInterpreted() throws Exception {
+ final DateTime now = clock.getUTCNow();
+ final UUID subscriptionId1 = UUID.randomUUID();
+
+ final Collection<BlockingState> blockingStates = new LinkedList<BlockingState>();
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, now));
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, "svc1", false, false, now.plusDays(1)));
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_CANCELLED, "svc1", false, false, now.plusDays(2)));
+
+ final LinkedList<SubscriptionEvent> allEvents = new LinkedList<SubscriptionEvent>();
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.START_BILLING, now));
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.PHASE, now.plusDays(30)));
+
+ computeEvents(allEvents, blockingStates);
+
+ Assert.assertEquals(allEvents.size(), 5);
+ Assert.assertEquals(allEvents.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+ Assert.assertEquals(allEvents.get(2).getSubscriptionEventType(), SubscriptionEventType.SERVICE_STATE_CHANGE);
+ Assert.assertEquals(allEvents.get(3).getSubscriptionEventType(), SubscriptionEventType.SERVICE_STATE_CHANGE);
+ Assert.assertEquals(allEvents.get(4).getSubscriptionEventType(), SubscriptionEventType.PHASE);
+ }
+
+ @Test(groups = "fast", invocationCount = 10)
+ public void testPauseAtStart() throws Exception {
+ final DateTime now = clock.getUTCNow();
+ final UUID subscriptionId1 = UUID.randomUUID();
+
+ final Collection<BlockingState> blockingStates = new LinkedList<BlockingState>();
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, now));
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, "stuff", "svc1", true, true, now));
+
+ final LinkedList<SubscriptionEvent> allEvents = new LinkedList<SubscriptionEvent>();
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.START_BILLING, now));
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.PHASE, now.plusDays(30)));
+
+ computeEvents(allEvents, blockingStates);
+
+ Assert.assertEquals(allEvents.size(), 5);
+ Assert.assertEquals(allEvents.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+ Assert.assertEquals(allEvents.get(2).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+ Assert.assertEquals(allEvents.get(4).getSubscriptionEventType(), SubscriptionEventType.PHASE);
+ }
+
+ @Test(groups = "fast", invocationCount = 10)
+ public void testPausePostPhase_0_17_X() throws Exception {
+ final DateTime now = clock.getUTCNow();
+ final UUID subscriptionId1 = UUID.randomUUID();
+
+ final Collection<BlockingState> blockingStates = new LinkedList<BlockingState>();
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, "stuff", "svc1", true, true, now.plusDays(40)));
+
+ final LinkedList<SubscriptionEvent> allEvents = new LinkedList<SubscriptionEvent>();
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.START_BILLING, now));
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.PHASE, now.plusDays(30)));
+
+ computeEvents(allEvents, blockingStates);
+
+ Assert.assertEquals(allEvents.size(), 5);
+ Assert.assertEquals(allEvents.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+ Assert.assertEquals(allEvents.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
+ Assert.assertEquals(allEvents.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(4).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+ }
+
+ @Test(groups = "fast", invocationCount = 10)
+ public void testPausePostPhase() throws Exception {
+ final DateTime now = clock.getUTCNow();
+ final UUID subscriptionId1 = UUID.randomUUID();
+
+ final Collection<BlockingState> blockingStates = new LinkedList<BlockingState>();
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, now));
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, "stuff", "svc1", true, true, now.plusDays(40)));
+
+ final LinkedList<SubscriptionEvent> allEvents = new LinkedList<SubscriptionEvent>();
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.START_BILLING, now));
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.PHASE, now.plusDays(30)));
+
+ computeEvents(allEvents, blockingStates);
+
+ Assert.assertEquals(allEvents.size(), 5);
+ Assert.assertEquals(allEvents.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+ Assert.assertEquals(allEvents.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
+ Assert.assertEquals(allEvents.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(4).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+ }
+
+ @Test(groups = "fast", invocationCount = 10)
+ public void testPauseAtPhase() throws Exception {
+ final DateTime now = clock.getUTCNow();
+ final UUID subscriptionId1 = UUID.randomUUID();
+
+ final Collection<BlockingState> blockingStates = new LinkedList<BlockingState>();
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, now));
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, "stuff", "svc1", true, true, now.plusDays(30)));
+
+ final LinkedList<SubscriptionEvent> allEvents = new LinkedList<SubscriptionEvent>();
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.START_BILLING, now));
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.PHASE, now.plusDays(30)));
+
+ computeEvents(allEvents, blockingStates);
+
+ Assert.assertEquals(allEvents.size(), 5);
+ Assert.assertEquals(allEvents.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+ Assert.assertEquals(allEvents.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
+ Assert.assertEquals(allEvents.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(4).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+ }
+
+ @Test(groups = "fast", invocationCount = 10)
+ public void testPauseResumeAtPhase() throws Exception {
+ final DateTime now = clock.getUTCNow();
+ final UUID subscriptionId1 = UUID.randomUUID();
+
+ final Collection<BlockingState> blockingStates = new LinkedList<BlockingState>();
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, now));
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, "stuff", "svc1", true, true, now.plusDays(30)));
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, "stuff", "svc1", false, false, now.plusDays(30)));
+
+ final LinkedList<SubscriptionEvent> allEvents = new LinkedList<SubscriptionEvent>();
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.START_BILLING, now));
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.PHASE, now.plusDays(30)));
+
+ computeEvents(allEvents, blockingStates);
+
+ Assert.assertEquals(allEvents.size(), 7);
+ Assert.assertEquals(allEvents.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+ Assert.assertEquals(allEvents.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
+ Assert.assertEquals(allEvents.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(4).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+ Assert.assertEquals(allEvents.get(5).getSubscriptionEventType(), SubscriptionEventType.RESUME_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(6).getSubscriptionEventType(), SubscriptionEventType.RESUME_BILLING);
+ }
+
+ @Test(groups = "fast", invocationCount = 10)
+ public void testPauseAccountAtPhase() throws Exception {
+ final DateTime now = clock.getUTCNow();
+ final UUID subscriptionId1 = UUID.randomUUID();
+
+ final Collection<BlockingState> blockingStates = new LinkedList<BlockingState>();
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, now));
+ blockingStates.add(createBlockingState(UUID.randomUUID(), BlockingStateType.ACCOUNT, "stuff", "svc1", true, true, now.plusDays(30)));
+
+ final LinkedList<SubscriptionEvent> allEvents = new LinkedList<SubscriptionEvent>();
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.START_BILLING, now));
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.PHASE, now.plusDays(30)));
+
+ computeEvents(allEvents, blockingStates);
+
+ Assert.assertEquals(allEvents.size(), 5);
+ Assert.assertEquals(allEvents.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+ Assert.assertEquals(allEvents.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
+ Assert.assertEquals(allEvents.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(4).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+ }
+
+ @Test(groups = "fast", invocationCount = 10)
+ public void testDifferentTypesOfBlockingSameService() throws Exception {
+ final DateTime now = clock.getUTCNow();
+ final UUID subscriptionId1 = UUID.randomUUID();
+
+ final Collection<BlockingState> blockingStates = new LinkedList<BlockingState>();
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, now));
+ blockingStates.add(createBlockingState(UUID.randomUUID(), BlockingStateType.ACCOUNT, "stuff", "svc1", false, true, now.plusDays(10)));
+ // Same service
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, "stuff", "svc1", true, false, now.plusDays(15)));
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, "stuff", "svc1", false, false, now.plusDays(20)));
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.ACCOUNT, "stuff", "svc1", false, false, now.plusDays(30)));
+
+ final LinkedList<SubscriptionEvent> allEvents = new LinkedList<SubscriptionEvent>();
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.START_BILLING, now));
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.PHASE, now.plusDays(30)));
+
+ computeEvents(allEvents, blockingStates);
+
+ Assert.assertEquals(allEvents.size(), 8);
+ Assert.assertEquals(allEvents.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+ Assert.assertEquals(allEvents.get(2).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+ Assert.assertEquals(allEvents.get(3).getSubscriptionEventType(), SubscriptionEventType.RESUME_BILLING);
+ Assert.assertEquals(allEvents.get(4).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(5).getSubscriptionEventType(), SubscriptionEventType.RESUME_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(6).getSubscriptionEventType(), SubscriptionEventType.PHASE);
+ Assert.assertEquals(allEvents.get(7).getSubscriptionEventType(), SubscriptionEventType.SERVICE_STATE_CHANGE);
+ }
+
+ @Test(groups = "fast", invocationCount = 10)
+ public void testDifferentTypesOfBlockingDifferentServices() throws Exception {
+ final DateTime now = clock.getUTCNow();
+ final UUID subscriptionId1 = UUID.randomUUID();
+
+ final Collection<BlockingState> blockingStates = new LinkedList<BlockingState>();
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, now));
+ blockingStates.add(createBlockingState(UUID.randomUUID(), BlockingStateType.ACCOUNT, "stuff", "svc1", false, true, now.plusDays(10)));
+ // Different service
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, "stuff", "svc2", true, false, now.plusDays(15)));
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, "stuff", "svc2", false, false, now.plusDays(20)));
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.ACCOUNT, "stuff", "svc1", false, false, now.plusDays(30)));
+
+ final LinkedList<SubscriptionEvent> allEvents = new LinkedList<SubscriptionEvent>();
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.START_BILLING, now));
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.PHASE, now.plusDays(30)));
+
+ computeEvents(allEvents, blockingStates);
+
+ Assert.assertEquals(allEvents.size(), 7);
+ Assert.assertEquals(allEvents.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+ Assert.assertEquals(allEvents.get(2).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+ Assert.assertEquals(allEvents.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(4).getSubscriptionEventType(), SubscriptionEventType.RESUME_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(5).getSubscriptionEventType(), SubscriptionEventType.PHASE);
+ Assert.assertEquals(allEvents.get(6).getSubscriptionEventType(), SubscriptionEventType.RESUME_BILLING);
+ }
+
+ @Test(groups = "fast", invocationCount = 10)
+ public void testPauseAccountAtPhaseAndPauseOtherSubscriptionFutureStartedV1() throws Exception {
+ final UUID subscriptionId1 = UUID.randomUUID();
+ UUID subscriptionId2 = UUID.randomUUID();
+ while (subscriptionId2.compareTo(subscriptionId1) <= 0) {
+ subscriptionId2 = UUID.randomUUID();
+ }
+ testPauseAccountAtPhaseAndPauseOtherSubscriptionFutureStarted(subscriptionId1, subscriptionId2);
+ }
+
+ @Test(groups = "fast", invocationCount = 10)
+ public void testPauseAccountAtPhaseAndPauseOtherSubscriptionFutureStartedV2() throws Exception {
+ final UUID subscriptionId1 = UUID.randomUUID();
+ UUID subscriptionId2 = UUID.randomUUID();
+ while (subscriptionId2.compareTo(subscriptionId1) >= 0) {
+ subscriptionId2 = UUID.randomUUID();
+ }
+ testPauseAccountAtPhaseAndPauseOtherSubscriptionFutureStarted(subscriptionId1, subscriptionId2);
+ }
+
+ private void testPauseAccountAtPhaseAndPauseOtherSubscriptionFutureStarted(final UUID subscriptionId1, final UUID subscriptionId2) throws Exception {
+ final DateTime now = clock.getUTCNow();
+
+ final Collection<BlockingState> blockingStates = new LinkedList<BlockingState>();
+ blockingStates.add(createBlockingState(subscriptionId1, BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, now));
+ blockingStates.add(createBlockingState(subscriptionId2, BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, now));
+ blockingStates.add(createBlockingState(UUID.randomUUID(), BlockingStateType.ACCOUNT, "stuff", "svc1", true, true, now.plusDays(30)));
+
+ final LinkedList<SubscriptionEvent> allEvents = new LinkedList<SubscriptionEvent>();
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.START_BILLING, now));
+ allEvents.add(createEvent(subscriptionId1, SubscriptionEventType.PHASE, now.plusDays(30)));
+ allEvents.add(createEvent(subscriptionId2, SubscriptionEventType.START_BILLING, now.plusDays(40)));
+
+ computeEvents(allEvents, blockingStates);
+
+ Assert.assertEquals(allEvents.size(), 8);
+ Assert.assertEquals(allEvents.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(1).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(2).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+ Assert.assertEquals(allEvents.get(3).getSubscriptionEventType(), SubscriptionEventType.PHASE);
+ if (subscriptionId1.compareTo(subscriptionId2) >= 0) {
+ Assert.assertEquals(allEvents.get(4).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(5).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(6).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+ } else {
+ Assert.assertEquals(allEvents.get(4).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ Assert.assertEquals(allEvents.get(5).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+ Assert.assertEquals(allEvents.get(6).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ }
+ Assert.assertEquals(allEvents.get(7).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+ }
+
+ private BlockingState createBlockingState(final UUID blockedId,
+ final BlockingStateType blockingStateType,
+ final String stateName,
+ final String service,
+ final boolean blockEntitlement,
+ final boolean blockBilling,
+ final DateTime effectiveDate) {
+ return new DefaultBlockingState(UUID.randomUUID(),
+ blockedId,
+ blockingStateType,
+ stateName,
+ service,
+ false,
+ blockEntitlement,
+ blockBilling,
+ effectiveDate,
+ effectiveDate,
+ effectiveDate,
+ globalOrdering++);
+ }
+
+ // Re-use SubscriptionEventOrdering method, as it's the input of BlockingStateOrdering
+ private SubscriptionEvent createEvent(final UUID subscriptionId, final SubscriptionEventType type, final DateTime effectiveDate) {
+ final SubscriptionBaseTransition subscriptionBaseTransition = Mockito.mock(SubscriptionBaseTransition.class);
+ Mockito.when(subscriptionBaseTransition.getId()).thenReturn(UUID.randomUUID());
+ Mockito.when(subscriptionBaseTransition.getSubscriptionId()).thenReturn(subscriptionId);
+ Mockito.when(subscriptionBaseTransition.getEffectiveTransitionTime()).thenReturn(effectiveDate);
+ return SubscriptionEventOrdering.toSubscriptionEvent(subscriptionBaseTransition, type, internalCallContext);
+ }
+
+ private void computeEvents(final LinkedList<SubscriptionEvent> allEvents, final Collection<BlockingState> blockingStates) {
+ final Collection<UUID> allEntitlementUUIDs = new HashSet<UUID>();
+ for (final SubscriptionEvent subscriptionEvent : allEvents) {
+ allEntitlementUUIDs.add(subscriptionEvent.getEntitlementId());
+ }
+ for (final BlockingState blockingState : blockingStates) {
+ if (blockingState.getType() == BlockingStateType.SUBSCRIPTION) {
+ allEntitlementUUIDs.add(blockingState.getBlockedId());
+ }
+ }
+
+ BlockingStateOrdering.INSTANCE.computeEvents(new LinkedList<UUID>(allEntitlementUUIDs), blockingStates, internalCallContext, allEvents);
+ }
+}
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
index fc7fb25..b82d6e8 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -41,7 +41,6 @@ import org.killbill.billing.subscription.api.user.SubscriptionBaseTransitionData
import org.killbill.billing.subscription.events.SubscriptionBaseEvent.EventType;
import org.killbill.billing.subscription.events.user.ApiEventType;
import org.mockito.Mockito;
-import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -62,209 +61,6 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
bundleExternalKey = bundleId.toString();
}
- public class TestSubscriptionBundleTimeline extends DefaultSubscriptionBundleTimeline {
-
- public TestSubscriptionBundleTimeline(final UUID accountId, final UUID bundleId, final String externalKey, final Iterable<Entitlement> entitlements) {
- super(accountId, bundleId, externalKey, entitlements, internalCallContext);
- }
-
- public SubscriptionEvent createEvent(final UUID subscriptionId, final SubscriptionEventType type, final DateTime effectiveDate) {
- return new DefaultSubscriptionEvent(UUID.randomUUID(),
- subscriptionId,
- effectiveDate,
- type,
- true,
- true,
- "foo",
- "bar",
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- internalCallContext);
-
- }
- }
-
- @Test(groups = "fast")
- public void testReOrderSubscriptionEventsOnInvalidOrder1() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
-
- final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
- final UUID subscriptionId = UUID.randomUUID();
- final DateTime effectiveDate = clock.getUTCNow();
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_BILLING, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_ENTITLEMENT, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_ENTITLEMENT, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_BILLING, effectiveDate));
-
- SubscriptionEventOrdering.INSTANCE.reOrderSubscriptionEventsOnSameDateByType(events);
-
- Assert.assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
- Assert.assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
- Assert.assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
- Assert.assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
- }
-
- @Test(groups = "fast")
- public void testReOrderSubscriptionEventsOnInvalidOrder2() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
-
- final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
- final UUID subscriptionId = UUID.randomUUID();
- final DateTime effectiveDate = clock.getUTCNow();
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_BILLING, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_ENTITLEMENT, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_BILLING, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_ENTITLEMENT, effectiveDate));
-
- SubscriptionEventOrdering.INSTANCE.reOrderSubscriptionEventsOnSameDateByType(events);
-
- Assert.assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
- Assert.assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
- Assert.assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
- Assert.assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
- }
-
- @Test(groups = "fast")
- public void testReOrderSubscriptionEventsOnInvalidOrder3() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
-
- final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
- final UUID subscriptionId = UUID.randomUUID();
- final DateTime effectiveDate = clock.getUTCNow();
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_BILLING, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_ENTITLEMENT, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_BILLING, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_ENTITLEMENT, effectiveDate));
-
- SubscriptionEventOrdering.INSTANCE.reOrderSubscriptionEventsOnSameDateByType(events);
-
- Assert.assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
- Assert.assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
- Assert.assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
- Assert.assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
- }
-
- @Test(groups = "fast")
- public void testReOrderSubscriptionEventsOnInvalidOrderAndDifferentSubscriptionsSameDates1() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
-
- final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
- final UUID subscriptionId = UUID.fromString("60b64e0c-cefd-48c3-8de9-c731a9558165");
-
- final UUID otherSubscriptionId = UUID.fromString("35b3b340-31b2-46ea-b062-e9fc9fab3bc9");
- final DateTime effectiveDate = clock.getUTCNow();
-
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_ENTITLEMENT, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_BILLING, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_BILLING, effectiveDate));
- events.add(timeline.createEvent(otherSubscriptionId, SubscriptionEventType.STOP_BILLING, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_ENTITLEMENT, effectiveDate));
-
- SubscriptionEventOrdering.INSTANCE.reOrderSubscriptionEventsOnSameDateByType(events);
-
- Assert.assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
- Assert.assertEquals(events.get(0).getEntitlementId(), otherSubscriptionId);
- Assert.assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
- Assert.assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
- Assert.assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
- Assert.assertEquals(events.get(4).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
- Assert.assertEquals(events.get(4).getEntitlementId(), subscriptionId);
- }
-
- @Test(groups = "fast")
- public void testReOrderSubscriptionEventsOnInvalidOrderAndDifferentSubscriptionsSameDates2() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
-
- final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
- final UUID subscriptionId = UUID.fromString("35b3b340-31b2-46ea-b062-e9fc9fab3bc9");
- final UUID otherSubscriptionId = UUID.fromString("60b64e0c-cefd-48c3-8de9-c731a9558165");
-
- final DateTime effectiveDate = clock.getUTCNow();
-
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_ENTITLEMENT, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_BILLING, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_BILLING, effectiveDate));
- events.add(timeline.createEvent(otherSubscriptionId, SubscriptionEventType.STOP_BILLING, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_ENTITLEMENT, effectiveDate));
-
- SubscriptionEventOrdering.INSTANCE.reOrderSubscriptionEventsOnSameDateByType(events);
-
- Assert.assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
- Assert.assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
- Assert.assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
- Assert.assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
- Assert.assertEquals(events.get(3).getEntitlementId(), subscriptionId);
- Assert.assertEquals(events.get(4).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
- Assert.assertEquals(events.get(4).getEntitlementId(), otherSubscriptionId);
- }
-
- @Test(groups = "fast")
- public void testReOrderSubscriptionEventsOnInvalidOrderAndDifferentSubscriptionsDates() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
-
- final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
- final UUID subscriptionId = UUID.randomUUID();
-
- final UUID otherSubscriptionId = UUID.randomUUID();
- final DateTime effectiveDate = clock.getUTCNow();
- final DateTime otherEffectiveDate = clock.getUTCNow().plusDays(1);
-
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_BILLING, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_ENTITLEMENT, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_BILLING, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_ENTITLEMENT, effectiveDate));
-
- events.add(timeline.createEvent(otherSubscriptionId, SubscriptionEventType.START_BILLING, otherEffectiveDate));
- events.add(timeline.createEvent(otherSubscriptionId, SubscriptionEventType.START_ENTITLEMENT, otherEffectiveDate));
- events.add(timeline.createEvent(otherSubscriptionId, SubscriptionEventType.STOP_ENTITLEMENT, otherEffectiveDate));
- events.add(timeline.createEvent(otherSubscriptionId, SubscriptionEventType.STOP_BILLING, otherEffectiveDate));
- events.add(timeline.createEvent(otherSubscriptionId, SubscriptionEventType.PAUSE_ENTITLEMENT, otherEffectiveDate));
- events.add(timeline.createEvent(otherSubscriptionId, SubscriptionEventType.PAUSE_BILLING, otherEffectiveDate));
-
- SubscriptionEventOrdering.INSTANCE.reOrderSubscriptionEventsOnSameDateByType(events);
-
- Assert.assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
- Assert.assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
- Assert.assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
- Assert.assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
-
- Assert.assertEquals(events.get(4).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
- Assert.assertEquals(events.get(5).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
- Assert.assertEquals(events.get(6).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
- Assert.assertEquals(events.get(7).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
- Assert.assertEquals(events.get(8).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
- Assert.assertEquals(events.get(9).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
- }
-
- @Test(groups = "fast")
- public void testReOrderSubscriptionEventsOnCorrectOrder() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
-
- final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
- final UUID subscriptionId = UUID.randomUUID();
- final DateTime effectiveDate = clock.getUTCNow();
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_ENTITLEMENT, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.START_BILLING, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_ENTITLEMENT, effectiveDate));
- events.add(timeline.createEvent(subscriptionId, SubscriptionEventType.STOP_BILLING, effectiveDate));
-
- SubscriptionEventOrdering.INSTANCE.reOrderSubscriptionEventsOnSameDateByType(events);
-
- Assert.assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
- Assert.assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
- Assert.assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
- Assert.assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
- }
-
@Test(groups = "fast")
public void testOneSimpleEntitlement() throws CatalogApiException {
testOneSimpleEntitlementImpl(false);
@@ -275,7 +71,6 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
testOneSimpleEntitlementImpl(true);
}
-
private void testOneSimpleEntitlementImpl(boolean regressionFlagForOlderVersionThan_0_17_X) throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));
@@ -348,18 +143,16 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
assertNull(events.get(3).getNextPhase());
}
-
- @Test(groups="fast", enabled = true)
+ @Test(groups="fast")
public void testOneSimpleEntitlementCancelImmediately() throws CatalogApiException {
testOneSimpleEntitlementCancelImmediatelyImpl(false);
}
- @Test(groups="fast", enabled = true)
+ @Test(groups="fast")
public void testOneSimpleEntitlementCancelImmediatelyWithRegression() throws CatalogApiException {
testOneSimpleEntitlementCancelImmediatelyImpl(true);
}
-
private void testOneSimpleEntitlementCancelImmediatelyImpl(boolean regressionFlagForOlderVersionThan_0_17_X) throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));
@@ -518,7 +311,6 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
testOneEntitlementWithPauseResumeImpl(true);
}
-
private void testOneEntitlementWithPauseResumeImpl(final boolean regressionFlagForOlderVersionThan_0_17_X) throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));