/*
* Copyright 2010-2013 Ning, Inc.
* 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.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhase;
import org.killbill.billing.catalog.api.PriceList;
import org.killbill.billing.catalog.api.Product;
import org.killbill.billing.entitlement.DefaultEntitlementService;
import org.killbill.billing.entitlement.EntitlementTestSuiteNoDB;
import org.killbill.billing.entitlement.EventsStream;
import org.killbill.billing.junction.DefaultBlockingState;
import org.killbill.billing.subscription.api.SubscriptionBase;
import org.killbill.billing.subscription.api.user.SubscriptionBaseTransition;
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.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteNoDB {
private UUID bundleId;
private String bundleExternalKey;
@BeforeClass(groups = "fast")
protected void beforeClass() throws Exception {
super.beforeClass();
bundleId = UUID.randomUUID();
bundleExternalKey = bundleId.toString();
}
@Test(groups = "fast")
public void testOneSimpleEntitlement() throws CatalogApiException {
testOneSimpleEntitlementImpl(false);
}
@Test(groups = "fast")
public void testOneSimpleEntitlementWithRegression() throws CatalogApiException {
testOneSimpleEntitlementImpl(true);
}
private void testOneSimpleEntitlementImpl(boolean regressionFlagForOlderVersionThan_0_17_X) throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));
final DateTimeZone accountTimeZone = DateTimeZone.UTC;
final UUID accountId = UUID.randomUUID();
final String externalKey = "foo";
final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
final UUID entitlementId = UUID.randomUUID();
final List<SubscriptionBaseTransition> allTransitions = new ArrayList<SubscriptionBaseTransition>();
DateTime effectiveDate = new DateTime(2013, 1, 1, 15, 43, 25, 0, DateTimeZone.UTC);
final SubscriptionBaseTransition tr1 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CREATE, effectiveDate, clock.getUTCNow(), null, "trial");
allTransitions.add(tr1);
if (!regressionFlagForOlderVersionThan_0_17_X) {
final BlockingState bsCreate = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bsCreate);
}
effectiveDate = effectiveDate.plusDays(30);
clock.addDays(30);
final SubscriptionBaseTransition tr2 = createTransition(entitlementId, EventType.PHASE, null, effectiveDate, clock.getUTCNow(), "trial", "phase");
allTransitions.add(tr2);
effectiveDate = effectiveDate.plusDays(15);
clock.addDays(15);
final SubscriptionBaseTransition tr3 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CANCEL, effectiveDate, clock.getUTCNow(), "phase", null);
allTransitions.add(tr3);
final List<Entitlement> entitlements = new ArrayList<Entitlement>();
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
assertEquals(timeline.getAccountId(), accountId);
assertEquals(timeline.getBundleId(), bundleId);
assertEquals(timeline.getExternalKey(), externalKey);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 4);
assertEquals(events.get(0).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(1).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(2).getEffectiveDate().compareTo(new LocalDate(tr2.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(3).getEffectiveDate().compareTo(new LocalDate(tr3.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
assertEquals(events.get(0).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(1).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(2).getServiceName(), EntitlementOrderingBase.ENT_BILLING_SERVICE_NAME);
assertEquals(events.get(3).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertNull(events.get(0).getPrevPhase());
assertNull(events.get(1).getPrevPhase());
assertEquals(events.get(1).getNextPhase().getName(), "trial");
assertEquals(events.get(2).getPrevPhase().getName(), "trial");
assertEquals(events.get(2).getNextPhase().getName(), "phase");
assertEquals(events.get(3).getPrevPhase().getName(), "phase");
assertNull(events.get(3).getNextPhase());
}
@Test(groups="fast")
public void testOneSimpleEntitlementCancelImmediately() throws CatalogApiException {
testOneSimpleEntitlementCancelImmediatelyImpl(false);
}
@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));
final UUID accountId = UUID.randomUUID();
final String externalKey = "foo";
final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
final UUID entitlementId = UUID.randomUUID();
final List<SubscriptionBaseTransition> allTransitions = new ArrayList<SubscriptionBaseTransition>();
DateTime effectiveDate = new DateTime(2013, 1, 1, 15, 43, 25, 0, DateTimeZone.UTC);
final SubscriptionBaseTransition tr1 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CREATE, effectiveDate, clock.getUTCNow(), null, "trial");
allTransitions.add(tr1);
if (!regressionFlagForOlderVersionThan_0_17_X) {
final BlockingState bsCreate = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bsCreate);
}
final SubscriptionBaseTransition tr2 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CANCEL, effectiveDate, clock.getUTCNow(), "trial", null);
allTransitions.add(tr2);
final BlockingState bsCancel = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_CANCELLED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bsCancel);
final List<Entitlement> entitlements = new ArrayList<Entitlement>();
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
assertEquals(timeline.getAccountId(), accountId);
assertEquals(timeline.getBundleId(), bundleId);
assertEquals(timeline.getExternalKey(), externalKey);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 4);
assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
assertNull(events.get(0).getPrevPhase());
assertEquals(events.get(0).getNextPhase().getName(), "trial");
assertNull(events.get(1).getPrevPhase());
assertEquals(events.get(1).getNextPhase().getName(), "trial");
assertEquals(events.get(2).getPrevPhase().getName(), "trial");
assertNull(events.get(2).getNextPhase());
assertEquals(events.get(3).getPrevPhase().getName(), "trial");
assertNull(events.get(3).getNextPhase());
}
@Test(groups = "fast")
public void testCancelBundleBeforeSubscription() throws CatalogApiException {
testCancelBundleBeforeSubscriptionImpl(false);
}
@Test(groups = "fast")
public void testCancelBundleBeforeSubscriptionWithRegression() throws CatalogApiException {
testCancelBundleBeforeSubscriptionImpl(true);
}
private void testCancelBundleBeforeSubscriptionImpl(final boolean regressionFlagForOlderVersionThan_0_17_X) throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));
final DateTimeZone accountTimeZone = DateTimeZone.UTC;
final UUID accountId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
final String externalKey = "foo";
final UUID entitlementId = UUID.randomUUID();
final List<SubscriptionBaseTransition> allTransitions = new ArrayList<SubscriptionBaseTransition>();
final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
DateTime effectiveDate = new DateTime(2013, 1, 1, 15, 43, 25, 0, DateTimeZone.UTC);
final SubscriptionBaseTransition tr1 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CREATE, effectiveDate, clock.getUTCNow(), null, "trial");
allTransitions.add(tr1);
if (!regressionFlagForOlderVersionThan_0_17_X) {
final BlockingState bsCreate = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bsCreate);
}
// Block the bundle before the subscription
effectiveDate = effectiveDate.plusDays(15);
clock.addDays(15);
final BlockingState bs1 = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE,
DefaultEntitlementApi.ENT_STATE_CANCELLED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bs1);
effectiveDate = effectiveDate.plusDays(15);
clock.addDays(15);
final SubscriptionBaseTransition tr2 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CANCEL, effectiveDate, clock.getUTCNow(), "trial", null);
allTransitions.add(tr2);
final List<Entitlement> entitlements = new ArrayList<Entitlement>();
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
assertEquals(timeline.getAccountId(), accountId);
assertEquals(timeline.getBundleId(), bundleId);
assertEquals(timeline.getExternalKey(), externalKey);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 4);
assertEquals(events.get(0).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(1).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(2).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(3).getEffectiveDate().compareTo(new LocalDate(tr2.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
assertEquals(events.get(0).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(1).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(2).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(3).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertNull(events.get(0).getPrevPhase());
assertNull(events.get(1).getPrevPhase());
assertEquals(events.get(1).getNextPhase().getName(), "trial");
assertEquals(events.get(3).getPrevPhase().getName(), "trial");
assertNull(events.get(3).getNextPhase());
}
@Test(groups = "fast", description = "Test for https://github.com/killbill/killbill/issues/135")
public void testOneEntitlementWithPauseResume() throws CatalogApiException {
testOneEntitlementWithPauseResumeImpl(false);
}
@Test(groups = "fast", description = "Test for https://github.com/killbill/killbill/issues/135")
public void testOneEntitlementWithPauseResumeWithRegression() throws CatalogApiException {
testOneEntitlementWithPauseResumeImpl(true);
}
private void testOneEntitlementWithPauseResumeImpl(final boolean regressionFlagForOlderVersionThan_0_17_X) throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));
final DateTimeZone accountTimeZone = DateTimeZone.UTC;
final UUID accountId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
final String externalKey = "foo";
final UUID entitlementId = UUID.randomUUID();
final List<SubscriptionBaseTransition> allTransitions = new ArrayList<SubscriptionBaseTransition>();
final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
DateTime effectiveDate = new DateTime(2013, 1, 1, 15, 43, 25, 0, DateTimeZone.UTC);
final SubscriptionBaseTransition tr1 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CREATE, effectiveDate, clock.getUTCNow(), null, "trial");
allTransitions.add(tr1);
if (!regressionFlagForOlderVersionThan_0_17_X) {
final BlockingState bsCreate = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bsCreate);
}
effectiveDate = effectiveDate.plusDays(30);
clock.addDays(30);
final SubscriptionBaseTransition tr2 = createTransition(entitlementId, EventType.PHASE, null, effectiveDate, clock.getUTCNow(), "trial", "phase");
allTransitions.add(tr2);
effectiveDate = effectiveDate.plusDays(12);
clock.addDays(12);
final BlockingState bs1 = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
"NothingUseful1", DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, true, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bs1);
effectiveDate = effectiveDate.plusDays(42);
clock.addDays(42);
final BlockingState bs2 = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
"NothingUseful2", DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 1L);
blockingStates.add(bs2);
effectiveDate = effectiveDate.plusDays(15);
clock.addDays(15);
final String service = "boo-service-which-will-pause-billing";
final BlockingState bs3 = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
"NothingUseful3", service,
false, false, true, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 2L);
blockingStates.add(bs3);
effectiveDate = effectiveDate.plusDays(15);
clock.addDays(15);
final BlockingState bs4 = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
"NothingUseful4", service,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 3L);
blockingStates.add(bs4);
final List<Entitlement> entitlements = new ArrayList<Entitlement>();
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
assertEquals(timeline.getAccountId(), accountId);
assertEquals(timeline.getBundleId(), bundleId);
assertEquals(timeline.getExternalKey(), externalKey);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 9);
assertEquals(events.get(0).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(1).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(2).getEffectiveDate().compareTo(new LocalDate(tr2.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(3).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(4).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(5).getEffectiveDate().compareTo(new LocalDate(bs2.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(6).getEffectiveDate().compareTo(new LocalDate(bs2.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(7).getEffectiveDate().compareTo(new LocalDate(bs3.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(8).getEffectiveDate().compareTo(new LocalDate(bs4.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
assertEquals(events.get(4).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
assertEquals(events.get(5).getSubscriptionEventType(), SubscriptionEventType.RESUME_ENTITLEMENT);
assertEquals(events.get(6).getSubscriptionEventType(), SubscriptionEventType.RESUME_BILLING);
assertEquals(events.get(7).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
assertEquals(events.get(8).getSubscriptionEventType(), SubscriptionEventType.RESUME_BILLING);
assertEquals(events.get(0).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(1).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(2).getServiceName(), EntitlementOrderingBase.ENT_BILLING_SERVICE_NAME);
assertEquals(events.get(3).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(4).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(5).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(6).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(7).getServiceName(), service);
assertEquals(events.get(8).getServiceName(), service);
assertNull(events.get(0).getPrevPhase());
assertNull(events.get(1).getPrevPhase());
assertEquals(events.get(1).getNextPhase().getName(), "trial");
assertEquals(events.get(2).getPrevPhase().getName(), "trial");
assertEquals(events.get(2).getNextPhase().getName(), "phase");
assertEquals(events.get(3).getPrevPhase().getName(), "phase");
assertEquals(events.get(3).getNextPhase().getName(), "phase");
assertEquals(events.get(4).getPrevPhase().getName(), "phase");
assertEquals(events.get(4).getNextPhase().getName(), "phase");
assertEquals(events.get(5).getPrevPhase().getName(), "phase");
assertEquals(events.get(5).getNextPhase().getName(), "phase");
assertEquals(events.get(6).getPrevPhase().getName(), "phase");
assertEquals(events.get(6).getNextPhase().getName(), "phase");
assertEquals(events.get(7).getPrevPhase().getName(), "phase");
assertEquals(events.get(7).getNextPhase().getName(), "phase");
assertEquals(events.get(8).getPrevPhase().getName(), "phase");
assertEquals(events.get(8).getNextPhase().getName(), "phase");
}
@Test(groups = "fast", description = "Test for https://github.com/killbill/killbill/issues/147 and https://github.com/killbill/killbill/issues/148")
public void testOneEntitlementWithOverduePauseThenCancel() throws CatalogApiException {
testOneEntitlementWithOverduePauseThenCancelImpl(false);
}
@Test(groups = "fast")
public void testOneEntitlementWithOverduePauseThenCancelWithRegression() throws CatalogApiException {
testOneEntitlementWithOverduePauseThenCancelImpl(true);
}
private void testOneEntitlementWithOverduePauseThenCancelImpl(final boolean regressionFlagForOlderVersionThan_0_17_X) throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));
final DateTimeZone accountTimeZone = DateTimeZone.UTC;
final UUID accountId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
final String externalKey = "foo";
final UUID entitlementId = UUID.randomUUID();
final List<SubscriptionBaseTransition> allTransitions = new ArrayList<SubscriptionBaseTransition>();
final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
DateTime effectiveDate = new DateTime(2013, 1, 1, 15, 43, 25, 0, DateTimeZone.UTC);
final SubscriptionBaseTransition tr1 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CREATE, effectiveDate, clock.getUTCNow(), null, "trial");
allTransitions.add(tr1);
if (!regressionFlagForOlderVersionThan_0_17_X) {
final BlockingState bsCreate = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bsCreate);
}
effectiveDate = effectiveDate.plusDays(30);
clock.addDays(30);
final SubscriptionBaseTransition tr2 = createTransition(entitlementId, EventType.PHASE, null, effectiveDate, clock.getUTCNow(), "trial", "phase");
allTransitions.add(tr2);
final String overdueService = "overdue-service";
effectiveDate = effectiveDate.plusDays(12);
clock.addDays(12);
final BlockingState bs1 = new DefaultBlockingState(UUID.randomUUID(), accountId, BlockingStateType.ACCOUNT,
"ODE1", overdueService,
true, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bs1);
effectiveDate = effectiveDate.plusDays(42);
clock.addDays(42);
final BlockingState bs2 = new DefaultBlockingState(UUID.randomUUID(), accountId, BlockingStateType.ACCOUNT,
"ODE2", overdueService,
true, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 1L);
blockingStates.add(bs2);
effectiveDate = effectiveDate.plusDays(15);
clock.addDays(15);
final BlockingState bs3 = new DefaultBlockingState(UUID.randomUUID(), accountId, BlockingStateType.ACCOUNT,
"ODE3", overdueService,
true, true, true, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 2L);
blockingStates.add(bs3);
effectiveDate = effectiveDate.plusDays(15);
clock.addDays(15);
final BlockingState bs4 = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_CANCELLED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 3L);
blockingStates.add(bs4);
effectiveDate = effectiveDate.plusDays(1);
clock.addDays(1);
final BlockingState bs5 = new DefaultBlockingState(UUID.randomUUID(), accountId, BlockingStateType.ACCOUNT,
"ODE4", overdueService,
true, true, true, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 4L);
blockingStates.add(bs5);
// Note: cancellation event and ODE4 at the same effective date (see https://github.com/killbill/killbill/issues/148)
final SubscriptionBaseTransition tr3 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CANCEL, effectiveDate, clock.getUTCNow(), "phase", null);
allTransitions.add(tr3);
final List<Entitlement> entitlements = new ArrayList<Entitlement>();
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
assertEquals(timeline.getAccountId(), accountId);
assertEquals(timeline.getBundleId(), bundleId);
assertEquals(timeline.getExternalKey(), externalKey);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 10);
assertEquals(events.get(0).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(1).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(2).getEffectiveDate().compareTo(new LocalDate(tr2.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(3).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(4).getEffectiveDate().compareTo(new LocalDate(bs2.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(5).getEffectiveDate().compareTo(new LocalDate(bs3.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(6).getEffectiveDate().compareTo(new LocalDate(bs3.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(7).getEffectiveDate().compareTo(new LocalDate(bs4.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(8).getEffectiveDate().compareTo(new LocalDate(tr3.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(9).getEffectiveDate().compareTo(new LocalDate(tr3.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.SERVICE_STATE_CHANGE);
assertEquals(events.get(4).getSubscriptionEventType(), SubscriptionEventType.SERVICE_STATE_CHANGE);
assertEquals(events.get(5).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
assertEquals(events.get(6).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
assertEquals(events.get(7).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
assertEquals(events.get(8).getSubscriptionEventType(), SubscriptionEventType.SERVICE_STATE_CHANGE);
assertEquals(events.get(9).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
assertEquals(events.get(0).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(1).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(2).getServiceName(), EntitlementOrderingBase.ENT_BILLING_SERVICE_NAME);
assertEquals(events.get(3).getServiceName(), overdueService);
assertEquals(events.get(4).getServiceName(), overdueService);
assertEquals(events.get(5).getServiceName(), overdueService);
assertEquals(events.get(6).getServiceName(), overdueService);
assertEquals(events.get(7).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(8).getServiceName(), overdueService);
assertEquals(events.get(9).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertNull(events.get(0).getPrevPhase());
assertNull(events.get(1).getPrevPhase());
assertEquals(events.get(1).getNextPhase().getName(), "trial");
assertEquals(events.get(2).getPrevPhase().getName(), "trial");
assertEquals(events.get(2).getNextPhase().getName(), "phase");
assertEquals(events.get(3).getPrevPhase().getName(), "phase");
assertEquals(events.get(3).getNextPhase().getName(), "phase");
assertEquals(events.get(4).getPrevPhase().getName(), "phase");
assertEquals(events.get(4).getNextPhase().getName(), "phase");
assertEquals(events.get(5).getPrevPhase().getName(), "phase");
assertEquals(events.get(5).getNextPhase().getName(), "phase");
assertEquals(events.get(6).getPrevPhase().getName(), "phase");
assertEquals(events.get(6).getNextPhase().getName(), "phase");
assertEquals(events.get(7).getPrevPhase().getName(), "phase");
assertNull(events.get(7).getNextPhase());
assertEquals(events.get(8).getPrevPhase().getName(), "phase");
assertNull(events.get(8).getNextPhase());
assertEquals(events.get(9).getPrevPhase().getName(), "phase");
assertNull(events.get(9).getNextPhase());
}
@Test(groups = "fast")
public void testOneEntitlementWithInitialBlockingState() throws CatalogApiException {
testOneEntitlementWithInitialBlockingStateImpl(false);
}
@Test(groups = "fast")
public void testOneEntitlementWithInitialBlockingStateWithRegression() throws CatalogApiException {
testOneEntitlementWithInitialBlockingStateImpl(true);
}
private void testOneEntitlementWithInitialBlockingStateImpl(final boolean regressionFlagForOlderVersionThan_0_17_X) throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));
final DateTimeZone accountTimeZone = DateTimeZone.UTC;
final UUID accountId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
final String externalKey = "foo";
final UUID entitlementId = UUID.randomUUID();
final List<SubscriptionBaseTransition> allTransitions = new ArrayList<SubscriptionBaseTransition>();
final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
final BlockingState bs1 = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_BLOCKED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, false, clock.getUTCNow(), clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bs1);
clock.addDays(1);
DateTime effectiveDate = new DateTime(2013, 1, 1, 15, 43, 25, 0, DateTimeZone.UTC);
final SubscriptionBaseTransition tr1 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CREATE, effectiveDate, clock.getUTCNow(), null, "trial");
allTransitions.add(tr1);
if (!regressionFlagForOlderVersionThan_0_17_X) {
final BlockingState bsCreate = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bsCreate);
}
effectiveDate = effectiveDate.plusDays(30);
clock.addDays(30);
final SubscriptionBaseTransition tr2 = createTransition(entitlementId, EventType.PHASE, null, effectiveDate, clock.getUTCNow(), "trial", "phase");
allTransitions.add(tr2);
final String service = "boo";
final BlockingState bs2 = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
"NothingUseful", service,
false, false, false, clock.getUTCNow(), clock.getUTCNow(), clock.getUTCNow(), 1L);
blockingStates.add(bs2);
effectiveDate = effectiveDate.plusDays(15);
clock.addDays(15);
final SubscriptionBaseTransition tr3 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CANCEL, effectiveDate, clock.getUTCNow(), "phase", null);
allTransitions.add(tr3);
final List<Entitlement> entitlements = new ArrayList<Entitlement>();
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
assertEquals(timeline.getAccountId(), accountId);
assertEquals(timeline.getBundleId(), bundleId);
assertEquals(timeline.getExternalKey(), externalKey);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 5);
assertEquals(events.get(0).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(1).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(2).getEffectiveDate().compareTo(new LocalDate(tr2.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(3).getEffectiveDate().compareTo(new LocalDate(bs2.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(4).getEffectiveDate().compareTo(new LocalDate(tr3.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.SERVICE_STATE_CHANGE);
assertEquals(events.get(4).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
assertEquals(events.get(0).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(1).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(2).getServiceName(), EntitlementOrderingBase.ENT_BILLING_SERVICE_NAME);
assertEquals(events.get(3).getServiceName(), service);
assertEquals(events.get(4).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertNull(events.get(0).getPrevPhase());
assertNull(events.get(1).getPrevPhase());
assertEquals(events.get(1).getNextPhase().getName(), "trial");
assertEquals(events.get(2).getPrevPhase().getName(), "trial");
assertEquals(events.get(2).getNextPhase().getName(), "phase");
assertEquals(events.get(3).getPrevPhase().getName(), "phase");
assertEquals(events.get(3).getNextPhase().getName(), "phase");
assertEquals(events.get(4).getPrevPhase().getName(), "phase");
assertNull(events.get(4).getNextPhase());
}
@Test(groups = "fast")
public void testOneEntitlementWithBlockingStatesSubscription() throws CatalogApiException {
testOneEntitlementWithBlockingStatesSubscriptionImpl(false);
}
@Test(groups = "fast")
public void testOneEntitlementWithBlockingStatesSubscriptionWithRegression() throws CatalogApiException {
testOneEntitlementWithBlockingStatesSubscriptionImpl(true);
}
private void testOneEntitlementWithBlockingStatesSubscriptionImpl(final boolean regressionFlagForOlderVersionThan_0_17_X) throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));
final DateTimeZone accountTimeZone = DateTimeZone.UTC;
final UUID accountId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
final String externalKey = "foo";
final UUID entitlementId = UUID.randomUUID();
final List<SubscriptionBaseTransition> allTransitions = new ArrayList<SubscriptionBaseTransition>();
final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
DateTime effectiveDate = new DateTime(2013, 1, 1, 15, 43, 25, 0, DateTimeZone.UTC);
final SubscriptionBaseTransition tr1 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CREATE, effectiveDate, clock.getUTCNow(), null, "trial");
allTransitions.add(tr1);
if (!regressionFlagForOlderVersionThan_0_17_X) {
final BlockingState bsCreate = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bsCreate);
}
effectiveDate = effectiveDate.plusDays(30);
clock.addDays(30);
final SubscriptionBaseTransition tr2 = createTransition(entitlementId, EventType.PHASE, null, effectiveDate, clock.getUTCNow(), "trial", "phase");
allTransitions.add(tr2);
effectiveDate = effectiveDate.plusDays(5);
clock.addDays(5);
final BlockingState bs1 = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_BLOCKED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bs1);
effectiveDate = effectiveDate.plusDays(15);
clock.addDays(15);
final SubscriptionBaseTransition tr3 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CANCEL, effectiveDate, clock.getUTCNow(), "phase", null);
allTransitions.add(tr3);
final BlockingState bs2 = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_CANCELLED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 1L);
blockingStates.add(bs2);
final List<Entitlement> entitlements = new ArrayList<Entitlement>();
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 6);
assertEquals(events.get(0).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(1).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(2).getEffectiveDate().compareTo(new LocalDate(tr2.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(3).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(4).getEffectiveDate().compareTo(new LocalDate(tr3.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(5).getEffectiveDate().compareTo(new LocalDate(bs2.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
assertEquals(events.get(4).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
assertEquals(events.get(5).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
assertEquals(events.get(0).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(1).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(2).getServiceName(), EntitlementOrderingBase.ENT_BILLING_SERVICE_NAME);
assertEquals(events.get(3).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(4).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(5).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertNull(events.get(0).getPrevPhase());
assertNull(events.get(1).getPrevPhase());
assertEquals(events.get(1).getNextPhase().getName(), "trial");
assertEquals(events.get(2).getPrevPhase().getName(), "trial");
assertEquals(events.get(2).getNextPhase().getName(), "phase");
assertEquals(events.get(3).getPrevPhase().getName(), "phase");
assertEquals(events.get(3).getNextPhase().getName(), "phase");
assertEquals(events.get(4).getPrevPhase().getName(), "phase");
assertNull(events.get(4).getNextPhase());
assertEquals(events.get(5).getPrevPhase().getName(), "phase");
assertNull(events.get(5).getNextPhase());
}
@Test(groups = "fast")
public void testWithMultipleEntitlements() throws CatalogApiException {
testWithMultipleEntitlementsImpl(false);
}
@Test(groups = "fast")
public void testWithMultipleEntitlementsWithRegression() throws CatalogApiException {
testWithMultipleEntitlementsImpl(true);
}
private void testWithMultipleEntitlementsImpl(final boolean regressionFlagForOlderVersionThan_0_17_X) throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));
final DateTimeZone accountTimeZone = DateTimeZone.UTC;
final UUID accountId = UUID.randomUUID();
final String externalKey = "foo";
final UUID entitlementId1 = UUID.fromString("cf5a597a-cf15-45d3-8f02-95371be7f927");
final UUID entitlementId2 = UUID.fromString("e37cc97a-7b98-4ab6-a29a-7259e45c3366");
final List<SubscriptionBaseTransition> allTransitions1 = new ArrayList<SubscriptionBaseTransition>();
final List<SubscriptionBaseTransition> allTransitions2 = new ArrayList<SubscriptionBaseTransition>();
final List<BlockingState> blockingStatesEnt1 = new ArrayList<BlockingState>();
final List<BlockingState> blockingStatesEnt2 = new ArrayList<BlockingState>();
DateTime effectiveDate = new DateTime(2013, 1, 1, 15, 43, 25, 0, DateTimeZone.UTC);
final SubscriptionBaseTransition ent1Tr1 = createTransition(entitlementId1, EventType.API_USER, ApiEventType.CREATE, effectiveDate, clock.getUTCNow(), null, "trial1");
allTransitions1.add(ent1Tr1);
if (!regressionFlagForOlderVersionThan_0_17_X) {
final BlockingState bsCreate = new DefaultBlockingState(UUID.randomUUID(), entitlementId1, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStatesEnt1.add(bsCreate);
}
effectiveDate = effectiveDate.plusDays(15);
clock.addDays(15);
final SubscriptionBaseTransition ent2Tr1 = createTransition(entitlementId2, EventType.API_USER, ApiEventType.TRANSFER, effectiveDate, clock.getUTCNow(), null, "phase2");
allTransitions2.add(ent2Tr1);
if (!regressionFlagForOlderVersionThan_0_17_X ) {
final BlockingState bsCreate2 = new DefaultBlockingState(UUID.randomUUID(), entitlementId2, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStatesEnt2.add(bsCreate2);
}
effectiveDate = effectiveDate.plusDays(15);
clock.addDays(15);
final SubscriptionBaseTransition ent1Tr2 = createTransition(entitlementId1, EventType.PHASE, null, effectiveDate, clock.getUTCNow(), "trial1", "phase1");
allTransitions1.add(ent1Tr2);
effectiveDate = effectiveDate.plusDays(5);
clock.addDays(5);
final BlockingState bs1 = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE,
DefaultEntitlementApi.ENT_STATE_BLOCKED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStatesEnt1.add(bs1);
blockingStatesEnt2.add(bs1);
effectiveDate = effectiveDate.plusDays(15);
clock.addDays(15);
final SubscriptionBaseTransition ent1Tr3 = createTransition(entitlementId1, EventType.API_USER, ApiEventType.CANCEL, effectiveDate, clock.getUTCNow(), "phase1", null);
allTransitions1.add(ent1Tr3);
final BlockingState bs2 = new DefaultBlockingState(UUID.randomUUID(), entitlementId1, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_CANCELLED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 1L);
blockingStatesEnt1.add(bs2);
final List<Entitlement> entitlements = new ArrayList<Entitlement>();
final Entitlement entitlement1 = createEntitlement(entitlementId1, allTransitions1, blockingStatesEnt1);
entitlements.add(entitlement1);
final Entitlement entitlement2 = createEntitlement(entitlementId2, allTransitions2, blockingStatesEnt2);
entitlements.add(entitlement2);
final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 9);
assertEquals(events.get(0).getEffectiveDate().compareTo(new LocalDate(ent1Tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(1).getEffectiveDate().compareTo(new LocalDate(ent1Tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(2).getEffectiveDate().compareTo(new LocalDate(ent2Tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(3).getEffectiveDate().compareTo(new LocalDate(ent2Tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(4).getEffectiveDate().compareTo(new LocalDate(ent1Tr2.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(5).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(6).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(7).getEffectiveDate().compareTo(new LocalDate(ent1Tr3.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(8).getEffectiveDate().compareTo(new LocalDate(bs2.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(events.get(4).getSubscriptionEventType(), SubscriptionEventType.PHASE);
assertEquals(events.get(5).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
assertEquals(events.get(6).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
assertEquals(events.get(7).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
assertEquals(events.get(8).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
assertEquals(events.get(0).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(1).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(2).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(3).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(4).getServiceName(), EntitlementOrderingBase.ENT_BILLING_SERVICE_NAME);
assertEquals(events.get(5).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(6).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(7).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(8).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertNull(events.get(0).getPrevPhase());
assertEquals(events.get(0).getNextPhase().getName(), "trial1");
assertNull(events.get(1).getPrevPhase());
assertEquals(events.get(1).getNextPhase().getName(), "trial1");
assertNull(events.get(2).getPrevPhase());
assertEquals(events.get(2).getNextPhase().getName(), "phase2");
assertNull(events.get(3).getPrevPhase());
assertEquals(events.get(3).getNextPhase().getName(), "phase2");
assertEquals(events.get(4).getPrevPhase().getName(), "trial1");
assertEquals(events.get(4).getNextPhase().getName(), "phase1");
assertEquals(events.get(5).getPrevPhase().getName(), "phase1");
assertEquals(events.get(5).getNextPhase().getName(), "phase1");
assertEquals(events.get(6).getPrevPhase().getName(), "phase2");
assertEquals(events.get(6).getNextPhase().getName(), "phase2");
assertEquals(events.get(7).getPrevPhase().getName(), "phase1");
assertNull(events.get(7).getNextPhase());
assertEquals(events.get(8).getPrevPhase().getName(), "phase1");
assertNull(events.get(8).getNextPhase());
}
@Test(groups = "fast")
public void testWithOverdueOffline() throws CatalogApiException {
testWithOverdueOfflineImpl(false);
}
@Test(groups = "fast")
public void testWithOverdueOfflineWithRegression() throws CatalogApiException {
testWithOverdueOfflineImpl(true);
}
private void testWithOverdueOfflineImpl(final boolean regressionFlagForOlderVersionThan_0_17_X) throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));
final DateTimeZone accountTimeZone = DateTimeZone.UTC;
final UUID accountId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
final String externalKey = "foo";
final UUID entitlementId = UUID.randomUUID();
final List<SubscriptionBaseTransition> allTransitions = new ArrayList<SubscriptionBaseTransition>();
final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
DateTime effectiveDate = new DateTime(2013, 1, 1, 23, 11, 8, 0, DateTimeZone.UTC);
final SubscriptionBaseTransition tr1 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CREATE, effectiveDate, clock.getUTCNow(), null, "trial");
allTransitions.add(tr1);
if (!regressionFlagForOlderVersionThan_0_17_X) {
final BlockingState bsCreate = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bsCreate);
}
effectiveDate = effectiveDate.plusDays(30);
clock.addDays(30);
final SubscriptionBaseTransition tr2 = createTransition(entitlementId, EventType.PHASE, null, effectiveDate, clock.getUTCNow(), "trial", "phase");
allTransitions.add(tr2);
effectiveDate = effectiveDate.plusDays(40); // 2013-03-12
clock.addDays(40);
final SubscriptionBaseTransition tr3 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CANCEL, effectiveDate, clock.getUTCNow(), "phase", null);
allTransitions.add(tr3);
// Verify the timeline without the blocking state events
final ImmutableList<Entitlement> entitlementsWithoutBlockingStates = ImmutableList.<Entitlement>of(createEntitlement(entitlementId, allTransitions, blockingStates));
final List<SubscriptionEvent> eventsWithoutBlockingStates = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlementsWithoutBlockingStates, internalCallContext).getSubscriptionEvents();
assertEquals(eventsWithoutBlockingStates.size(), 4);
assertEquals(eventsWithoutBlockingStates.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(eventsWithoutBlockingStates.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(eventsWithoutBlockingStates.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
assertEquals(eventsWithoutBlockingStates.get(3).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
final String service = "overdue-service";
final BlockingState bs1 = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.ACCOUNT,
"OFFLINE", service,
true, true, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bs1);
// Verify the timeline with the overdue event blocking the entitlement
final ImmutableList<Entitlement> entitlementsWithOverdueEvent = ImmutableList.<Entitlement>of(createEntitlement(entitlementId, allTransitions, blockingStates));
final List<SubscriptionEvent> eventsWithOverdueEvent = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlementsWithOverdueEvent, internalCallContext).getSubscriptionEvents();
assertEquals(eventsWithOverdueEvent.size(), 5);
assertEquals(eventsWithOverdueEvent.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(eventsWithOverdueEvent.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(eventsWithOverdueEvent.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
assertEquals(eventsWithOverdueEvent.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
assertEquals(eventsWithOverdueEvent.get(4).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
final BlockingState bs2 = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_CANCELLED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 1L);
blockingStates.add(bs2);
final List<Entitlement> entitlements = new ArrayList<Entitlement>();
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
// Verify the timeline with both the overdue event and the entitlement cancel event
final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
assertEquals(timeline.getAccountId(), accountId);
assertEquals(timeline.getBundleId(), bundleId);
assertEquals(timeline.getExternalKey(), externalKey);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 6);
assertEquals(events.get(0).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(1).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(2).getEffectiveDate().compareTo(new LocalDate(tr2.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(3).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(4).getEffectiveDate().compareTo(new LocalDate(tr3.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(5).getEffectiveDate().compareTo(new LocalDate(tr3.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
assertEquals(events.get(4).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
assertEquals(events.get(5).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
assertEquals(events.get(0).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(1).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(2).getServiceName(), EntitlementOrderingBase.ENT_BILLING_SERVICE_NAME);
assertEquals(events.get(3).getServiceName(), service);
assertEquals(events.get(4).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(5).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertNull(events.get(0).getPrevPhase());
assertNull(events.get(1).getPrevPhase());
assertEquals(events.get(1).getNextPhase().getName(), "trial");
assertEquals(events.get(2).getPrevPhase().getName(), "trial");
assertEquals(events.get(2).getNextPhase().getName(), "phase");
assertEquals(events.get(3).getPrevPhase().getName(), "phase");
assertEquals(events.get(3).getNextPhase().getName(), "phase");
assertEquals(events.get(4).getPrevPhase().getName(), "phase");
assertNull(events.get(4).getNextPhase());
assertEquals(events.get(5).getPrevPhase().getName(), "phase");
assertNull(events.get(5).getNextPhase());
}
@Test(groups = "fast", description = "Test for https://github.com/killbill/killbill/issues/134")
public void testRemoveOverlappingBlockingStates() throws CatalogApiException {
testRemoveOverlappingBlockingStatesImpl(false);
}
@Test(groups = "fast")
public void testRemoveOverlappingBlockingStatesWithRegression() throws CatalogApiException {
testRemoveOverlappingBlockingStatesImpl(true);
}
public void testRemoveOverlappingBlockingStatesImpl(final boolean regressionFlagForOlderVersionThan_0_17_X) throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));
final DateTimeZone accountTimeZone = DateTimeZone.UTC;
final UUID accountId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
final String externalKey = "foo";
final UUID entitlementId = UUID.randomUUID();
final List<SubscriptionBaseTransition> allTransitions = new ArrayList<SubscriptionBaseTransition>();
final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
DateTime effectiveDate = new DateTime(2013, 1, 1, 15, 43, 25, 0, DateTimeZone.UTC);
final SubscriptionBaseTransition tr1 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CREATE, effectiveDate, clock.getUTCNow(), null, "trial");
allTransitions.add(tr1);
if (!regressionFlagForOlderVersionThan_0_17_X) {
final BlockingState bsCreate = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bsCreate);
}
// Overlapping ENT_STATE_BLOCKED - should merge
effectiveDate = effectiveDate.plusDays(5);
clock.addDays(5);
final BlockingState bs1 = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_BLOCKED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bs1);
effectiveDate = effectiveDate.plusDays(1);
clock.addDays(1);
final BlockingState bs2 = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE,
DefaultEntitlementApi.ENT_STATE_BLOCKED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 1L);
blockingStates.add(bs2);
// Overlapping ENT_STATE_CANCELLED - should merge
effectiveDate = effectiveDate.plusDays(1);
clock.addDays(1);
final BlockingState bs3 = new DefaultBlockingState(UUID.randomUUID(), accountId, BlockingStateType.ACCOUNT,
DefaultEntitlementApi.ENT_STATE_CANCELLED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 2L);
blockingStates.add(bs3);
final BlockingState bs4 = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE,
DefaultEntitlementApi.ENT_STATE_CANCELLED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 3L);
blockingStates.add(bs4);
final List<Entitlement> entitlements = new ArrayList<Entitlement>();
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 4);
assertEquals(events.get(0).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(1).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(2).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(3).getEffectiveDate().compareTo(new LocalDate(bs3.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
assertEquals(events.get(0).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(1).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(2).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(3).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertNull(events.get(0).getPrevPhase());
assertNull(events.get(1).getPrevPhase());
assertEquals(events.get(1).getNextPhase().getName(), "trial");
assertEquals(events.get(2).getPrevPhase().getName(), "trial");
assertEquals(events.get(2).getNextPhase().getName(), "trial");
assertEquals(events.get(3).getPrevPhase().getName(), "trial");
assertNull(events.get(3).getNextPhase());
}
@Test(groups = "fast", description = "Test for https://github.com/killbill/killbill/issues/149")
public void testVariousBlockingStatesAtTheSameEffectiveDate() throws CatalogApiException {
testVariousBlockingStatesAtTheSameEffectiveDateImpl(false);
}
@Test(groups = "fast")
public void testVariousBlockingStatesAtTheSameEffectiveDateWithRegression() throws CatalogApiException {
testVariousBlockingStatesAtTheSameEffectiveDateImpl(true);
}
private void testVariousBlockingStatesAtTheSameEffectiveDateImpl(final boolean regressionFlagForOlderVersionThan_0_17_X) throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));
final DateTimeZone accountTimeZone = DateTimeZone.UTC;
final UUID accountId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
final String externalKey = "foo";
final UUID entitlementId = UUID.randomUUID();
final List<SubscriptionBaseTransition> allTransitions = new ArrayList<SubscriptionBaseTransition>();
final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
DateTime effectiveDate = new DateTime(2013, 1, 1, 15, 43, 25, 0, DateTimeZone.UTC);
final SubscriptionBaseTransition tr1 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CREATE, effectiveDate, clock.getUTCNow(), null, "trial");
allTransitions.add(tr1);
if (!regressionFlagForOlderVersionThan_0_17_X) {
final BlockingState bsCreate = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
DefaultEntitlementApi.ENT_STATE_START, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bsCreate);
}
// 2013-02-10
effectiveDate = effectiveDate.plusDays(40);
clock.addDays(40);
final BlockingState bs1 = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE,
DefaultEntitlementApi.ENT_STATE_BLOCKED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, true, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 0L);
blockingStates.add(bs1);
// Same timestamp on purpose
final BlockingState bs2 = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE,
DefaultEntitlementApi.ENT_STATE_CLEAR, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 1L);
blockingStates.add(bs2);
// 2013-02-20
effectiveDate = effectiveDate.plusDays(10);
clock.addDays(10);
final BlockingState bs3 = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE,
DefaultEntitlementApi.ENT_STATE_BLOCKED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
true, true, true, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 2L);
blockingStates.add(bs3);
// 2013-03-02
effectiveDate = effectiveDate.plusDays(10);
clock.addDays(10);
final BlockingState bs4 = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE,
DefaultEntitlementApi.ENT_STATE_CLEAR, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 3L);
blockingStates.add(bs4);
final String overdueService = "overdue-service";
// 2013-03-04
effectiveDate = effectiveDate.plusDays(2);
clock.addDays(2);
final BlockingState bs5 = new DefaultBlockingState(UUID.randomUUID(), accountId, BlockingStateType.ACCOUNT,
"OD1", overdueService,
false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow(), 4L);
blockingStates.add(bs5);
final List<Entitlement> entitlements = new ArrayList<Entitlement>();
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 11);
assertEquals(events.get(0).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(1).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
assertEquals(events.get(2).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(3).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(4).getEffectiveDate().compareTo(new LocalDate(bs2.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(5).getEffectiveDate().compareTo(new LocalDate(bs2.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(6).getEffectiveDate().compareTo(new LocalDate(bs3.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(7).getEffectiveDate().compareTo(new LocalDate(bs3.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(8).getEffectiveDate().compareTo(new LocalDate(bs4.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(9).getEffectiveDate().compareTo(new LocalDate(bs4.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(10).getEffectiveDate().compareTo(new LocalDate(bs5.getEffectiveDate(), accountTimeZone)), 0);
assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
assertEquals(events.get(4).getSubscriptionEventType(), SubscriptionEventType.RESUME_ENTITLEMENT);
assertEquals(events.get(5).getSubscriptionEventType(), SubscriptionEventType.RESUME_BILLING);
assertEquals(events.get(6).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
assertEquals(events.get(7).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
assertEquals(events.get(8).getSubscriptionEventType(), SubscriptionEventType.RESUME_ENTITLEMENT);
assertEquals(events.get(9).getSubscriptionEventType(), SubscriptionEventType.RESUME_BILLING);
assertEquals(events.get(10).getSubscriptionEventType(), SubscriptionEventType.SERVICE_STATE_CHANGE);
assertEquals(events.get(0).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(1).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(2).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(3).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(4).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(5).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(6).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(7).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(8).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(9).getServiceName(), EntitlementOrderingBase.BILLING_SERVICE_NAME);
assertEquals(events.get(10).getServiceName(), overdueService);
assertNull(events.get(0).getPrevPhase());
assertNull(events.get(1).getPrevPhase());
assertEquals(events.get(1).getNextPhase().getName(), "trial");
assertEquals(events.get(2).getPrevPhase().getName(), "trial");
assertEquals(events.get(2).getNextPhase().getName(), "trial");
assertEquals(events.get(3).getPrevPhase().getName(), "trial");
assertEquals(events.get(3).getNextPhase().getName(), "trial");
assertEquals(events.get(4).getPrevPhase().getName(), "trial");
assertEquals(events.get(4).getNextPhase().getName(), "trial");
assertEquals(events.get(5).getPrevPhase().getName(), "trial");
assertEquals(events.get(5).getNextPhase().getName(), "trial");
assertEquals(events.get(6).getPrevPhase().getName(), "trial");
assertEquals(events.get(6).getNextPhase().getName(), "trial");
assertEquals(events.get(7).getPrevPhase().getName(), "trial");
assertEquals(events.get(7).getNextPhase().getName(), "trial");
assertEquals(events.get(8).getPrevPhase().getName(), "trial");
assertEquals(events.get(8).getNextPhase().getName(), "trial");
assertEquals(events.get(9).getPrevPhase().getName(), "trial");
assertEquals(events.get(9).getNextPhase().getName(), "trial");
assertEquals(events.get(10).getPrevPhase().getName(), "trial");
assertEquals(events.get(10).getNextPhase().getName(), "trial");
}
private Entitlement createEntitlement(final UUID entitlementId, final List<SubscriptionBaseTransition> allTransitions, final Collection<BlockingState> blockingStates) {
final DefaultEntitlement result = Mockito.mock(DefaultEntitlement.class);
Mockito.when(result.getId()).thenReturn(entitlementId);
final EventsStream eventsStream = Mockito.mock(EventsStream.class);
Mockito.when(eventsStream.getBlockingStates()).thenReturn(blockingStates);
Mockito.when(result.getEventsStream()).thenReturn(eventsStream);
final SubscriptionBase base = Mockito.mock(SubscriptionBase.class);
Mockito.when(base.getAllTransitions()).thenReturn(allTransitions);
Mockito.when(result.getSubscriptionBase()).thenReturn(base);
Mockito.when(result.getSubscriptionBase().getStartDate()).thenReturn(new DateTime(DateTimeZone.UTC));
return result;
}
private SubscriptionBaseTransition createTransition(final UUID entitlementId,
final EventType eventType,
final ApiEventType apiEventType,
final DateTime effectiveDate,
final DateTime createdDate,
final String prevPhaseName,
final String nextPhaseName
) throws CatalogApiException {
final PlanPhase prevPhase;
final Plan prevPlan;
final Product prevProduct;
final PriceList prevPriceList;
if (prevPhaseName == null) {
prevPhase = null;
prevPlan = null;
prevProduct = null;
prevPriceList = null;
} else {
prevPhase = Mockito.mock(PlanPhase.class);
Mockito.when(prevPhase.getName()).thenReturn(prevPhaseName);
prevProduct = Mockito.mock(Product.class);
Mockito.when(prevProduct.getName()).thenReturn("product");
prevPlan = Mockito.mock(Plan.class);
Mockito.when(prevPlan.getName()).thenReturn("plan");
Mockito.when(prevPlan.getProduct()).thenReturn(prevProduct);
prevPriceList = Mockito.mock(PriceList.class);
Mockito.when(prevPriceList.getName()).thenReturn("pricelist");
}
final PlanPhase nextPhase;
final Plan nextPlan;
final Product nextProduct;
final PriceList nextPriceList;
if (nextPhaseName == null) {
nextPhase = null;
nextPlan = null;
nextProduct = null;
nextPriceList = null;
} else {
nextPhase = Mockito.mock(PlanPhase.class);
Mockito.when(nextPhase.getName()).thenReturn(nextPhaseName);
nextProduct = Mockito.mock(Product.class);
Mockito.when(nextProduct.getName()).thenReturn("product");
nextPlan = Mockito.mock(Plan.class);
Mockito.when(nextPlan.getName()).thenReturn("plan");
Mockito.when(nextPlan.getProduct()).thenReturn(nextProduct);
nextPriceList = Mockito.mock(PriceList.class);
Mockito.when(nextPriceList.getName()).thenReturn("pricelist");
}
return new SubscriptionBaseTransitionData(UUID.randomUUID(),
entitlementId,
bundleId,
bundleExternalKey,
eventType,
apiEventType,
effectiveDate,
null,
null,
null,
prevPlan,
prevPhase,
prevPriceList,
null,
null,
null,
null,
nextPlan,
nextPhase,
nextPriceList,
null,
1L,
createdDate,
UUID.randomUUID(),
true);
}
}