killbill-aplcache
Changes
entitlement/killbill-entitlement.iml 3(+2 -1)
entitlement/pom.xml 11(+11 -0)
entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java 39(+38 -1)
entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestListenerStatus.java 43(+43 -0)
entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java 121(+117 -4)
entitlement/src/test/java/com/ning/billing/entitlement/glue/TestEntitlementModuleWithEmbeddedDB.java 12(+12 -0)
entitlement/src/test/resources/catalog.xml 828(+828 -0)
Details
entitlement/killbill-entitlement.iml 3(+2 -1)
diff --git a/entitlement/killbill-entitlement.iml b/entitlement/killbill-entitlement.iml
index 6a94abc..5f378db 100644
--- a/entitlement/killbill-entitlement.iml
+++ b/entitlement/killbill-entitlement.iml
@@ -4,10 +4,10 @@
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
- <sourceFolder url="file://$MODULE_DIR$/src/test/resources" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test/resources" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
@@ -52,6 +52,7 @@
<orderEntry type="module" module-name="killbill-catalog" scope="TEST" />
<orderEntry type="module" module-name="killbill-util" scope="TEST" production-on-test="" />
<orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-util:test-jar:tests:0.3.6-SNAPSHOT" level="project" />
+ <orderEntry type="module" module-name="killbill-subscription" scope="TEST" />
<orderEntry type="library" scope="TEST" name="Maven: com.ning.billing.commons:killbill-clock:test-jar:tests:0.1.7" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.ning.billing.commons:killbill-queue:test-jar:tests:0.1.7" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: mysql:mysql-connector-mxj:5.0.12" level="project" />
entitlement/pom.xml 11(+11 -0)
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index 4d4195a..f7a3164 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -79,6 +79,17 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-util</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-subscription</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>com.ning.billing.commons</groupId>
<artifactId>killbill-clock</artifactId>
</dependency>
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java
index d3809bd..f08808b 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java
@@ -1,4 +1,41 @@
package com.ning.billing.entitlement.api;
-public class TestDefaultEntitlementApi {
+import java.util.UUID;
+
+import org.mockito.Mockito;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.entitlement.EntitlementTestSuiteWithEmbeddedDB;
+import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.callcontext.TenantContext;
+
+
+public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedDB {
+
+ @Test(groups = "slow")
+ public void test1() {
+
+ try {
+ final UUID accountId = UUID.randomUUID();
+ final String externalKey = "externalKey";
+ final Account account = Mockito.mock(Account.class);
+ Mockito.when(account.getId()).thenReturn(accountId);
+ Mockito.when(accountInternalApi.getAccountById(Mockito.<UUID>any(), Mockito.<InternalTenantContext>any())).thenReturn(account);
+
+ final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+ entitlementApi.createBaseEntitlement(accountId, spec, externalKey, callContext);
+ } catch (EntitlementApiException e) {
+ Assert.fail("Test failed " + e.getMessage());
+ } catch (AccountApiException e) {
+ Assert.fail("Test failed " + e.getMessage());
+ }
+ }
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestListenerStatus.java b/entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestListenerStatus.java
new file mode 100644
index 0000000..05c0c6e
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestListenerStatus.java
@@ -0,0 +1,43 @@
+package com.ning.billing.entitlement;
+
+import javax.inject.Inject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+
+import com.ning.billing.api.TestListenerStatus;
+
+public class EntitlementTestListenerStatus implements TestListenerStatus {
+
+ private final Logger log = LoggerFactory.getLogger(EntitlementTestListenerStatus.class);
+
+ private boolean isListenerFailed;
+ private String listenerFailedMsg;
+
+
+ @Inject
+ public EntitlementTestListenerStatus() {
+ isListenerFailed = false;
+ }
+
+
+ @Override
+ public void failed(final String msg) {
+ this.isListenerFailed = true;
+ this.listenerFailedMsg = msg;
+ }
+
+ @Override
+ public void resetTestListenerStatus() {
+ this.isListenerFailed = false;
+ this.listenerFailedMsg = null;
+ }
+
+ public void assertListenerStatus() {
+ if (isListenerFailed) {
+ log.error(listenerFailedMsg);
+ Assert.fail(listenerFailedMsg);
+ }
+ }
+}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java b/entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
index 8a26360..a6d9a85 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
@@ -16,33 +16,54 @@
package com.ning.billing.entitlement;
+import java.net.URL;
+
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import com.ning.billing.GuicyKillbillTestSuiteWithEmbeddedDB;
+import com.ning.billing.api.TestApiListener;
+import com.ning.billing.api.TestListenerStatus;
import com.ning.billing.bus.api.PersistentBus;
+import com.ning.billing.catalog.DefaultCatalogService;
+import com.ning.billing.catalog.api.Catalog;
import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.clock.ClockMock;
+import com.ning.billing.entitlement.api.EntitlementApi;
import com.ning.billing.entitlement.dao.BlockingStateDao;
import com.ning.billing.entitlement.glue.TestEntitlementModuleWithEmbeddedDB;
+import com.ning.billing.subscription.api.SubscriptionBaseService;
+import com.ning.billing.subscription.engine.core.DefaultSubscriptionBaseService;
import com.ning.billing.util.svcapi.account.AccountInternalApi;
import com.ning.billing.util.svcapi.junction.BlockingInternalApi;
import com.ning.billing.util.svcapi.subscription.SubscriptionBaseInternalApi;
import com.ning.billing.util.svcapi.tag.TagInternalApi;
+import com.ning.billing.util.svcsapi.bus.BusService;
import com.ning.billing.util.tag.dao.TagDao;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
+import com.google.inject.Stage;
+
+import static org.testng.Assert.assertNotNull;
public class EntitlementTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteWithEmbeddedDB {
+ protected static final Logger log = LoggerFactory.getLogger(EntitlementTestSuiteWithEmbeddedDB.class);
@Inject
protected AccountInternalApi accountInternalApi;
@Inject
protected BlockingInternalApi blockingInternalApi;
@Inject
+ protected EntitlementApi entitlementApi;
+ @Inject
protected BlockingStateDao blockingStateDao;
@Inject
protected CatalogService catalogService;
@@ -54,21 +75,113 @@ public class EntitlementTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteWi
protected TagDao tagDao;
@Inject
protected TagInternalApi tagInternalApi;
+ @javax.inject.Inject
+ protected TestApiListener testListener;
+ @javax.inject.Inject
+ protected TestListenerStatus testListenerStatus;
+ @javax.inject.Inject
+ protected BusService busService;
+ @javax.inject.Inject
+ protected SubscriptionBaseService subscriptionBaseService;
+
+ protected Catalog catalog;
+
+ private void loadSystemPropertiesFromClasspath(final String resource) {
+ final URL url = EntitlementTestSuiteWithEmbeddedDB.class.getResource(resource);
+ Assert.assertNotNull(url);
+
+ configSource.merge(url);
+ }
@BeforeClass(groups = "slow")
protected void beforeClass() throws Exception {
- final Injector injector = Guice.createInjector(new TestEntitlementModuleWithEmbeddedDB(configSource));
+ loadSystemPropertiesFromClasspath("/entitlement.properties");
+ final Injector injector = Guice.createInjector(Stage.PRODUCTION, new TestEntitlementModuleWithEmbeddedDB(configSource));
injector.injectMembers(this);
}
@BeforeMethod(groups = "slow")
public void beforeMethod() throws Exception {
super.beforeMethod();
- bus.start();
+ startTestFamework(testListener, testListenerStatus, clock, busService, subscriptionBaseService);
+ this.catalog = initCatalog(catalogService);
}
@AfterMethod(groups = "slow")
- public void afterMethod() {
- bus.stop();
+ public void afterMethod() throws Exception {
+ stopTestFramework(testListener, busService, subscriptionBaseService);
+ }
+
+ private Catalog initCatalog(final CatalogService catalogService) throws Exception {
+
+ ((DefaultCatalogService) catalogService).loadCatalog();
+ final Catalog catalog = catalogService.getFullCatalog();
+ assertNotNull(catalog);
+ return catalog;
+ }
+
+
+ private void startTestFamework(final TestApiListener testListener,
+ final TestListenerStatus testListenerStatus,
+ final ClockMock clock,
+ final BusService busService,
+ final SubscriptionBaseService subscriptionBaseService) throws Exception {
+ log.warn("STARTING TEST FRAMEWORK");
+
+ resetTestListener(testListener, testListenerStatus);
+
+ resetClockToStartOfTest(clock);
+
+ startBusAndRegisterListener(busService, testListener);
+
+ restartSubscriptionService(subscriptionBaseService);
+
+ log.warn("STARTED TEST FRAMEWORK");
+ }
+
+
+ private void stopTestFramework(final TestApiListener testListener,
+ final BusService busService,
+ final SubscriptionBaseService subscriptionBaseService) throws Exception {
+ log.warn("STOPPING TEST FRAMEWORK");
+ stopBusAndUnregisterListener(busService, testListener);
+ stopSubscriptionService(subscriptionBaseService);
+ log.warn("STOPPED TEST FRAMEWORK");
+ }
+
+ private void resetTestListener(final TestApiListener testListener, final TestListenerStatus testListenerStatus) {
+ // RESET LIST OF EXPECTED EVENTS
+ if (testListener != null) {
+ testListener.reset();
+ testListenerStatus.resetTestListenerStatus();
+ }
+ }
+
+ private void resetClockToStartOfTest(final ClockMock clock) {
+ clock.resetDeltaFromReality();
+
+ // Date at which all tests start-- we create the date object here after the system properties which set the JVM in UTC have been set.
+ final DateTime testStartDate = new DateTime(2012, 5, 7, 0, 3, 42, 0);
+ clock.setDeltaFromReality(testStartDate.getMillis() - clock.getUTCNow().getMillis());
+ }
+
+ private void startBusAndRegisterListener(final BusService busService, final TestApiListener testListener) throws Exception {
+ busService.getBus().start();
+ busService.getBus().register(testListener);
+ }
+
+ private void restartSubscriptionService(final SubscriptionBaseService subscriptionBaseService) {
+ // START NOTIFICATION QUEUE FOR SUBSCRIPTION
+ ((DefaultSubscriptionBaseService) subscriptionBaseService).initialize();
+ ((DefaultSubscriptionBaseService) subscriptionBaseService).start();
+ }
+
+ private void stopBusAndUnregisterListener(final BusService busService, final TestApiListener testListener) throws Exception {
+ busService.getBus().unregister(testListener);
+ busService.getBus().stop();
+ }
+
+ private void stopSubscriptionService(final SubscriptionBaseService subscriptionBaseService) throws Exception {
+ ((DefaultSubscriptionBaseService) subscriptionBaseService).stop();
}
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/TestEntitlementModule.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/TestEntitlementModule.java
index 7ae3800..96d7152 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/TestEntitlementModule.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/TestEntitlementModule.java
@@ -19,6 +19,7 @@ package com.ning.billing.entitlement.glue;
import com.ning.billing.catalog.MockCatalogModule;
import com.ning.billing.mock.glue.MockAccountModule;
import com.ning.billing.mock.glue.MockSubscriptionModule;
+import com.ning.billing.subscription.glue.DefaultSubscriptionModule;
import com.ning.billing.util.glue.CacheModule;
import com.ning.billing.util.glue.CallContextModule;
import org.skife.config.ConfigSource;
@@ -38,8 +39,5 @@ public class TestEntitlementModule extends DefaultEntitlementModule {
install(new CacheModule(configSource));
install(new CallContextModule());
install(new MockAccountModule());
- install(new MockCatalogModule());
- install(new MockSubscriptionModule());
-
}
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/TestEntitlementModuleNoDB.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/TestEntitlementModuleNoDB.java
index aff1d31..579a606 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/TestEntitlementModuleNoDB.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/TestEntitlementModuleNoDB.java
@@ -17,9 +17,11 @@
package com.ning.billing.entitlement.glue;
import com.ning.billing.GuicyKillbillTestNoDBModule;
+import com.ning.billing.catalog.MockCatalogModule;
import com.ning.billing.entitlement.dao.BlockingStateDao;
import com.ning.billing.entitlement.dao.MockBlockingStateDao;
import com.ning.billing.mock.glue.MockNonEntityDaoModule;
+import com.ning.billing.mock.glue.MockSubscriptionModule;
import com.ning.billing.mock.glue.MockTagModule;
import com.ning.billing.util.bus.InMemoryBusModule;
import org.skife.config.ConfigSource;
@@ -37,6 +39,8 @@ public class TestEntitlementModuleNoDB extends TestEntitlementModule {
install(new MockNonEntityDaoModule());
install(new InMemoryBusModule(configSource));
install(new MockTagModule());
+ install(new MockSubscriptionModule());
+ install(new MockCatalogModule());
}
@Override
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/TestEntitlementModuleWithEmbeddedDB.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/TestEntitlementModuleWithEmbeddedDB.java
index a81c8ae..20f7401 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/TestEntitlementModuleWithEmbeddedDB.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/TestEntitlementModuleWithEmbeddedDB.java
@@ -17,8 +17,14 @@
package com.ning.billing.entitlement.glue;
import com.ning.billing.GuicyKillbillTestWithEmbeddedDBModule;
+import com.ning.billing.api.TestApiListener;
+import com.ning.billing.api.TestListenerStatus;
+import com.ning.billing.catalog.glue.CatalogModule;
+import com.ning.billing.entitlement.EntitlementTestListenerStatus;
+import com.ning.billing.subscription.glue.DefaultSubscriptionModule;
import com.ning.billing.util.glue.BusModule;
import com.ning.billing.util.glue.NonEntityDaoModule;
+import com.ning.billing.util.glue.NotificationQueueModule;
import com.ning.billing.util.glue.TagStoreModule;
import org.skife.config.ConfigSource;
@@ -35,5 +41,11 @@ public class TestEntitlementModuleWithEmbeddedDB extends TestEntitlementModule {
install(new NonEntityDaoModule());
install(new BusModule(configSource));
install(new TagStoreModule());
+ install(new CatalogModule(configSource));
+ install(new NotificationQueueModule(configSource));
+ install(new DefaultSubscriptionModule(configSource));
+
+ bind(TestListenerStatus.class).to(EntitlementTestListenerStatus.class).asEagerSingleton();
+ bind(TestApiListener.class).asEagerSingleton();
}
}
entitlement/src/test/resources/catalog.xml 828(+828 -0)
diff --git a/entitlement/src/test/resources/catalog.xml b/entitlement/src/test/resources/catalog.xml
new file mode 100644
index 0000000..973afd0
--- /dev/null
+++ b/entitlement/src/test/resources/catalog.xml
@@ -0,0 +1,828 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- ~ Copyright 2010-2011 Ning, Inc. ~ ~ Ning 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. -->
+
+<!-- Use cases covered so far: Tiered Product (Pistol/Shotgun/Assault-Rifle)
+ Multiple changeEvent plan policies Multiple PlanAlignment (see below, trial
+ add-on alignments and rescue discount package) Product transition rules Add
+ on (Scopes, Hoster) Multi-pack addon (Extra-Ammo) Addon Trial aligned to
+ base plan (holster-monthly-regular) Addon Trial aligned to creation (holster-monthly-special)
+ Rescue discount package (assault-rifle-annual-rescue) Plan phase with a reccurring
+ and a one off (refurbish-maintenance) Phan with more than 2 phase (gunclub
+ discount plans) Use Cases to do: Tiered Add On Riskfree period -->
+<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="CatalogSchema.xsd ">
+
+ <effectiveDate>2011-01-01T00:00:00+00:00</effectiveDate>
+ <catalogName>Firearms</catalogName>
+
+ <currencies>
+ <currency>USD</currency>
+ <currency>EUR</currency>
+ <currency>GBP</currency>
+ </currencies>
+
+ <products>
+ <product name="Pistol">
+ <category>BASE</category>
+ </product>
+ <product name="Shotgun">
+ <category>BASE</category>
+ <available>
+ <addonProduct>Telescopic-Scope</addonProduct>
+ <addonProduct>Laser-Scope</addonProduct>
+ </available>
+ </product>
+ <product name="Assault-Rifle">
+ <category>BASE</category>
+ <included>
+ <addonProduct>Telescopic-Scope</addonProduct>
+ </included>
+ <available>
+ <addonProduct>Laser-Scope</addonProduct>
+ </available>
+ </product>
+ <product name="Telescopic-Scope">
+ <category>ADD_ON</category>
+ </product>
+ <product name="Laser-Scope">
+ <category>ADD_ON</category>
+ </product>
+ <product name="Holster">
+ <category>ADD_ON</category>
+ </product>
+ <product name="Extra-Ammo">
+ <category>ADD_ON</category>
+ </product>
+ <product name="Refurbish-Maintenance">
+ <category>ADD_ON</category>
+ </product>
+ </products>
+
+ <rules>
+ <changePolicy>
+ <changePolicyCase>
+ <phaseType>TRIAL</phaseType>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <toPriceList>rescue</toPriceList>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <toProduct>Assault-Rifle</toProduct>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <fromProduct>Pistol</fromProduct>
+ <toProduct>Shotgun</toProduct>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <fromBillingPeriod>MONTHLY</fromBillingPeriod>
+ <toBillingPeriod>ANNUAL</toBillingPeriod>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <fromBillingPeriod>ANNUAL</fromBillingPeriod>
+ <toBillingPeriod>MONTHLY</toBillingPeriod>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
+ </changePolicy>
+ <changeAlignment>
+ <changeAlignmentCase>
+ <toPriceList>rescue</toPriceList>
+ <alignment>CHANGE_OF_PLAN</alignment>
+ </changeAlignmentCase>
+ <changeAlignmentCase>
+ <fromPriceList>rescue</fromPriceList>
+ <toPriceList>rescue</toPriceList>
+ <alignment>CHANGE_OF_PRICELIST</alignment>
+ </changeAlignmentCase>
+ <changeAlignmentCase>
+ <alignment>START_OF_SUBSCRIPTION</alignment>
+ </changeAlignmentCase>
+ </changeAlignment>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <phaseType>TRIAL</phaseType>
+ <policy>IMMEDIATE</policy>
+ </cancelPolicyCase>
+ <cancelPolicyCase>
+ <policy>END_OF_TERM</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
+ <createAlignment>
+ <createAlignmentCase>
+ <product>Laser-Scope</product>
+ <alignment>START_OF_SUBSCRIPTION</alignment>
+ </createAlignmentCase>
+ <createAlignmentCase>
+ <alignment>START_OF_BUNDLE</alignment>
+ </createAlignmentCase>
+ </createAlignment>
+ <billingAlignment>
+ <billingAlignmentCase>
+ <productCategory>ADD_ON</productCategory>
+ <alignment>BUNDLE</alignment>
+ </billingAlignmentCase>
+ <billingAlignmentCase>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <alignment>SUBSCRIPTION</alignment>
+ </billingAlignmentCase>
+ <billingAlignmentCase>
+ <alignment>ACCOUNT</alignment>
+ </billingAlignmentCase>
+ </billingAlignment>
+ <priceList>
+ <priceListCase>
+ <fromPriceList>rescue</fromPriceList>
+ <toPriceList>DEFAULT</toPriceList>
+ </priceListCase>
+ </priceList>
+ </rules>
+
+ <plans>
+ <plan name="pistol-monthly">
+ <product>Pistol</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice> <!-- empty price implies $0 -->
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>GBP</currency>
+ <value>29.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>29.95</value>
+ </price>
+ <price>
+ <currency>USD</currency>
+ <value>29.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="shotgun-monthly">
+ <product>Shotgun</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice></fixedPrice>
+ <!-- no price implies $0 -->
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ <number>-1</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>249.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>149.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>169.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="assault-rifle-monthly">
+ <product>Assault-Rifle</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>599.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>349.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>399.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="pistol-annual">
+ <product>Pistol</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>199.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>199.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>199.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="shotgun-annual">
+ <product>Shotgun</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>2399.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>1499.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>1699.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="assault-rifle-annual">
+ <product>Assault-Rifle</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>5999.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>3499.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>3999.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="pistol-annual-gunclub-discount">
+ <product>Pistol</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>6</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>9.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>9.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>9.95</value>
+ </price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>199.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>199.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>199.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="shotgun-annual-gunclub-discount">
+ <product>Shotgun</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>6</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>19.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>49.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>69.95</value>
+ </price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>2399.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>1499.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>1699.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="assault-rifle-annual-gunclub-discount">
+ <product>Assault-Rifle</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>6</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>99.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>99.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>99.95</value>
+ </price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>5999.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>3499.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>3999.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="laser-scope-monthly">
+ <product>Laser-Scope</product>
+ <initialPhases>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>1</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>999.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>499.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>999.95</value>
+ </price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>1999.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>1499.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>1999.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="telescopic-scope-monthly">
+ <product>Telescopic-Scope</product>
+ <initialPhases>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>1</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>399.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>299.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>399.95</value>
+ </price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>999.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>499.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>999.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="extra-ammo-monthly">
+ <product>Extra-Ammo</product>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>999.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>499.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>999.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ <plansAllowedInBundle>-1</plansAllowedInBundle> <!-- arbitrary number of these (multipack) -->
+ </plan>
+ <plan name="holster-monthly-regular">
+ <product>Holster</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>199.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>199.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>199.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="holster-monthly-special">
+ <product>Holster</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>199.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>199.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>199.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="assault-rifle-annual-rescue">
+ <product>Assault-Rifle</product>
+ <initialPhases>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>YEARS</unit>
+ <number>1</number>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>5999.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>3499.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>3999.95</value>
+ </price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>5999.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>3499.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>3999.95</value>
+ </price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="refurbish-maintenance">
+ <product>Refurbish-Maintenance</product>
+ <finalPhase type="FIXEDTERM">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>12</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>199.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>199.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>199.95</value>
+ </price>
+ </recurringPrice>
+ <fixedPrice>
+ <price>
+ <currency>USD</currency>
+ <value>599.95</value>
+ </price>
+ <price>
+ <currency>EUR</currency>
+ <value>599.95</value>
+ </price>
+ <price>
+ <currency>GBP</currency>
+ <value>599.95</value>
+ </price>
+ </fixedPrice>
+ </finalPhase>
+ </plan>
+ </plans>
+ <priceLists>
+ <defaultPriceList name="DEFAULT">
+ <plans>
+ <plan>pistol-monthly</plan>
+ <plan>shotgun-monthly</plan>
+ <plan>assault-rifle-monthly</plan>
+ <plan>pistol-annual</plan>
+ <plan>shotgun-annual</plan>
+ <plan>assault-rifle-annual</plan>
+ <plan>laser-scope-monthly</plan>
+ <plan>telescopic-scope-monthly</plan>
+ <plan>extra-ammo-monthly</plan>
+ <plan>holster-monthly-regular</plan>
+ <plan>refurbish-maintenance</plan>
+ </plans>
+ </defaultPriceList>
+ <childPriceList name="gunclubDiscount">
+ <plans>
+ <plan>pistol-monthly</plan>
+ <plan>shotgun-monthly</plan>
+ <plan>assault-rifle-monthly</plan>
+ <plan>pistol-annual-gunclub-discount</plan>
+ <plan>shotgun-annual-gunclub-discount</plan>
+ <plan>assault-rifle-annual-gunclub-discount</plan>
+ <plan>holster-monthly-special</plan>
+ </plans>
+ </childPriceList>
+ <childPriceList name="rescue">
+ <plans>
+ <plan>assault-rifle-annual-rescue</plan>
+ </plans>
+ </childPriceList>
+ </priceLists>
+
+</catalog>
diff --git a/entitlement/src/test/resources/entitlement.properties b/entitlement/src/test/resources/entitlement.properties
new file mode 100644
index 0000000..ede26d9
--- /dev/null
+++ b/entitlement/src/test/resources/entitlement.properties
@@ -0,0 +1,5 @@
+killbill.catalog.uri=file:src/test/resources/catalog.xml
+killbill.billing.persistent.bus.sleep=100
+killbill.billing.persistent.bus.nbThreads=1
+killbill.billing.persistent.bus.claimed=1
+user.timezone=UTC