killbill-aplcache

Merge branch 'inv-ent-integration' of github.com:ning/killbill

1/18/2012 8:44:39 PM

Details

diff --git a/beatrix/src/test/resources/Catalog-Entitlement-Testplan.txt b/beatrix/src/test/resources/Catalog-Entitlement-Testplan.txt
new file mode 100644
index 0000000..84c496b
--- /dev/null
+++ b/beatrix/src/test/resources/Catalog-Entitlement-Testplan.txt
@@ -0,0 +1,97 @@
+NOTES
+=====
+
+Events: Create, change, cancel, migrate 
+Validate: BillingEvents, SubscriptionTransition 
+Rules: 
+    Cancellation
+        Action Policy: When to cancel (Immediate/End-of-term)
+    Creation
+        Alignment: How to align phases in a bundle
+    Change plan behavior
+        Action Policy: When to change plan (Immediate/End-of-term)
+        Alignment: How to align phases 
+        Pricelist: Which pricelist to pick when moving between plans
+    Billing alignment
+        Subscription BCD, Bundle BCD, Account BCD 
+Phases - timing
+Prices - multi-currency, fixed vs recurring prices
+Pricelists - particularly pricelist change rules
+Catalog changes new subscriptions / existing subscriptions
+Price change
+    
+TESTS
+=====
+
+BASEPLAN TESTS
+    * Create a single phase recurring plan
+        - check for creation event (timing?)
+        - check for no termination event
+        - check pricing (different currencies)
+        - check BDC (subscription, account, timezone)
+    * Create a single phase fixed length plan 
+        - check for creation event (timing - different request dates)
+        - check for termination event (timing - different lengths?)
+        - check price (fixed vs recurring)
+    * Create a two phase event use a fixed price and a recurring price
+        - check for phase change (timing)
+        - check prices change
+    * Create a multi-phase plan 
+        - check for phase events
+        - check price changes
+    * Create multiple base plans in a single bundle - should fail
+    
+    * Change base plan once
+        - check plan change policy (immediate, eot)
+        - check alignments of new plan with old 
+        - check move between pricelists
+        - check that phases progress successfully after change
+        - check obsolete events are removed
+    * Change base plan multiple times
+        - check that alignment occurs correctly 
+        - check phases progress correctly
+        - check obsolete events are removed 
+        
+    * Cancellation of a single phase plan
+        - check creation and timing of termination event
+    * Cancellation of a multi-phase plan
+        - check creation of termination event 
+        - check removal of events beyond termination event
+    * Change a cancelled base plan - should fail
+    
+    * Migration to a single phase plan
+        - check migration event occurs when it should
+    * Migration to a multi-phase plan
+        - check migration event occurs when it should
+        - check migration into different phase
+        - check alignment of phases can be correctly controlled
+    * Migration to a fixed duration plan
+        - check migration event occurs when it should
+        - check termination event occurs when it should
+        
+
+         
+STANDALONE TEST
+    * Create multiple plans in a single bundle
+        - check plans can be created
+        - check cannot add a base plan
+        - check BCD at subscription bundle level
+            
+
+PRICE CHANGE TEST
+    * Price change on a single phase base plan
+        - check new subscriptions get price after effective date
+        - check changed subscriptions get price after effective date
+        - check existing subscriptions ONLY get it after ESED
+        - check that if ESED is missing existing subs are grandfathered for ever
+    * Price change on a multi-phase subscription
+        - check price change applies correctly to correct phases
+    * Multiple price changes
+        - check multiple price changes with overlapping dates
+
+
+ADD-ON TESTS
+    * Add-on creation alignment
+    * Add-on cancel with base plan
+    
+    
\ No newline at end of file

invoice/pom.xml 6(+5 -1)

diff --git a/invoice/pom.xml b/invoice/pom.xml
index 1001e68..3cc522b 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -103,7 +103,11 @@
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
         </dependency>
-        
+        <dependency>
+            <groupId>com.jayway.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
     </build>
diff --git a/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java b/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
index c9f5aa9..6036652 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
@@ -16,50 +16,131 @@
 
 package com.ning.billing.invoice.notification;
 
+import static com.jayway.awaitility.Awaitility.await;
+import static java.util.concurrent.TimeUnit.MINUTES;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+
+import org.apache.commons.io.IOUtils;
+import org.joda.time.DateTime;
 import org.skife.config.ConfigurationObjectFactory;
+import org.skife.jdbi.v2.DBI;
+import org.skife.jdbi.v2.Transaction;
+import org.skife.jdbi.v2.TransactionStatus;
+import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import com.google.common.eventbus.Subscribe;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
-import com.ning.billing.config.CatalogConfig;
 import com.ning.billing.config.InvoiceConfig;
+import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.lifecycle.KillbillService.ServiceException;
 import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.DefaultClock;
+import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.eventbus.Bus;
 import com.ning.billing.util.eventbus.MemoryEventBus;
 import com.ning.billing.util.notificationq.DefaultNotificationQueueService;
+import com.ning.billing.util.notificationq.DummySqlTest;
 import com.ning.billing.util.notificationq.NotificationQueueService;
