killbill-aplcache

Minor refactoring of Subscriptiondata Major test cleanup

3/17/2012 12:17:44 AM

Changes

beatrix/pom.xml 5(+0 -5)

pom.xml 69(+45 -24)

util/pom.xml 10(+0 -10)

Details

diff --git a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
index c88d255..14654d2 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
@@ -31,6 +31,7 @@ import org.joda.time.DateTime;
 import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
@@ -132,11 +133,21 @@ public class TestAnalyticsService {
     private InvoiceCreationNotification invoiceCreationNotification;
     private PaymentInfo paymentInfoNotification;
 
+    @BeforeMethod
+    public void cleanup() throws Exception
+    {
+        helper.cleanupTable("bst");
+        helper.cleanupTable("bac");
+
+    }
+
+
     @BeforeClass(alwaysRun = true)
     public void startMysql() throws IOException, ClassNotFoundException, SQLException, EntitlementUserApiException {
         // Killbill generic setup
         setupBusAndMySQL();
 
+
         tagDao.create(TAG_ONE);
         tagDao.create(TAG_TWO);
 
@@ -174,6 +185,9 @@ public class TestAnalyticsService {
         helper.initDb(invoiceDdl);
         helper.initDb(paymentDdl);
         helper.initDb(utilDdl);
+
+        helper.cleanupTable("tag_definitions");
+        helper.cleanupTable("accounts");
     }
 
     private void createSubscriptionTransitionEvent(final Account account) throws EntitlementUserApiException {
diff --git a/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java b/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
index a9a5422..e31d562 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
@@ -128,6 +128,7 @@ public class TestAnalyticsDao
     public void cleanup() throws Exception
     {
         helper.cleanupTable("bst");
+        helper.cleanupTable("bac");
     }
 
     @Test(groups = "slow")
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java b/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
index 69abfb4..357caad 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
@@ -116,17 +116,6 @@ public class MockSubscription implements Subscription
     }
 
     @Override
-    public List<SubscriptionTransition> getActiveTransitions() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-
-    public List<SubscriptionTransition> getAllTransitions() {
-        throw new UnsupportedOperationException();
-     }
-
-    @Override
     public SubscriptionTransition getPendingTransition() {
         throw new UnsupportedOperationException();
     }
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
index a9ce2c7..83d0b68 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
@@ -68,10 +68,6 @@ public interface Subscription extends CustomizableEntity {
 
     public ProductCategory getCategory();
 
-    public List<SubscriptionTransition> getActiveTransitions();
-
-    public List<SubscriptionTransition> getAllTransitions();
-
     public SubscriptionTransition getPendingTransition();
 
     public SubscriptionTransition getPreviousTransition();

beatrix/pom.xml 5(+0 -5)

diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index a3098bc..032ae4a 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -83,11 +83,6 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>com.mysql</groupId>
-            <artifactId>management</artifactId>
-            <version>5.0.11</version>
-        </dependency>
-        <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
             <scope>test</scope>
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
index 7739ba7..8d78cc7 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
@@ -80,7 +80,7 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
         	List<Subscription> subscriptions = entitlementDao.getSubscriptions(bundle.getId());
 
         	for (final Subscription subscription: subscriptions) {
-        		for (final SubscriptionTransition transition : subscription.getAllTransitions()) {
+        		for (final SubscriptionTransition transition : ((SubscriptionData) subscription).getBillingTransitions()) {
         			try {
         				BillingEvent event = new DefaultBillingEvent(transition, subscription, calculateBcd(bundle, subscription, transition, accountId), currency);
         				result.add(event);
@@ -122,7 +122,7 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
 		switch (alignment) {
     		case ACCOUNT :
     			result = account.getBillCycleDay();
-    			
+
     			if(result == 0) {
     				result = calculateBcdFromSubscription(subscription, plan, account);
     			}
@@ -140,7 +140,7 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
     	return result;
 
     }
-    
+
    	private int calculateBcdFromSubscription(Subscription subscription, Plan plan, Account account) throws AccountApiException {
 		int result = account.getBillCycleDay();
         if(result != 0) {
@@ -153,7 +153,7 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
         } catch (CatalogApiException e) {
             log.error("Unexpected catalog error encountered when updating BCD",e);
         }
-        
+
 
         Account modifiedAccount = new DefaultAccount(
                 account.getId(),
@@ -181,15 +181,15 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
         return result;
     }
 
-    private int billCycleDay(DateTime requestedDate, DateTimeZone timeZone, 
+    private int billCycleDay(DateTime requestedDate, DateTimeZone timeZone,
     		Plan plan) throws CatalogApiException {
 
         DateTime date = plan.dateOfFirstRecurringNonZeroCharge(requestedDate);
         return date.toDateTime(timeZone).getDayOfMonth();
 
     }
-    
-    
+
+
     @Override
     public void setChargedThroughDate(final UUID subscriptionId, final DateTime ctd) {
         SubscriptionData subscription = (SubscriptionData) entitlementDao.getSubscriptionFromId(subscriptionId);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
index c8aa427..ee7bb5a 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
@@ -26,6 +26,10 @@ import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
 import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.SubscriptionTransitionDataIterator.Kind;
+import com.ning.billing.entitlement.api.user.SubscriptionTransitionDataIterator.Order;
+import com.ning.billing.entitlement.api.user.SubscriptionTransitionDataIterator.TimeLimit;
+import com.ning.billing.entitlement.api.user.SubscriptionTransitionDataIterator.Visibility;
 import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
 import com.ning.billing.entitlement.events.phase.PhaseEvent;
@@ -42,7 +46,6 @@ import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
@@ -73,7 +76,7 @@ public class SubscriptionData extends CustomizableEntityBase implements Subscrip
     // so the user holding that subscription object get the correct state when
     // the call completes
     //
-    private List<SubscriptionTransitionData> transitions;
+    private LinkedList<SubscriptionTransitionData> transitions;
 
     // Transient object never returned at the API
     public SubscriptionData(SubscriptionBuilder builder) {
@@ -203,48 +206,29 @@ public class SubscriptionData extends CustomizableEntityBase implements Subscrip
         apiService.recreatePlan(this, spec, requestedDate);
     }
 
-    @Override
-    public List<SubscriptionTransition> getActiveTransitions() {
-        if (transitions == null) {
-            return Collections.emptyList();
-        }
-
-        List<SubscriptionTransition> activeTransitions = new ArrayList<SubscriptionTransition>();
-        for (SubscriptionTransition cur : transitions) {
-            if (cur.getEffectiveTransitionTime().isAfter(clock.getUTCNow())) {
-                activeTransitions.add(cur);
-            }
-        }
-        return activeTransitions;
-    }
+    public List<SubscriptionTransition> getBillingTransitions() {
 
-    @Override
-    public List<SubscriptionTransition> getAllTransitions() {
         if (transitions == null) {
             return Collections.emptyList();
         }
-
         List<SubscriptionTransition> result = new ArrayList<SubscriptionTransition>();
-        for (SubscriptionTransition cur : transitions) {
-            result.add(cur);
+        SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(clock, transitions,
+                Order.ASC_FROM_PAST, Kind.BILLING, Visibility.ALL, TimeLimit.ALL);
+        while (it.hasNext()) {
+            result.add(it.next());
         }
         return result;
     }
 
     @Override
     public SubscriptionTransition getPendingTransition() {
+
         if (transitions == null) {
             return null;
         }
-        for (SubscriptionTransition cur : transitions) {
-            if (cur.getTransitionType() == SubscriptionTransitionType.MIGRATE_BILLING) {
-                continue;
-            }
-            if (cur.getEffectiveTransitionTime().isAfter(clock.getUTCNow())) {
-                return cur;
-            }
-        }
-        return null;
+        SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(clock, transitions,
+                Order.ASC_FROM_PAST, Kind.ENTITLEMENT, Visibility.ALL, TimeLimit.FUTURE_ONLY);
+        return it.hasNext() ? it.next() : null;
     }
 
     @Override
@@ -252,28 +236,15 @@ public class SubscriptionData extends CustomizableEntityBase implements Subscrip
         if (transitions == null) {
             return null;
         }
-
-        // ensure that the latestSubscription is always set; prevents NPEs
-        SubscriptionTransitionData latestSubscription = transitions.get(0);
-        for (SubscriptionTransitionData cur : transitions) {
-            if (cur.getTransitionType() == SubscriptionTransitionType.MIGRATE_BILLING) {
-                continue;
-            }
-            if (cur.getEffectiveTransitionTime().isAfter(clock.getUTCNow()) ||
-                    // We are not looking at events that were patched on the fly-- such as future ADDON cancelation from Base Plan
-                   !cur.isFromDisk()) {
-                break;
-            }
-            latestSubscription = cur;
-        }
-        return latestSubscription;
+        SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(clock, transitions,
+                Order.DESC_FROM_FUTURE, Kind.ENTITLEMENT, Visibility.FROM_DISK_ONLY, TimeLimit.PAST_OR_PRESENT_ONLY);
+        return it.hasNext() ? it.next() : null;
     }
 
     public SubscriptionTransition getTransitionFromEvent(EntitlementEvent event) {
         if (transitions == null || event == null) {
             return null;
         }
-
         for (SubscriptionTransition cur : transitions) {
             if (cur.getId().equals(event.getId())) {
                 return cur;
@@ -310,41 +281,32 @@ public class SubscriptionData extends CustomizableEntityBase implements Subscrip
             throw new EntitlementError(String.format("No transitions for subscription %s", getId()));
         }
 
-        Iterator<SubscriptionTransitionData> it = ((LinkedList<SubscriptionTransitionData>) transitions).descendingIterator();
+
+        SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(clock, transitions,
+                Order.DESC_FROM_FUTURE, Kind.ENTITLEMENT, Visibility.ALL, TimeLimit.PAST_OR_PRESENT_ONLY);
         while (it.hasNext()) {
             SubscriptionTransitionData cur = it.next();
-            if (cur.getEffectiveTransitionTime().isAfter(clock.getUTCNow())) {
-                // Skip future events
-                continue;
-            }
-            if (cur.getTransitionType() == SubscriptionTransitionType.MIGRATE_BILLING) {
-                continue;
-            }
-            if (cur.getEventType() == EventType.API_USER &&
-                    (cur.getApiEventType() == ApiEventType.CHANGE ||
-                            cur.getApiEventType() == ApiEventType.RE_CREATE)) {
+            if (cur.getTransitionType() == SubscriptionTransitionType.CREATE ||
+                    cur.getTransitionType() == SubscriptionTransitionType.RE_CREATE ||
+                    cur.getTransitionType() == SubscriptionTransitionType.CHANGE ||
+                    cur.getTransitionType() == SubscriptionTransitionType.MIGRATE_ENTITLEMENT) {
                 return cur;
             }
         }
-        // CREATE event
-        return transitions.get(0);
+        throw new EntitlementError(String.format("Failed to find InitialTransitionForCurrentPlan id = %s", getId().toString()));
     }
 
     public boolean isSubscriptionFutureCancelled() {
         if (transitions == null) {
             return false;
         }
-
-        for (SubscriptionTransitionData cur : transitions) {
-            if (cur.getTransitionType() == SubscriptionTransitionType.MIGRATE_BILLING) {
-                continue;
-            }
-            if (cur.getEffectiveTransitionTime().isBefore(clock.getUTCNow()) ||
-                    cur.getEventType() == EventType.PHASE ||
-                        cur.getApiEventType() != ApiEventType.CANCEL) {
-                continue;
+        SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(clock, transitions,
+                Order.ASC_FROM_PAST, Kind.ENTITLEMENT, Visibility.ALL, TimeLimit.FUTURE_ONLY);
+        while (it.hasNext()) {
+            SubscriptionTransitionData cur = it.next();
+            if (cur.getTransitionType() == SubscriptionTransitionType.CANCEL) {
+                return true;
             }
-            return true;
         }
         return false;
     }
@@ -371,26 +333,20 @@ public class SubscriptionData extends CustomizableEntityBase implements Subscrip
         if (transitions == null) {
             throw new EntitlementError(String.format("No transitions for subscription %s", getId()));
         }
-
-        Iterator<SubscriptionTransitionData> it = ((LinkedList<SubscriptionTransitionData>) transitions).descendingIterator();
+        SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(clock, transitions,
+                Order.DESC_FROM_FUTURE, Kind.ENTITLEMENT, Visibility.ALL, TimeLimit.PAST_OR_PRESENT_ONLY);
         while (it.hasNext()) {
             SubscriptionTransitionData cur = it.next();
-            if (cur.getTransitionType() == SubscriptionTransitionType.MIGRATE_BILLING) {
-                continue;
-            }
-            if (cur.getEffectiveTransitionTime().isAfter(clock.getUTCNow())) {
-                // Skip future events
-                continue;
-            }
-            if (cur.getEventType() == EventType.PHASE
-                    || (cur.getEventType() == EventType.API_USER &&
-                            (cur.getApiEventType() == ApiEventType.CHANGE ||
-                                    cur.getApiEventType() == ApiEventType.RE_CREATE))) {
+
+            if (cur.getTransitionType() == SubscriptionTransitionType.PHASE ||
+                    cur.getTransitionType() == SubscriptionTransitionType.CREATE ||
+                    cur.getTransitionType() == SubscriptionTransitionType.RE_CREATE ||
+                    cur.getTransitionType() == SubscriptionTransitionType.CHANGE ||
+                    cur.getTransitionType() == SubscriptionTransitionType.MIGRATE_ENTITLEMENT) {
                 return cur.getEffectiveTransitionTime();
             }
         }
-        // CREATE event
-        return transitions.get(0).getEffectiveTransitionTime();
+        throw new EntitlementError(String.format("Failed to find CurrentPhaseStart id = %s", getId().toString()));
     }
 
     public void rebuildTransitions(final List<EntitlementEvent> events, final Catalog catalog) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java
new file mode 100644
index 0000000..fbab9b2
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.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.entitlement.api.user;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.exceptions.EntitlementError;
+import com.ning.billing.util.clock.Clock;
+
+public class SubscriptionTransitionDataIterator implements Iterator<SubscriptionTransitionData> {
+
+    private final Clock clock;
+    private final Iterator<SubscriptionTransitionData> it;
+    private final Kind kind;
+    private final TimeLimit timeLimit;
+    private final Visibility visibility;
+
+    private SubscriptionTransitionData next;
+
+    public enum Order {
+        ASC_FROM_PAST,
+        DESC_FROM_FUTURE
+    }
+
+    public enum Kind {
+        ENTITLEMENT,
+        BILLING,
+        ALL
+    }
+
+    public enum TimeLimit {
+        FUTURE_ONLY,
+        PAST_OR_PRESENT_ONLY,
+        ALL
+    }
+
+    public enum Visibility {
+        FROM_DISK_ONLY,
+        ALL
+    }
+
+    public SubscriptionTransitionDataIterator(Clock clock, LinkedList<SubscriptionTransitionData> transitions,
+            Order order, Kind kind, Visibility visibility, TimeLimit timeLimit) {
+        this.it = (order == Order.DESC_FROM_FUTURE) ? transitions.descendingIterator() : transitions.iterator();
+        this. clock = clock;
+        this.kind = kind;
+        this.timeLimit = timeLimit;
+        this.visibility = visibility;
+        this.next = null;
+    }
+
+    @Override
+    public boolean hasNext() {
+        do {
+            boolean hasNext = it.hasNext();
+            if (!hasNext) {
+                return false;
+            }
+            next = it.next();
+        }  while (shouldSkip(next));
+        return true;
+    }
+
+    private boolean shouldSkip(SubscriptionTransitionData input) {
+        if (visibility == Visibility.FROM_DISK_ONLY && !input.isFromDisk()) {
+            return true;
+        }
+        if ((kind == Kind.ENTITLEMENT && input.getTransitionType() == SubscriptionTransitionType.MIGRATE_BILLING) ||
+                (kind == Kind.BILLING && input.getTransitionType() == SubscriptionTransitionType.MIGRATE_ENTITLEMENT)) {
+            return true;
+        }
+        if ((timeLimit == TimeLimit.FUTURE_ONLY && ! input.getEffectiveTransitionTime().isAfter(clock.getUTCNow())) ||
+                ((timeLimit == TimeLimit.PAST_OR_PRESENT_ONLY && input.getEffectiveTransitionTime().isAfter(clock.getUTCNow())))) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public SubscriptionTransitionData next() {
+        return next;
+    }
+
+    @Override
+    public void remove() {
+        throw new EntitlementError("Operation SubscriptionTransitionDataIterator.remove not implemented");
+    }
+}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
index 513a5ca..ce84575 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
@@ -106,7 +106,7 @@ public class TestDefaultEntitlementBillingApi {
 		builder.setStartDate(subscriptionStartDate).setId(oneId);
 		subscription = new SubscriptionData(builder) {
 		    @Override
-            public List<SubscriptionTransition> getAllTransitions() {
+            public List<SubscriptionTransition> getBillingTransitions() {
 		    	return transitions;
 		    }
 		};
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
index 1e725bf..88c3825 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
@@ -66,12 +66,8 @@ public abstract class TestUserApiCancel extends TestApiBase {
             // CANCEL in trial period to get IMM policy
             subscription.cancel(clock.getUTCNow(), false);
             currentPhase = subscription.getCurrentPhase();
-
             testListener.isCompleted(1000);
 
-            List<SubscriptionTransition> allTransitions = subscription.getActiveTransitions();
-            printSubscriptionTransitions(allTransitions);
-
             assertNull(currentPhase);
             checkNextPhaseChange(subscription, 0, null);
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
index ee8490b..a56f13b 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
@@ -100,8 +100,6 @@ public abstract class TestUserApiCreate extends TestApiBase {
             assertDateWithin(subscription.getStartDate(), init, clock.getUTCNow());
             assertDateWithin(subscription.getBundleStartDate(), init, clock.getUTCNow());
 
-            printSubscriptionTransitions(subscription.getActiveTransitions());
-
             Plan currentPlan = subscription.getCurrentPlan();
             assertNotNull(currentPlan);
             assertEquals(currentPlan.getProduct().getName(), productName);
@@ -141,8 +139,6 @@ public abstract class TestUserApiCreate extends TestApiBase {
             assertDateWithin(subscription.getStartDate(), init, clock.getUTCNow());
             assertDateWithin(subscription.getBundleStartDate(), init, clock.getUTCNow());
 
-            printSubscriptionTransitions(subscription.getActiveTransitions());
-
             Plan currentPlan = subscription.getCurrentPlan();
             assertNotNull(currentPlan);
             assertEquals(currentPlan.getProduct().getName(), productName);
@@ -152,11 +148,6 @@ public abstract class TestUserApiCreate extends TestApiBase {
             PlanPhase currentPhase = subscription.getCurrentPhase();
             assertNotNull(currentPhase);
             assertEquals(currentPhase.getPhaseType(), PhaseType.TRIAL);
-
-            List<SubscriptionTransition> transitions = subscription.getActiveTransitions();
-            assertNotNull(transitions);
-            assertEquals(transitions.size(), 1);
-
             assertTrue(testListener.isCompleted(5000));
 
             List<EntitlementEvent> events = dao.getPendingEventsForSubscription(subscription.getId());

pom.xml 69(+45 -24)

diff --git a/pom.xml b/pom.xml
index 406dc40..9a6662e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,8 @@
     OR CONDITIONS OF ANY KIND, either express or implied. See the ~ License for 
     the specific language governing permissions and limitations ~ under the License. -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <parent>
         <groupId>org.sonatype.oss</groupId>
         <artifactId>oss-parent</artifactId>
@@ -332,16 +333,16 @@
                 </configuration>
             </plugin>
             <plugin>
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-jar-plugin</artifactId>
-              <version>2.2</version>
-              <executions>
-                <execution>
-                  <goals>
-                    <goal>test-jar</goal>
-                  </goals>
-               </execution>
-              </executions>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.2</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
@@ -453,24 +454,44 @@
                 </configuration>
             </plugin>
             <plugin>
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-source-plugin</artifactId>
-              <version>2.1.2</version>
-              <executions>
-                <execution>
-                  <id>attach-sources</id>
-                  <phase>verify</phase>
-                  <goals>
-                    <goal>jar</goal>
-                    <goal>test-jar</goal>
-                  </goals>
-                </execution>
-              </executions>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+                <version>2.1.2</version>
+                <executions>
+                    <execution>
+                        <id>attach-sources</id>
+                        <phase>verify</phase>
+                        <goals>
+                            <goal>jar</goal>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
             </plugin>
         </plugins>
     </build>
     <profiles>
         <profile>
+            <id>localtest</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <version>2.11</version>
+                        <configuration>
+                            <useManifestOnlyJar>false</useManifestOnlyJar>
+                            <systemPropertyVariables>
+                                <log4j.configuration>file:${project.basedir}/src/test/resources/log4j.xml</log4j.configuration>
+                                <com.ning.billing.dbi.test.useLocalDb>true</com.ning.billing.dbi.test.useLocalDb>
+                                <com.ning.billing.dbi.jdbc.url>jdbc:mysql://127.0.0.1:3306/test_killbill</com.ning.billing.dbi.jdbc.url>
+                            </systemPropertyVariables>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
             <id>sonatype-oss-release</id>
             <build>
                 <plugins>

util/pom.xml 10(+0 -10)

diff --git a/util/pom.xml b/util/pom.xml
index 9e67775..10cb192 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -33,13 +33,8 @@
             <artifactId>jdbi</artifactId>
         </dependency>
         <dependency>
-            <groupId>mysql</groupId>
-            <artifactId>mysql-connector-java</artifactId>
-        </dependency>
-        <dependency>
             <groupId>com.google.inject</groupId>
             <artifactId>guice</artifactId>
-            <version>3.0</version>
         </dependency>
         <dependency>
             <groupId>org.skife.config</groupId>
@@ -93,11 +88,6 @@
             <scope>runtime</scope>
         </dependency>
         <dependency>
-            <groupId>com.mysql</groupId>
-            <artifactId>management-dbfiles</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
             <groupId>com.jayway.awaitility</groupId>
             <artifactId>awaitility</artifactId>
             <scope>test</scope>
diff --git a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
index 9237997..98d498c 100644
--- a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
+++ b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
@@ -110,11 +110,6 @@ public class MysqlTestingHelper
             return;
         }
 
-        if (mysqldResource == null || !mysqldResource.isRunning()) {
-            log.error("Asked to cleanup table " + table + " but MySQL is not running!");
-            return;
-        }
-
         log.info("Deleting table: " + table);
         final IDBI dbi = getDBI();
         dbi.withHandle(new HandleCallback<Void>()
diff --git a/util/src/test/java/com/ning/billing/util/globallocker/TestMysqlGlobalLocker.java b/util/src/test/java/com/ning/billing/util/globallocker/TestMysqlGlobalLocker.java
index 1fd8290..9f60162 100644
--- a/util/src/test/java/com/ning/billing/util/globallocker/TestMysqlGlobalLocker.java
+++ b/util/src/test/java/com/ning/billing/util/globallocker/TestMysqlGlobalLocker.java
@@ -19,6 +19,7 @@ package com.ning.billing.util.globallocker;
 import java.io.IOException;
 import java.util.UUID;
 
+import org.apache.commons.io.IOUtils;
 import org.skife.jdbi.v2.Handle;
 import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.TransactionCallback;
@@ -49,8 +50,9 @@ public class TestMysqlGlobalLocker {
 
     @BeforeClass(alwaysRun=true)
     public void setup() throws IOException  {
+        final String testDdl = IOUtils.toString(TestMysqlGlobalLocker.class.getResourceAsStream("/com/ning/billing/util/ddl_test.sql"));
         helper.startMysql();
-        createSimpleTable(dbi);
+        helper.initDb(testDdl);
     }
 
     @AfterClass(alwaysRun=true)
@@ -71,7 +73,7 @@ public class TestMysqlGlobalLocker {
             @Override
             public Void inTransaction(Handle conn, TransactionStatus status)
                     throws Exception {
-                conn.execute("insert into dummy (dummy_id) values ('" + UUID.randomUUID().toString()  + "')");
+                conn.execute("insert into dummy2 (dummy_id) values ('" + UUID.randomUUID().toString()  + "')");
                 return null;
             }
         });
@@ -90,22 +92,6 @@ public class TestMysqlGlobalLocker {
         Assert.assertEquals(locker.isFree(LockerService.INVOICE, lockName), Boolean.TRUE);
     }
 
-    private void createSimpleTable(IDBI dbi) {
-        dbi.inTransaction(new TransactionCallback<Void>() {
-
-            @Override
-            public Void inTransaction(Handle h, TransactionStatus status)
-                    throws Exception {
-                h.execute("create table dummy " +
-                        "(id int(11) unsigned NOT NULL AUTO_INCREMENT, " +
-                        "dummy_id char(36) NOT NULL, " +
-                        "PRIMARY KEY(id)" +
-                		") ENGINE=innodb;");
-                return null;
-            }
-        });
-    }
-
     public final static class TestMysqlGlobalLockerModule extends AbstractModule {
 
         @Override
diff --git a/util/src/test/java/com/ning/billing/util/tag/TagStoreModuleMock.java b/util/src/test/java/com/ning/billing/util/tag/TagStoreModuleMock.java
index 7bf9572..3e6ad2a 100644
--- a/util/src/test/java/com/ning/billing/util/tag/TagStoreModuleMock.java
+++ b/util/src/test/java/com/ning/billing/util/tag/TagStoreModuleMock.java
@@ -16,31 +16,21 @@
 
 package com.ning.billing.util.tag;
 
-import java.io.IOException;
 
 import org.skife.jdbi.v2.IDBI;
 
 import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.util.clock.MockClockModule;
 import com.ning.billing.util.glue.TagStoreModule;
 
 public class TagStoreModuleMock extends TagStoreModule {
-    private final MysqlTestingHelper helper = new MysqlTestingHelper();
-
-    public void startDb() throws IOException {
-        helper.startMysql();
-    }
-
-    public void initDb(String ddl) throws IOException {
-        helper.initDb(ddl);
-    }
-
-    public void stopDb() {
-        helper.stopMysql();
-    }
 
     @Override
     protected void configure() {
+        MysqlTestingHelper helper = new MysqlTestingHelper();
         bind(IDBI.class).toInstance(helper.getDBI());
+        bind(MysqlTestingHelper.class).toInstance(helper);
+        install(new MockClockModule());
         super.configure();
     }
 }
diff --git a/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java b/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
index c913791..727a7cc 100644
--- a/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
+++ b/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
@@ -20,62 +20,74 @@ import java.io.IOException;
 import java.util.List;
 import java.util.UUID;
 import org.apache.commons.io.IOUtils;
+import org.skife.jdbi.v2.Handle;
 import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.Transaction;
 import org.skife.jdbi.v2.TransactionStatus;
+import org.skife.jdbi.v2.tweak.HandleCallback;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.testng.annotations.Guice;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Stage;
+import com.google.inject.Inject;
 import com.ning.billing.account.api.ControlTagType;
+import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.util.api.TagDefinitionApiException;
 import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.DefaultClock;
-import com.ning.billing.util.clock.MockClockModule;
 import com.ning.billing.util.tag.dao.TagDefinitionDao;
 import com.ning.billing.util.tag.dao.TagStoreSqlDao;
 
+
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
-@Test(groups={"util"})
+
+@Test(groups={"slow"})
+@Guice(modules = TagStoreModuleMock.class)
 public class TestTagStore {
     private final static String ACCOUNT_TYPE = "ACCOUNT";
-    private final Clock clock = new DefaultClock();
+
+    @Inject
+    private MysqlTestingHelper helper;
+
+    @Inject
     private IDBI dbi;
-    private TagDefinition tag1;
-    private TagDefinition tag2;
-    private TagStoreModuleMock module;
+
+    @Inject
     private TagStoreSqlDao tagStoreSqlDao;
+
+    @Inject
     private TagDefinitionDao tagDefinitionDao;
+
+    @Inject
+    private Clock clock;
+
+    private TagDefinition tag1;
+    private TagDefinition tag2;
+
+
     private final Logger log = LoggerFactory.getLogger(TestTagStore.class);
 
     @BeforeClass(alwaysRun = true)
     protected void setup() throws IOException {
         // Health check test to make sure MySQL is setup properly
         try {
-            module = new TagStoreModuleMock();
             final String utilDdl = IOUtils.toString(TestTagStore.class.getResourceAsStream("/com/ning/billing/util/ddl.sql"));
 
-            module.startDb();
-            module.initDb(utilDdl);
-
-            final Injector injector = Guice.createInjector(Stage.DEVELOPMENT, module, new MockClockModule());
-            dbi = injector.getInstance(IDBI.class);
-
-            tagStoreSqlDao = injector.getInstance(TagStoreSqlDao.class);
+            helper.startMysql();
+            helper.initDb(utilDdl);
             tagStoreSqlDao.test();
 
-            tagDefinitionDao = injector.getInstance(TagDefinitionDao.class);
+            cleanupTags();
             tag1 = tagDefinitionDao.create("tag1", "First tag", "test");
             tag2 = tagDefinitionDao.create("tag2", "Second tag", "test");
+
         }
         catch (Throwable t) {
             log.error("Failed to start tag store tests", t);
@@ -86,7 +98,7 @@ public class TestTagStore {
     @AfterClass(alwaysRun = true)
     public void stopMysql()
     {
-        module.stopDb();
+        helper.stopMysql();
     }
 
     private void saveTags(final TagStoreSqlDao dao, final String objectType, final String accountId, final List<Tag> tagList)  {
@@ -100,6 +112,22 @@ public class TestTagStore {
         });
     }
 
+
+    private void cleanupTags() {
+        try {
+            helper.getDBI().withHandle(new HandleCallback<Void>() {
+                @Override
+                public Void withHandle(Handle handle) throws Exception {
+                    handle.createScript("delete from tag_definitions").execute();
+                    handle.createScript("delete from tag_definition_history").execute();
+                    handle.createScript("delete from tags").execute();
+                    handle.createScript("delete from tag_history").execute();
+                    return null;
+                }
+            });
+        } catch (Throwable ignore) {
+        }
+    }
     @Test
     public void testTagCreationAndRetrieval() {
         UUID accountId = UUID.randomUUID();
diff --git a/util/src/test/java/com/ning/billing/util/validation/TestValidationManager.java b/util/src/test/java/com/ning/billing/util/validation/TestValidationManager.java
index b7e5bc6..bb7ac85 100644
--- a/util/src/test/java/com/ning/billing/util/validation/TestValidationManager.java
+++ b/util/src/test/java/com/ning/billing/util/validation/TestValidationManager.java
@@ -17,7 +17,10 @@
 package com.ning.billing.util.validation;
 
 import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.util.globallocker.TestMysqlGlobalLocker;
 import com.ning.billing.util.validation.dao.DatabaseSchemaDao;
+
+import org.apache.commons.io.IOUtils;
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.IDBI;
 import org.testng.annotations.AfterClass;
@@ -38,7 +41,7 @@ public class TestValidationManager {
     private static final String TABLE_NAME = "validation_test";
 
     private ValidationManager vm;
-    
+
     @BeforeClass(alwaysRun = true)
     public void setup() throws IOException {
         setupDatabase();
@@ -53,11 +56,9 @@ public class TestValidationManager {
     }
 
     private void setupDatabase() throws IOException {
+        final String testDdl = IOUtils.toString(TestMysqlGlobalLocker.class.getResourceAsStream("/com/ning/billing/util/ddl_test.sql"));
         helper.startMysql();
-        StringBuilder ddl = new StringBuilder();
-        ddl.append(String.format("DROP TABLE IF EXISTS %s;", TABLE_NAME));
-        ddl.append(String.format("CREATE TABLE %s (column1 varchar(25), column2 char(2) NOT NULL, column3 numeric(10,4), column4 datetime) ENGINE = innodb;", TABLE_NAME));
-        helper.initDb(ddl.toString());
+        helper.initDb(testDdl);
     }
 
     @AfterClass(alwaysRun = true)
diff --git a/util/src/test/resources/com/ning/billing/util/ddl_test.sql b/util/src/test/resources/com/ning/billing/util/ddl_test.sql
index 50de498..1322a02 100644
--- a/util/src/test/resources/com/ning/billing/util/ddl_test.sql
+++ b/util/src/test/resources/com/ning/billing/util/ddl_test.sql
@@ -4,3 +4,18 @@ CREATE TABLE dummy (
     value varchar(256) NOT NULL,
     PRIMARY KEY(dummy_id)
 ) ENGINE = innodb;
+
+DROP TABLE IF EXISTS dummy2;
+CREATE TABLE dummy2 (
+    id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    dummy_id char(36) NOT NULL,
+    PRIMARY KEY(id)
+) ENGINE = innodb;
+
+DROP TABLE IF EXISTS validation_test;
+CREATE TABLE validation_test (
+    column1 varchar(25),
+    column2 char(2) NOT NULL,
+    column3 numeric(10,4),
+    column4 datetime
+) ENGINE = innodb;