killbill-aplcache
Changes
beatrix/pom.xml 10(+10 -0)
beatrix/src/test/resources/catalogSample.xml 624(+624 -0)
pom.xml 6(+6 -0)
Details
diff --git a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
index 6ec95b9..4518731 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
@@ -21,6 +21,8 @@ import com.ning.billing.analytics.setup.AnalyticsModule;
import com.ning.billing.catalog.glue.CatalogModule;
import com.ning.billing.dbi.MysqlTestingHelper;
import com.ning.billing.entitlement.glue.EntitlementModule;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.DefaultClock;
import com.ning.billing.util.glue.EventBusModule;
import com.ning.billing.util.glue.NotificationQueueModule;
import com.ning.billing.util.glue.TagStoreModule;
@@ -42,6 +44,8 @@ public class AnalyticsTestModule extends AnalyticsModule
install(new TagStoreModule());
install(new NotificationQueueModule());
+ bind(Clock.class).to(DefaultClock.class).asEagerSingleton();
+
// Install the Dao layer
final MysqlTestingHelper helper = new MysqlTestingHelper();
bind(MysqlTestingHelper.class).toInstance(helper);
beatrix/pom.xml 10(+10 -0)
diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index 32ceef9..e0e4352 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -28,6 +28,10 @@
<groupId>com.ning.billing</groupId>
<artifactId>killbill-entitlement</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-invoice</artifactId>
+ </dependency>
<dependency>
<groupId>com.ning.billing</groupId>
<artifactId>killbill-catalog</artifactId>
@@ -78,6 +82,12 @@
<artifactId>commons-io</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-util</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
diff --git a/beatrix/src/main/java/com/ning/billing/beatrix/glue/BeatrixModule.java b/beatrix/src/main/java/com/ning/billing/beatrix/glue/BeatrixModule.java
index 7a672c1..02da6c9 100644
--- a/beatrix/src/main/java/com/ning/billing/beatrix/glue/BeatrixModule.java
+++ b/beatrix/src/main/java/com/ning/billing/beatrix/glue/BeatrixModule.java
@@ -17,13 +17,14 @@
package com.ning.billing.beatrix.glue;
import com.google.inject.AbstractModule;
+import com.ning.billing.beatrix.lifecycle.DefaultLifecycle;
import com.ning.billing.beatrix.lifecycle.Lifecycle;
public class BeatrixModule extends AbstractModule {
@Override
protected void configure() {
- bind(Lifecycle.class).asEagerSingleton();
+ bind(Lifecycle.class).to(DefaultLifecycle.class).asEagerSingleton();
}
}
diff --git a/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/DefaultLifecycle.java b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/DefaultLifecycle.java
new file mode 100644
index 0000000..87075a9
--- /dev/null
+++ b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/DefaultLifecycle.java
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+package com.ning.billing.beatrix.lifecycle;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.ning.billing.lifecycle.KillbillService;
+import com.ning.billing.lifecycle.LifecycleHandlerType;
+import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
+import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel.Sequence;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+
+public class DefaultLifecycle implements Lifecycle {
+
+ private final static Logger log = LoggerFactory.getLogger(DefaultLifecycle.class);
+ private final SetMultimap<LifecycleLevel, LifecycleHandler<? extends KillbillService>> handlersByLevel;
+
+ private final ServiceFinder serviceFinder;
+
+ protected final Injector injector;
+
+ @Inject
+ public DefaultLifecycle(Injector injector) {
+
+ this.serviceFinder = new ServiceFinder(DefaultLifecycle.class.getClassLoader());
+ this.handlersByLevel = Multimaps.newSetMultimap(new ConcurrentHashMap<LifecycleLevel, Collection<LifecycleHandler<? extends KillbillService>>>(),
+
+ new Supplier<Set<LifecycleHandler<? extends KillbillService>>>() {
+ @Override
+ public Set<LifecycleHandler<? extends KillbillService>> get() {
+ return new CopyOnWriteArraySet<LifecycleHandler<? extends KillbillService>>();
+ }
+ });
+ this.injector = injector;
+
+ init();
+ }
+
+
+ @Override
+ public void fireStartupSequencePriorEventRegistration() {
+ fireSequence(Sequence.STARTUP_PRE_EVENT_REGISTRATION);
+ }
+
+ @Override
+ public void fireStartupSequencePostEventRegistration() {
+ fireSequence(Sequence.STARTUP_POST_EVENT_REGISTRATION);
+ }
+
+ @Override
+ public void fireShutdownSequencePriorEventUnRegistration() {
+ fireSequence(Sequence.SHUTDOWN_PRE_EVENT_UNREGISTRATION);
+ }
+
+ @Override
+ public void fireShutdownSequencePostEventUnRegistration() {
+ fireSequence(Sequence.SHUTDOWN_POST_EVENT_UNREGISTRATION);
+ }
+
+ protected Set<? extends KillbillService> findServices() {
+
+ Set<KillbillService> result = new HashSet<KillbillService>();
+ Set<Class<? extends KillbillService>> services = serviceFinder.getServices();
+ for (Class<? extends KillbillService> cur : services) {
+ log.debug("Found service {}", cur.getName());
+ try {
+ KillbillService instance = injector.getInstance(cur);
+ log.debug("got instance {}", instance.getName());
+ result.add(instance);
+ } catch (Exception e) {
+ logWarn("Failed to inject " + cur.getName(), e);
+ }
+
+ }
+ return result;
+ }
+
+ private void init() {
+ Set<? extends KillbillService> services = findServices();
+ Iterator<? extends KillbillService> it = services.iterator();
+ while (it.hasNext()) {
+ handlersByLevel.putAll(findAllHandlers(it.next()));
+ }
+ }
+
+ private void fireSequence(Sequence seq) {
+ List<LifecycleLevel> levels = LifecycleLevel.getLevelsForSequence(seq);
+ for (LifecycleLevel cur : levels) {
+ doFireStage(cur);
+ }
+ }
+
+ private void doFireStage(LifecycleLevel level) {
+ log.info("Killbill lifecycle firing stage {}", level);
+ Set<LifecycleHandler<? extends KillbillService>> handlers = handlersByLevel.get(level);
+ for (LifecycleHandler<? extends KillbillService> cur : handlers) {
+
+ try {
+ Method method = cur.getMethod();
+ KillbillService target = cur.getTarget();
+ log.info("Killbill lifecycle calling handler {} for service {}", cur.getMethod().getName(), target.getName());
+ method.invoke(target);
+ } catch (Exception e) {
+ logWarn("Killbill lifecycle failed to invoke lifecycle handler", e);
+ }
+ }
+
+ }
+
+
+ // Used to disable valid injection failure from unit tests
+ protected void logWarn(String msg, Exception e) {
+ log.warn(msg, e);
+ }
+
+ private Multimap<LifecycleLevel, LifecycleHandler<? extends KillbillService>> findAllHandlers(KillbillService service) {
+ Multimap<LifecycleLevel, LifecycleHandler<? extends KillbillService>> methodsInService = HashMultimap.create();
+ Class<? extends KillbillService> clazz = service.getClass();
+ for (Method method : clazz.getMethods()) {
+ LifecycleHandlerType annotation = method.getAnnotation(LifecycleHandlerType.class);
+ if (annotation != null) {
+ LifecycleLevel level = annotation.value();
+ LifecycleHandler<? extends KillbillService> handler = new LifecycleHandler<KillbillService>(service, method);
+ methodsInService.put(level, handler);
+ }
+ }
+ return methodsInService;
+ }
+
+
+ private final class LifecycleHandler<T> {
+ private final T target;
+ private final Method method;
+
+ public LifecycleHandler(T target, Method method) {
+ this.target = target;
+ this.method = method;
+ }
+
+ public T getTarget() {
+ return target;
+ }
+
+ public Method getMethod() {
+ return method;
+ }
+ }
+}
diff --git a/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/Lifecycle.java b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/Lifecycle.java
index c0edf2c..8192a65 100644
--- a/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/Lifecycle.java
+++ b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/Lifecycle.java
@@ -16,156 +16,14 @@
package com.ning.billing.beatrix.lifecycle;
-import com.google.common.base.Supplier;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.SetMultimap;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.ning.billing.lifecycle.KillbillService;
-import com.ning.billing.lifecycle.LifecycleHandlerType;
-import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
-import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel.Sequence;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import java.lang.reflect.Method;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArraySet;
+public interface Lifecycle {
+ public void fireStartupSequencePriorEventRegistration();
-public class Lifecycle {
+ public void fireStartupSequencePostEventRegistration();
- private final static Logger log = LoggerFactory.getLogger(Lifecycle.class);
- private final SetMultimap<LifecycleLevel, LifecycleHandler<? extends KillbillService>> handlersByLevel;
+ public void fireShutdownSequencePriorEventUnRegistration();
- private final ServiceFinder serviceFinder;
-
- private final Injector injector;
-
- @Inject
- public Lifecycle(Injector injector) {
-
- this.serviceFinder = new ServiceFinder(Lifecycle.class.getClassLoader());
- this.handlersByLevel = Multimaps.newSetMultimap(new ConcurrentHashMap<LifecycleLevel, Collection<LifecycleHandler<? extends KillbillService>>>(),
-
- new Supplier<Set<LifecycleHandler<? extends KillbillService>>>() {
- @Override
- public Set<LifecycleHandler<? extends KillbillService>> get() {
- return new CopyOnWriteArraySet<LifecycleHandler<? extends KillbillService>>();
- }
- });
- this.injector = injector;
-
- init();
- }
-
- public void init() {
- Set<? extends KillbillService> services = findServices();
- Iterator<? extends KillbillService> it = services.iterator();
- while (it.hasNext()) {
- handlersByLevel.putAll(findAllHandlers(it.next()));
- }
- }
-
-
- public void fireStartupSequencePriorEventRegistration() {
- fireSequence(Sequence.STARTUP_PRE_EVENT_REGISTRATION);
- }
-
- public void fireStartupSequencePostEventRegistration() {
- fireSequence(Sequence.STARTUP_POST_EVENT_REGISTRATION);
- }
-
- public void fireShutdownSequencePriorEventUnRegistration() {
- fireSequence(Sequence.SHUTDOWN_PRE_EVENT_UNREGISTRATION);
- }
-
- public void fireShutdownSequencePostEventUnRegistration() {
- fireSequence(Sequence.SHUTDOWN_POST_EVENT_UNREGISTRATION);
- }
-
- private void fireSequence(Sequence seq) {
- List<LifecycleLevel> levels = LifecycleLevel.getLevelsForSequence(seq);
- for (LifecycleLevel cur : levels) {
- doFireStage(cur);
- }
- }
-
- private void doFireStage(LifecycleLevel level) {
- log.info("Killbill lifecycle firing stage {}", level);
- Set<LifecycleHandler<? extends KillbillService>> handlers = handlersByLevel.get(level);
- for (LifecycleHandler<? extends KillbillService> cur : handlers) {
-
- try {
- Method method = cur.getMethod();
- KillbillService target = cur.getTarget();
- log.info("Killbill lifecycle calling handler {} for service {}", cur.getMethod().getName(), target.getName());
- method.invoke(target);
- } catch (Exception e) {
- logWarn("Killbill lifecycle failed to invoke lifecycle handler", e);
- }
- }
-
- }
-
-
- private Set<? extends KillbillService> findServices() {
-
- Set<KillbillService> result = new HashSet<KillbillService>();
- Set<Class<? extends KillbillService>> services = serviceFinder.getServices();
- for (Class<? extends KillbillService> cur : services) {
- log.debug("Found service {}", cur.getName());
- try {
- KillbillService instance = injector.getInstance(cur);
- log.debug("got instance {}", instance.getName());
- result.add(instance);
- } catch (Exception e) {
- logWarn("Failed to inject " + cur.getName(), e);
- }
-
- }
- return result;
- }
-
-
- // Used to disable valid injection failure from unit tests
- protected void logWarn(String msg, Exception e) {
- log.warn(msg, e);
- }
-
- public Multimap<LifecycleLevel, LifecycleHandler<? extends KillbillService>> findAllHandlers(KillbillService service) {
- Multimap<LifecycleLevel, LifecycleHandler<? extends KillbillService>> methodsInService = HashMultimap.create();
- Class<? extends KillbillService> clazz = service.getClass();
- for (Method method : clazz.getMethods()) {
- LifecycleHandlerType annotation = method.getAnnotation(LifecycleHandlerType.class);
- if (annotation != null) {
- LifecycleLevel level = annotation.value();
- LifecycleHandler<? extends KillbillService> handler = new LifecycleHandler<KillbillService>(service, method);
- methodsInService.put(level, handler);
- }
- }
- return methodsInService;
- }
-
-
- private final class LifecycleHandler<T> {
- private final T target;
- private final Method method;
-
- public LifecycleHandler(T target, Method method) {
- this.target = target;
- this.method = method;
- }
-
- public T getTarget() {
- return target;
- }
-
- public Method getMethod() {
- return method;
- }
- }
+ public void fireShutdownSequencePostEventUnRegistration();
}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/MockModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/MockModule.java
new file mode 100644
index 0000000..5fc81c6
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/MockModule.java
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+package com.ning.billing.beatrix.integration.inv_ent;
+
+import static org.testng.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Set;
+
+import org.skife.config.ConfigurationObjectFactory;
+import org.skife.jdbi.v2.DBI;
+import org.skife.jdbi.v2.IDBI;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.ning.billing.account.glue.AccountModule;
+import com.ning.billing.beatrix.lifecycle.DefaultLifecycle;
+import com.ning.billing.beatrix.lifecycle.Lifecycle;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.glue.CatalogModule;
+import com.ning.billing.dbi.DBIProvider;
+import com.ning.billing.dbi.DbiConfig;
+import com.ning.billing.entitlement.api.EntitlementService;
+import com.ning.billing.entitlement.glue.EntitlementModule;
+import com.ning.billing.invoice.api.InvoiceService;
+import com.ning.billing.invoice.glue.InvoiceModule;
+import com.ning.billing.lifecycle.KillbillService;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.eventbus.BusService;
+import com.ning.billing.util.glue.EventBusModule;
+import com.ning.billing.util.glue.NotificationQueueModule;
+
+
+public class MockModule extends AbstractModule {
+
+ @Override
+ protected void configure() {
+
+ loadSystemPropertiesFromClasspath("/resource.properties");
+
+ bind(Clock.class).to(ClockMock.class).asEagerSingleton();
+ bind(ClockMock.class).asEagerSingleton();
+ bind(Lifecycle.class).to(SubsetDefaultLifecycle.class).asEagerSingleton();
+ bind(IDBI.class).to(DBI.class).asEagerSingleton();
+ bind(DBI.class).toProvider(DBIProvider.class).asEagerSingleton();
+ final DbiConfig config = new ConfigurationObjectFactory(System.getProperties()).build(DbiConfig.class);
+ bind(DbiConfig.class).toInstance(config);
+ install(new EventBusModule());
+ install(new NotificationQueueModule());
+ install(new AccountModule());
+ install(new CatalogModule());
+ install(new EntitlementModule());
+ install(new InvoiceModule());
+ }
+
+
+ private static void loadSystemPropertiesFromClasspath(final String resource) {
+ final URL url = TestBasic.class.getResource(resource);
+ assertNotNull(url);
+ try {
+ System.getProperties().load( url.openStream() );
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private final static class SubsetDefaultLifecycle extends DefaultLifecycle {
+
+
+ @Inject
+ public SubsetDefaultLifecycle(Injector injector) {
+ super(injector);
+ }
+
+ @Override
+ protected Set<? extends KillbillService> findServices() {
+ ImmutableSet<? extends KillbillService> services = new ImmutableSet.Builder<KillbillService>()
+ .add(injector.getInstance(BusService.class))
+ .add(injector.getInstance(CatalogService.class))
+ .add(injector.getInstance(EntitlementService.class))
+ .add(injector.getInstance(InvoiceService.class))
+ .build();
+ return services;
+ }
+ }
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBasic.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBasic.java
new file mode 100644
index 0000000..b79d2a9
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBasic.java
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ */
+
+package com.ning.billing.beatrix.integration.inv_ent;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.Interval;
+import org.skife.jdbi.v2.Handle;
+import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.TransactionCallback;
+import org.skife.jdbi.v2.TransactionStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.AfterSuite;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+
+import com.google.inject.Inject;
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.beatrix.integration.inv_ent.TestBusHandler.NextEvent;
+import com.ning.billing.beatrix.lifecycle.Lifecycle;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.Currency;
+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.api.EntitlementService;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.invoice.api.InvoiceService;
+import com.ning.billing.invoice.api.InvoiceUserApi;
+
+import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.eventbus.BusService;
+
+@Guice(modules = {MockModule.class})
+public class TestBasic {
+
+ private static final Logger log = LoggerFactory.getLogger(TestBasic.class);
+ private static long AT_LEAST_ONE_MONTH_MS = (31 * 24 * 3600 * 1000);
+
+ @Inject IDBI dbi;
+
+ @Inject
+ private ClockMock clock;
+
+ @Inject
+ private Lifecycle lifecycle;
+
+ @Inject
+ private BusService busService;
+
+ @Inject
+ private EntitlementService entitlementService;
+
+ @Inject
+ private InvoiceService invoiceService;
+
+
+ private EntitlementUserApi entitlementUserApi;
+
+ private InvoiceUserApi invoiceUserApi;
+
+ private TestBusHandler busHandler;
+
+
+
+ @BeforeSuite(alwaysRun = true)
+ public void setup() throws Exception{
+
+ /**
+ * Initialize lifecyle for subset of services
+ */
+ busHandler = new TestBusHandler();
+ lifecycle.fireStartupSequencePriorEventRegistration();
+ busService.getBus().register(busHandler);
+ lifecycle.fireStartupSequencePostEventRegistration();
+
+ /**
+ * Retrieve APIs
+ */
+ entitlementUserApi = entitlementService.getUserApi();
+ invoiceUserApi = invoiceService.getUserApi();
+ }
+
+ @AfterSuite(alwaysRun = true)
+ public void tearDown() throws Exception {
+ lifecycle.fireShutdownSequencePriorEventUnRegistration();
+ busService.getBus().unregister(busHandler);
+ lifecycle.fireShutdownSequencePostEventUnRegistration();
+ }
+
+
+ @BeforeMethod(alwaysRun = true)
+ public void setupTest() {
+
+ log.warn("\n");
+ log.warn("RESET TEST FRAMEWORK\n\n");
+ busHandler.reset();
+ clock.resetDeltaFromReality();
+ cleanupData();
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void cleanupTest() {
+ log.warn("DONE WITH TEST\n");
+ }
+
+ private void cleanupData() {
+ dbi.inTransaction(new TransactionCallback<Void>() {
+ @Override
+ public Void inTransaction(Handle h, TransactionStatus status)
+ throws Exception {
+ h.execute("truncate table accounts");
+ h.execute("truncate table events");
+ h.execute("truncate table subscriptions");
+ h.execute("truncate table bundles");
+ h.execute("truncate table notifications");
+ h.execute("truncate table claimed_notifications");
+ h.execute("truncate table invoices");
+ h.execute("truncate table invoice_items");
+ h.execute("truncate table tag_descriptions");
+ h.execute("truncate table tags");
+ return null;
+ }
+ });
+ }
+
+
+ private DateTime checkAndGetCTD(UUID subscriptionId) {
+ SubscriptionData subscription = (SubscriptionData) entitlementUserApi.getSubscriptionFromId(subscriptionId);
+ DateTime ctd = subscription.getChargedThroughDate();
+ assertNotNull(ctd);
+ assertTrue(clock.getUTCNow().isBefore(ctd));
+ return ctd;
+ }
+
+ @Test(groups = "fast", enabled = false)
+ public void testSimple() throws Exception {
+
+ UUID accountId = UUID.randomUUID();
+ SubscriptionBundle bundle = entitlementUserApi.createBundleForAccount(accountId, "whatever");
+
+ String productName = "Shotgun";
+ BillingPeriod term = BillingPeriod.MONTHLY;
+ String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
+
+ //
+ // CREATE SUBSCRIPTION AND EXPECT BOTH EVENTS: NextEvent.CREATE NextEvent.INVOICE
+ //
+ busHandler.pushExpectedEvent(NextEvent.CREATE);
+ busHandler.pushExpectedEvent(NextEvent.INVOICE);
+ SubscriptionData subscription = (SubscriptionData) entitlementUserApi.createSubscription(bundle.getId(),
+ new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null), null);
+ assertNotNull(subscription);
+ assertTrue(busHandler.isCompleted(5000));
+
+ //
+ // VERIFY CTD HAS BEEN SET
+ //
+ checkAndGetCTD(subscription.getId());
+
+ //
+ // CHANGE PLAN IMMEDIATELY AND EXPECT BOTH EVENTS: NextEvent.CHANGE NextEvent.INVOICE
+ //
+ busHandler.pushExpectedEvent(NextEvent.CHANGE);
+ busHandler.pushExpectedEvent(NextEvent.INVOICE);
+
+ BillingPeriod newTerm = BillingPeriod.MONTHLY;
+ String newPlanSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
+ String newProductName = "Assault-Rifle";
+ subscription.changePlan(newProductName, newTerm, newPlanSetName, clock.getUTCNow());
+ assertTrue(busHandler.isCompleted(5000));
+
+
+ //
+ // VERIFY AGAIN CTD HAS BEEN SET
+ //
+ DateTime ctd = checkAndGetCTD(subscription.getId());
+
+ //
+ // CHANGE PAN EOT AND EXPECT NOTHING
+ //
+ newTerm = BillingPeriod.MONTHLY;
+ newPlanSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
+ newProductName = "Pistol";
+ subscription.changePlan(newProductName, newTerm, newPlanSetName, clock.getUTCNow());
+
+ //
+ // MOVE TIME AFTER CTD AND EXPECT BOTH EVENTS : NextEvent.CHANGE NextEvent.INVOICE
+ //
+ busHandler.pushExpectedEvent(NextEvent.CHANGE);
+ busHandler.pushExpectedEvent(NextEvent.INVOICE);
+ clock.setDeltaFromReality(ctd.getMillis() - clock.getUTCNow().getMillis());
+ //clock.setDeltaFromReality(AT_LEAST_ONE_MONTH_MS + 1000);
+ assertTrue(busHandler.isCompleted(5000));
+
+ //
+ // MOVE TIME AFTER NEXT BILL CYCLE DAY AND EXPECT EVENT : NextEvent.INVOICE
+ //
+ int maxCycles = 3;
+ DateTime lastCtd = null;
+ do {
+ clock.addDeltaFromReality(AT_LEAST_ONE_MONTH_MS + 1000);
+ busHandler.pushExpectedEvent(NextEvent.INVOICE);
+ assertTrue(busHandler.isCompleted(5000));
+ lastCtd = checkAndGetCTD(subscription.getId());
+ } while (maxCycles-- > 0);
+
+ //
+ // FINALY CANCEL SUBSCRIPTION EOT
+ //
+ subscription.cancel(clock.getUTCNow(), false);
+
+ // MOVE AFTER CANCEL DATE AND EXPECT EVENT : NextEvent.CANCEL, NextEvent.INVOICE
+ busHandler.pushExpectedEvent(NextEvent.CANCEL);
+ busHandler.pushExpectedEvent(NextEvent.INVOICE);
+ Interval it = new Interval(lastCtd, clock.getUTCNow());
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(busHandler.isCompleted(5000));
+ }
+
+
+ protected AccountData getAccountData() {
+ AccountData accountData = new AccountData() {
+ @Override
+ public String getName() {
+ return "firstName lastName";
+ }
+ @Override
+ public int getFirstNameLength() {
+ return "firstName".length();
+ }
+ @Override
+ public String getEmail() {
+ return "accountName@yahoo.com";
+ }
+ @Override
+ public String getPhone() {
+ return "4152876341";
+ }
+ @Override
+ public String getExternalKey() {
+ return "k123456";
+ }
+ @Override
+ public int getBillCycleDay() {
+ return 1;
+ }
+ @Override
+ public Currency getCurrency() {
+ return Currency.USD;
+ }
+ @Override
+ public String getPaymentProviderName() {
+ return "Paypal";
+ }
+ };
+ return accountData;
+ }
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBusHandler.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBusHandler.java
new file mode 100644
index 0000000..0c3e035
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBusHandler.java
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+package com.ning.billing.beatrix.integration.inv_ent;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Stack;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Joiner;
+import com.google.common.eventbus.Subscribe;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition;
+import com.ning.billing.invoice.api.InvoiceCreationNotification;
+
+public class TestBusHandler {
+
+ protected static final Logger log = LoggerFactory.getLogger(TestBusHandler.class);
+
+ private final List<NextEvent> nextExpectedEvent;
+
+ private volatile boolean completed;
+
+ public TestBusHandler() {
+ nextExpectedEvent = new Stack<NextEvent>();
+ this.completed = false;
+ }
+
+ public enum NextEvent {
+ MIGRATE_ENTITLEMENT,
+ CREATE,
+ CHANGE,
+ CANCEL,
+ UNCANCEL,
+ PAUSE,
+ RESUME,
+ PHASE,
+ INVOICE
+ }
+
+ @Subscribe
+ public void handleEntitlementEvents(SubscriptionTransition event) {
+ log.info(String.format("Got subscription event %s", event.toString()));
+ switch (event.getTransitionType()) {
+ case MIGRATE_ENTITLEMENT:
+ assertEqualsNicely(NextEvent.MIGRATE_ENTITLEMENT);
+ notifyIfStackEmpty();
+ break;
+ case CREATE:
+ assertEqualsNicely(NextEvent.CREATE);
+ notifyIfStackEmpty();
+
+ break;
+ case CANCEL:
+ assertEqualsNicely(NextEvent.CANCEL);
+ notifyIfStackEmpty();
+
+ break;
+ case CHANGE:
+ assertEqualsNicely(NextEvent.CHANGE);
+ notifyIfStackEmpty();
+
+ break;
+ case PAUSE:
+ assertEqualsNicely(NextEvent.PAUSE);
+ notifyIfStackEmpty();
+
+ break;
+ case RESUME:
+ assertEqualsNicely(NextEvent.RESUME);
+ notifyIfStackEmpty();
+
+ break;
+ case UNCANCEL:
+ assertEqualsNicely(NextEvent.UNCANCEL);
+ notifyIfStackEmpty();
+ break;
+ case PHASE:
+ assertEqualsNicely(NextEvent.PHASE);
+ notifyIfStackEmpty();
+ break;
+ default:
+ throw new RuntimeException("Unexpected event type " + event.getRequestedTransitionTime());
+ }
+ }
+
+ @Subscribe
+ public void handleInvoiceEvents(InvoiceCreationNotification event) {
+ log.info(String.format("Got Invoice event %s", event.toString()));
+ assertEqualsNicely(NextEvent.INVOICE);
+ notifyIfStackEmpty();
+
+ }
+
+ public void reset() {
+ nextExpectedEvent.clear();
+ }
+
+ public void pushExpectedEvent(NextEvent next) {
+ synchronized (this) {
+ nextExpectedEvent.add(next);
+ completed = false;
+ }
+ }
+
+ public boolean isCompleted(long timeout) {
+ synchronized (this) {
+ try {
+ wait(timeout);
+ } catch (Exception ignore) {
+ }
+ }
+ if (!completed) {
+ log.debug("TestBusHandler did not complete in " + timeout + " ms");
+ }
+ return completed;
+ }
+
+ private void notifyIfStackEmpty() {
+ log.debug("notifyIfStackEmpty ENTER");
+ synchronized (this) {
+ if (nextExpectedEvent.isEmpty()) {
+ log.debug("notifyIfStackEmpty EMPTY");
+ completed = true;
+ notify();
+ }
+ }
+ log.debug("notifyIfStackEmpty EXIT");
+ }
+
+ private void assertEqualsNicely(NextEvent expected) {
+
+ boolean foundIt = false;
+ Iterator<NextEvent> it = nextExpectedEvent.iterator();
+ while (it.hasNext()) {
+ NextEvent ev = it.next();
+ if (ev == expected) {
+ it.remove();
+ foundIt = true;
+ break;
+ }
+ }
+ if (!foundIt) {
+ Joiner joiner = Joiner.on(" ");
+ System.err.println("Expected event " + expected + " got " + joiner.join(nextExpectedEvent));
+ System.exit(1);
+ }
+ }
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/lifecycle/TestLifecycle.java b/beatrix/src/test/java/com/ning/billing/beatrix/lifecycle/TestLifecycle.java
index 69e6a0d..595a01b 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/lifecycle/TestLifecycle.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/lifecycle/TestLifecycle.java
@@ -34,7 +34,7 @@ public class TestLifecycle {
private Service1 s1;
private Service2 s2;
- private Lifecycle lifecycle;
+ private DefaultLifecycle lifecycle;
public static class ServiceBase {
@@ -122,7 +122,7 @@ public class TestLifecycle {
final Injector g = Guice.createInjector(Stage.DEVELOPMENT, new TestLifecycleModule());
s1 = g.getInstance(Service1.class);
s2 = g.getInstance(Service2.class);
- lifecycle = g.getInstance(Lifecycle.class);
+ lifecycle = g.getInstance(DefaultLifecycle.class);
}
@Test(enabled=true, groups={"fast"})
@@ -148,7 +148,7 @@ public class TestLifecycle {
Assert.assertEquals(s1.getCount() + s2.getCount(), 1);
}
- public static class LifecycleNoWarn extends Lifecycle {
+ public static class LifecycleNoWarn extends DefaultLifecycle {
@Inject
public LifecycleNoWarn(Injector injector) {
@@ -163,7 +163,7 @@ public class TestLifecycle {
@Override
protected void configure() {
- bind(Lifecycle.class).to(LifecycleNoWarn.class).asEagerSingleton();
+ bind(DefaultLifecycle.class).to(LifecycleNoWarn.class).asEagerSingleton();
bind(Service1.class).asEagerSingleton();
bind(Service2.class).asEagerSingleton();
}
beatrix/src/test/resources/catalogSample.xml 624(+624 -0)
diff --git a/beatrix/src/test/resources/catalogSample.xml b/beatrix/src/test/resources/catalogSample.xml
new file mode 100644
index 0000000..ce3b250
--- /dev/null
+++ b/beatrix/src/test/resources/catalogSample.xml
@@ -0,0 +1,624 @@
+<?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>
+ <available>
+ <addonProduct>Telescopic-Scope</addonProduct>
+ <addonProduct>Laser-Scope</addonProduct>
+ </available>
+ </product>
+ <product name="Shotgun">
+ <category>BASE</category>
+ </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>
+ <toProduct>Pistol</toProduct>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <toPriceList>rescue</toPriceList>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <fromProduct>Pistol</fromProduct>
+ <toProduct>Shotgun</toProduct>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <fromProduct>Assault-Rifle</fromProduct>
+ <toProduct>Shotgun</toProduct>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <fromBillingPeriod>MONTHLY</fromBillingPeriod>
+ <toProduct>Assault-Rifle</toProduct>
+ <toBillingPeriod>MONTHLY</toBillingPeriod>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <toProduct>Assault-Rifle</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>
+ <alignment>START_OF_SUBSCRIPTION</alignment>
+ </changeAlignmentCase>
+ <changeAlignmentCase>
+ <toPriceList>rescue</toPriceList>
+ <alignment>CHANGE_OF_PLAN</alignment>
+ </changeAlignmentCase>
+ <changeAlignmentCase>
+ <fromPriceList>rescue</fromPriceList>
+ <toPriceList>rescue</toPriceList>
+ <alignment>CHANGE_OF_PRICELIST</alignment>
+ </changeAlignmentCase>
+ </changeAlignment>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <policy>END_OF_TERM</policy>
+ </cancelPolicyCase>
+ <cancelPolicyCase>
+ <phaseType>TRIAL</phaseType>
+ <policy>IMMEDIATE</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
+ <createAlignment>
+ <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>
+ <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>
+ <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/beatrix/src/test/resources/resource.properties b/beatrix/src/test/resources/resource.properties
new file mode 100644
index 0000000..cc82754
--- /dev/null
+++ b/beatrix/src/test/resources/resource.properties
@@ -0,0 +1,6 @@
+killbill.catalog.uri=file:src/test/resources/catalogSample.xml
+killbill.entitlement.dao.claim.time=60000
+killbill.entitlement.dao.ready.max=1
+killbill.entitlement.engine.notifications.sleep=500
+
+
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java b/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
index a5ab3d8..7c5eee6 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
@@ -43,10 +43,6 @@ import org.skife.config.ConfigurationObjectFactory;
public class EntitlementModule extends AbstractModule {
- protected void installClock() {
- bind(Clock.class).to(DefaultClock.class).asEagerSingleton();
- }
-
protected void installConfig() {
final EntitlementConfig config = new ConfigurationObjectFactory(System.getProperties()).build(EntitlementConfig.class);
bind(EntitlementConfig.class).toInstance(config);
@@ -71,7 +67,6 @@ public class EntitlementModule extends AbstractModule {
@Override
protected void configure() {
installConfig();
- installClock();
installEntitlementDao();
installEntitlementCore();
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
index 1555bdb..b57d15b 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
@@ -25,14 +25,11 @@ import com.ning.billing.util.glue.NotificationQueueModule;
public class MockEngineModule extends EntitlementModule {
- @Override
- protected void installClock() {
- bind(Clock.class).to(ClockMock.class).asEagerSingleton();
- }
@Override
protected void configure() {
super.configure();
+ bind(Clock.class).to(ClockMock.class).asEagerSingleton();
install(new EventBusModule());
install(new CatalogModule());
install(new AccountModuleMock());
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
index dbe2938..c2cc95c 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
@@ -35,10 +35,6 @@ public class MockEngineModuleSql extends MockEngineModule {
bind(EntitlementDao.class).to(MockEntitlementDaoSql.class).asEagerSingleton();
}
- @Override
- protected void installClock() {
- bind(Clock.class).to(ClockMock.class).asEagerSingleton();
- }
protected void installDBI() {
bind(DBI.class).toProvider(DBIProvider.class).asEagerSingleton();
diff --git a/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java b/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java
index 54990c5..35c6ac6 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java
@@ -17,7 +17,9 @@
package com.ning.billing.invoice.glue;
import com.google.inject.AbstractModule;
+import com.ning.billing.invoice.api.DefaultInvoiceService;
import com.ning.billing.invoice.api.InvoicePaymentApi;
+import com.ning.billing.invoice.api.InvoiceService;
import com.ning.billing.invoice.api.invoice.DefaultInvoicePaymentApi;
import com.ning.billing.invoice.api.user.DefaultInvoiceUserApi;
import com.ning.billing.invoice.api.InvoiceUserApi;
@@ -25,6 +27,7 @@ import com.ning.billing.invoice.dao.DefaultInvoiceDao;
import com.ning.billing.invoice.dao.InvoiceDao;
public class InvoiceModule extends AbstractModule {
+
private void installInvoiceDao() {
bind(InvoiceDao.class).to(DefaultInvoiceDao.class).asEagerSingleton();
}
@@ -39,6 +42,7 @@ public class InvoiceModule extends AbstractModule {
@Override
protected void configure() {
+ bind(InvoiceService.class).to(DefaultInvoiceService.class).asEagerSingleton();
installInvoiceDao();
installInvoiceUserApi();
installInvoicePaymentApi();
pom.xml 6(+6 -0)
diff --git a/pom.xml b/pom.xml
index 28f48db..fb37e6b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -73,6 +73,11 @@
</dependency>
<dependency>
<groupId>com.ning.billing</groupId>
+ <artifactId>killbill-invoice</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
<artifactId>killbill-catalog</artifactId>
<version>${project.version}</version>
</dependency>
@@ -327,6 +332,7 @@
<exclude>**/.project</exclude>
<exclude>.git/**</exclude>
<exclude>.gitignore</exclude>
+ <exclude>ignore/**</exclude>
<exclude>API.txt</exclude>
<exclude>RELEASE.sh</exclude>
<exclude>deploy.sh</exclude>