+import com.ning.billing.util.notificationq.dao.NotificationSqlDao;
 
 public class TestNextBillingDateNotifier {
 
 	private Clock clock;
-	private NextBillingDateNotifier notifier;
+	private DefaultNextBillingDateNotifier notifier;
+	private DummySqlTest dao;
+	private Bus eventBus;
+	private MysqlTestingHelper helper;
 	
 	@BeforeClass(groups={"setup"})
-	public void setup() throws ServiceException {
+	public void setup() throws ServiceException, IOException, ClassNotFoundException, SQLException {
 		//TestApiBase.loadSystemPropertiesFromClasspath("/entitlement.properties");
-        final Injector g = Guice.createInjector(Stage.PRODUCTION, new AbstractModule() {
+        final Injector g = Guice.createInjector(Stage.PRODUCTION,  new AbstractModule() {
 			protected void configure() {
-				 bind(Clock.class).to(DefaultClock.class).asEagerSingleton();
-				 bind(NextBillingDateNotifier.class).to(DefaultNextBillingDateNotifier.class).asEagerSingleton();
+				 bind(Clock.class).to(ClockMock.class).asEagerSingleton();
 				 bind(Bus.class).to(MemoryEventBus.class).asEagerSingleton();
 				 bind(NotificationQueueService.class).to(DefaultNotificationQueueService.class).asEagerSingleton();
 				 final InvoiceConfig config = new ConfigurationObjectFactory(System.getProperties()).build(InvoiceConfig.class);
-			        bind(InvoiceConfig.class).toInstance(config);
+				 bind(InvoiceConfig.class).toInstance(config);
+				 final MysqlTestingHelper helper = new MysqlTestingHelper();
+				 bind(MysqlTestingHelper.class).toInstance(helper);
+				 DBI dbi = helper.getDBI();
+				 bind(DBI.class).toInstance(dbi);
+
 			}  	
         });
 
-        notifier = g.getInstance(NextBillingDateNotifier.class);
         clock = g.getInstance(Clock.class);
-       
+        DBI dbi = g.getInstance(DBI.class);
+        dao = dbi.onDemand(DummySqlTest.class);
+        eventBus = g.getInstance(Bus.class);
+        helper = g.getInstance(MysqlTestingHelper.class);
+        notifier = new DefaultNextBillingDateNotifier(g.getInstance(NotificationQueueService.class), eventBus, g.getInstance(InvoiceConfig.class));
+        startMysql();
 	}
 	
-	@Test(enabled=false, groups="fast")
-	public void test() {
+	private void startMysql() throws IOException, ClassNotFoundException, SQLException {
+		final String ddl = IOUtils.toString(NotificationSqlDao.class.getResourceAsStream("/com/ning/billing/util/ddl.sql"));
+		final String testDdl = IOUtils.toString(NotificationSqlDao.class.getResourceAsStream("/com/ning/billing/util/ddl_test.sql"));
+		helper.startMysql();
+		helper.initDb(ddl);
+		helper.initDb(testDdl);
+	}
+
+	public static class NextBillingEventListener {
+		private int eventCount=0;
+
+		public int getEventCount() {
+			return eventCount;
+		}
+
+		@Subscribe
+		public synchronized void processEvent(NextBillingDateEvent event) {
+			eventCount++;
+			//log.debug("Got event {} {}", event.name, event.value);
+		}
+	}
+	
+	@Test(enabled=true, groups="slow")
+	public void test() throws Exception {
+		final UUID subscriptionId = new UUID(0L,1L);
+		final DateTime now = new DateTime();
+		final DateTime readyTime = now.plusMillis(2000);
+
+		final NextBillingEventListener listener = new NextBillingEventListener();
+		eventBus.start();
+		notifier.initialize();
+		notifier.start();
 		
+        eventBus.register(listener);
+		dao.inTransaction(new Transaction<Void, DummySqlTest>() {
+			@Override
+			public Void inTransaction(DummySqlTest transactional,
+					TransactionStatus status) throws Exception {
+
+				notifier.insertNextBillingNotification(transactional, subscriptionId, readyTime);
+				return null;
+			}
+		});
+
+		// Move time in the future after the notification effectiveDate
+		((ClockMock) clock).setDeltaFromReality(3000);
+
+
+	    await().atMost(1, MINUTES).until(new Callable<Boolean>() {
+	            @Override
+	            public Boolean call() throws Exception {
+	                return listener.getEventCount() == 1;
+	            }
+	        });
+
+		Assert.assertEquals(listener.getEventCount(), 1);
 	}
 }

pom.xml 6(+6 -0)

diff --git a/pom.xml b/pom.xml
index 8c8fbb3..28f48db 100644
--- a/pom.xml
+++ b/pom.xml
@@ -234,6 +234,12 @@
                 <version>6.0</version>
                 <scope>test</scope>
             </dependency>
+             <dependency>
+                <groupId>com.jayway.awaitility</groupId>
+                <artifactId>awaitility</artifactId>
+                <version>1.3.3</version>
+                <scope>test</scope>
+            </dependency>
         </dependencies>
     </dependencyManagement>
     <build>
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java b/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
index 8058561..207a78c 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
@@ -150,18 +150,7 @@ public class TestNotificationQueue {
 		((ClockMock) clock).setDeltaFromReality(3000);
 
 		// Notification should have kicked but give it at least a sec' for thread scheduling
-		int nbTry = 1;
-		boolean success = false;
-		do {
-			synchronized(expectedNotifications) {
-				if (expectedNotifications.get(notificationKey.toString())) {
-					success = true;
-					break;
-				}
-				expectedNotifications.wait(1000);
-			}
-		} while (nbTry-- > 0);
-		assertEquals(success, true);
+		  
 	}
 
 	@Test