killbill-memoizeit

beatrix: add Analytics test Add a simple test for Analytics

6/22/2012 6:49:19 PM

Details

diff --git a/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java b/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java
new file mode 100644
index 0000000..402f17d
--- /dev/null
+++ b/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2010-2012 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.analytics.api.user;
+
+import javax.inject.Inject;
+import java.util.List;
+
+import com.ning.billing.analytics.dao.AnalyticsDao;
+import com.ning.billing.analytics.model.BusinessAccount;
+import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
+
+// Note: not exposed in api yet
+public class DefaultAnalyticsUserApi {
+    private final AnalyticsDao analyticsDao;
+
+    @Inject
+    public DefaultAnalyticsUserApi(final AnalyticsDao analyticsDao) {
+        this.analyticsDao = analyticsDao;
+    }
+
+    public BusinessAccount getAccountByKey(final String accountKey) {
+        return analyticsDao.getAccountByKey(accountKey);
+    }
+
+    public List<BusinessSubscriptionTransition> getTransitionsForBundle(final String key) {
+        return analyticsDao.getTransitionsByKey(key);
+    }
+}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java
index 66a8a26..bd3cda9 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java
@@ -16,12 +16,17 @@
 
 package com.ning.billing.analytics.dao;
 
+import java.util.List;
+
 import com.ning.billing.analytics.model.BusinessAccount;
 import com.ning.billing.analytics.model.BusinessInvoice;
 import com.ning.billing.analytics.model.BusinessInvoiceItem;
+import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
 
 public interface AnalyticsDao {
     BusinessAccount getAccountByKey(final String accountKey);
 
+    List<BusinessSubscriptionTransition> getTransitionsByKey(final String externalKey);
+
     void createInvoice(final String accountKey, final BusinessInvoice invoice, final Iterable<BusinessInvoiceItem> invoiceItems);
 }
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java
index 87da400..1f44af9 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java
@@ -17,6 +17,7 @@
 package com.ning.billing.analytics.dao;
 
 import javax.inject.Inject;
+import java.util.List;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
@@ -26,14 +27,19 @@ import org.skife.jdbi.v2.TransactionStatus;
 import com.ning.billing.analytics.model.BusinessAccount;
 import com.ning.billing.analytics.model.BusinessInvoice;
 import com.ning.billing.analytics.model.BusinessInvoiceItem;
+import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
 
 public class DefaultAnalyticsDao implements AnalyticsDao {
     private final BusinessAccountSqlDao accountSqlDao;
+    private final BusinessSubscriptionTransitionSqlDao subscriptionTransitionSqlDao;
     private final BusinessInvoiceSqlDao invoiceSqlDao;
 
     @Inject
-    public DefaultAnalyticsDao(final BusinessAccountSqlDao accountSqlDao, final BusinessInvoiceSqlDao invoiceSqlDao) {
+    public DefaultAnalyticsDao(final BusinessAccountSqlDao accountSqlDao,
+                               final BusinessSubscriptionTransitionSqlDao subscriptionTransitionSqlDao,
+                               final BusinessInvoiceSqlDao invoiceSqlDao) {
         this.accountSqlDao = accountSqlDao;
+        this.subscriptionTransitionSqlDao = subscriptionTransitionSqlDao;
         this.invoiceSqlDao = invoiceSqlDao;
     }
 
@@ -43,6 +49,11 @@ public class DefaultAnalyticsDao implements AnalyticsDao {
     }
 
     @Override
+    public List<BusinessSubscriptionTransition> getTransitionsByKey(final String externalKey) {
+        return subscriptionTransitionSqlDao.getTransitions(externalKey);
+    }
+
+    @Override
     public void createInvoice(final String accountKey, final BusinessInvoice invoice, final Iterable<BusinessInvoiceItem> invoiceItems) {
         invoiceSqlDao.inTransaction(new Transaction<Void, BusinessInvoiceSqlDao>() {
             @Override
diff --git a/analytics/src/main/java/com/ning/billing/analytics/setup/AnalyticsModule.java b/analytics/src/main/java/com/ning/billing/analytics/setup/AnalyticsModule.java
index 3d3c2e4..82433ec 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/setup/AnalyticsModule.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/setup/AnalyticsModule.java
@@ -24,6 +24,7 @@ import com.ning.billing.analytics.BusinessSubscriptionTransitionRecorder;
 import com.ning.billing.analytics.BusinessTagRecorder;
 import com.ning.billing.analytics.api.AnalyticsService;
 import com.ning.billing.analytics.api.DefaultAnalyticsService;
+import com.ning.billing.analytics.api.user.DefaultAnalyticsUserApi;
 import com.ning.billing.analytics.dao.AnalyticsDao;
 import com.ning.billing.analytics.dao.BusinessAccountSqlDao;
 import com.ning.billing.analytics.dao.BusinessAccountTagSqlDao;
@@ -65,5 +66,7 @@ public class AnalyticsModule extends AbstractModule {
 
         bind(AnalyticsDao.class).to(DefaultAnalyticsDao.class).asEagerSingleton();
         bind(AnalyticsService.class).to(DefaultAnalyticsService.class).asEagerSingleton();
+
+        bind(DefaultAnalyticsUserApi.class).asEagerSingleton();
     }
 }
diff --git a/analytics/src/test/java/com/ning/billing/analytics/dao/TestDefaultAnalyticsDao.java b/analytics/src/test/java/com/ning/billing/analytics/dao/TestDefaultAnalyticsDao.java
index 20b3517..a7f1479 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/dao/TestDefaultAnalyticsDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/dao/TestDefaultAnalyticsDao.java
@@ -36,6 +36,7 @@ import com.ning.billing.catalog.api.Currency;
 
 public class TestDefaultAnalyticsDao extends TestWithEmbeddedDB {
     private BusinessAccountSqlDao accountSqlDao;
+    private BusinessSubscriptionTransitionSqlDao subscriptionTransitionSqlDao;
     private BusinessInvoiceSqlDao invoiceSqlDao;
     private BusinessInvoiceItemSqlDao invoiceItemSqlDao;
     private AnalyticsDao analyticsDao;
@@ -44,9 +45,10 @@ public class TestDefaultAnalyticsDao extends TestWithEmbeddedDB {
     public void setUp() throws Exception {
         final IDBI dbi = helper.getDBI();
         accountSqlDao = dbi.onDemand(BusinessAccountSqlDao.class);
+        subscriptionTransitionSqlDao = dbi.onDemand(BusinessSubscriptionTransitionSqlDao.class);
         invoiceSqlDao = dbi.onDemand(BusinessInvoiceSqlDao.class);
         invoiceItemSqlDao = dbi.onDemand(BusinessInvoiceItemSqlDao.class);
-        analyticsDao = new DefaultAnalyticsDao(accountSqlDao, invoiceSqlDao);
+        analyticsDao = new DefaultAnalyticsDao(accountSqlDao, subscriptionTransitionSqlDao, invoiceSqlDao);
     }
 
     @Test(groups = "slow")

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

diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index 4f66b35..805cd58 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -108,6 +108,11 @@
         </dependency>
         <dependency>
             <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-analytics</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
             <artifactId>killbill-overdue</artifactId>
             <scope>test</scope>
         </dependency>
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixModule.java
index 0e0ea55..c26fac5 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixModule.java
@@ -29,6 +29,7 @@ import com.google.inject.Inject;
 import com.google.inject.Injector;
 import com.ning.billing.account.api.AccountService;
 import com.ning.billing.account.glue.AccountModule;
+import com.ning.billing.analytics.setup.AnalyticsModule;
 import com.ning.billing.beatrix.integration.overdue.IntegrationTestOverdueModule;
 import com.ning.billing.beatrix.lifecycle.DefaultLifecycle;
 import com.ning.billing.beatrix.lifecycle.Lifecycle;
@@ -96,6 +97,7 @@ public class BeatrixModule extends AbstractModule {
         install(new TagStoreModule());
         install(new CustomFieldModule());
         install(new AccountModule());
+        install(new AnalyticsModule());
         install(new CatalogModule());
         install(new DefaultEntitlementModule());
         install(new DefaultInvoiceModule());
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java
new file mode 100644
index 0000000..4edd6d6
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2010-2012 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;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.UUID;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.account.api.MutableAccountData;
+import com.ning.billing.analytics.model.BusinessAccount;
+import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
+import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
+import com.ning.billing.analytics.utils.Rounder;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
+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.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+
+@Guice(modules = BeatrixModule.class)
+public class TestAnalytics extends TestIntegrationBase {
+    @BeforeMethod(groups = "slow")
+    public void setUpAnalyticsHandler() throws Exception {
+        busService.getBus().register(analyticsListener);
+    }
+
+    @AfterMethod(groups = "slow")
+    public void tearDownAnalyticsHandler() throws Exception {
+        busService.getBus().unregister(analyticsListener);
+    }
+
+    @Test(groups = "slow")
+    public void testAnalyticsEvents() throws Exception {
+        // Create an account
+        final Account account = verifyAccountCreation();
+
+        // Update some fields
+        verifyAccountUpdate(account);
+
+        // Create a bundle
+        final SubscriptionBundle bundle = verifyFirstBundle(account);
+
+        // Add a subscription
+        verifyFirstSubscription(account, bundle);
+    }
+
+    private Account verifyAccountCreation() throws Exception {
+        final AccountData accountData = getAccountData(1);
+
+        // Verify BAC is empty
+        Assert.assertNull(analyticsUserApi.getAccountByKey(accountData.getExternalKey()));
+
+        // Create an account
+        final Account account = createAccountWithPaymentMethod(accountData);
+        Assert.assertNotNull(account);
+
+        waitALittle();
+
+        // Verify Analytics got the account creation event
+        final BusinessAccount businessAccount = analyticsUserApi.getAccountByKey(account.getExternalKey());
+        Assert.assertNotNull(businessAccount);
+        // No balance yet
+        Assert.assertEquals(businessAccount.getBalance().doubleValue(), Rounder.round(BigDecimal.ZERO));
+        Assert.assertEquals(businessAccount.getKey(), account.getExternalKey());
+        // No invoice yet
+        Assert.assertNull(businessAccount.getLastInvoiceDate());
+        // No payment yet
+        Assert.assertNull(businessAccount.getLastPaymentStatus());
+        Assert.assertEquals(businessAccount.getName(), account.getName());
+        // No invoice balance yet
+        Assert.assertEquals(businessAccount.getTotalInvoiceBalance().doubleValue(), Rounder.round(BigDecimal.ZERO));
+        // TODO - payment fields
+        //Assert.assertNotNull(businessAccount.getBillingAddressCountry());
+        //Assert.assertNotNull(businessAccount.getCreditCardType());
+        //Assert.assertNotNull(businessAccount.getPaymentMethod());
+
+        return account;
+    }
+
+    private void verifyAccountUpdate(final Account account) throws InterruptedException {
+        final MutableAccountData mutableAccountData = account.toMutableAccountData();
+
+        mutableAccountData.setName(UUID.randomUUID().toString().substring(0, 20));
+
+        try {
+            accountUserApi.updateAccount(account.getId(), mutableAccountData, context);
+        } catch (AccountApiException e) {
+            Assert.fail("Unable to update account", e);
+        }
+
+        waitALittle();
+
+        // Verify Analytics got the account update event
+        final BusinessAccount businessAccount = analyticsUserApi.getAccountByKey(mutableAccountData.getExternalKey());
+        Assert.assertNotNull(businessAccount);
+        // No balance yet
+        Assert.assertEquals(businessAccount.getBalance().doubleValue(), Rounder.round(BigDecimal.ZERO));
+        Assert.assertEquals(businessAccount.getKey(), mutableAccountData.getExternalKey());
+        // No invoice yet
+        Assert.assertNull(businessAccount.getLastInvoiceDate());
+        // No payment yet
+        Assert.assertNull(businessAccount.getLastPaymentStatus());
+        Assert.assertEquals(businessAccount.getName(), mutableAccountData.getName());
+        // No invoice balance yet
+        Assert.assertEquals(businessAccount.getTotalInvoiceBalance().doubleValue(), Rounder.round(BigDecimal.ZERO));
+        // TODO - payment fields
+        //Assert.assertNotNull(businessAccount.getBillingAddressCountry());
+        //Assert.assertNotNull(businessAccount.getCreditCardType());
+        //Assert.assertNotNull(businessAccount.getPaymentMethod());
+    }
+
+    private SubscriptionBundle verifyFirstBundle(final Account account) throws EntitlementUserApiException, InterruptedException {
+        // Add a bundle
+        final SubscriptionBundle bundle = entitlementUserApi.createBundleForAccount(account.getId(), UUID.randomUUID().toString(), context);
+        Assert.assertNotNull(bundle);
+
+        waitALittle();
+
+        // Verify BST is still empty since no subscription has been added yet
+        Assert.assertEquals(analyticsUserApi.getTransitionsForBundle(bundle.getKey()).size(), 0);
+
+        return bundle;
+    }
+
+    private Subscription verifyFirstSubscription(final Account account, final SubscriptionBundle bundle) throws EntitlementUserApiException, InterruptedException, CatalogApiException {
+        // Add a subscription
+        final String productName = "Shotgun";
+        final BillingPeriod term = BillingPeriod.MONTHLY;
+        final String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
+        final PlanPhaseSpecifier phaseSpecifier = new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null);
+        final Subscription subscription = entitlementUserApi.createSubscription(bundle.getId(), phaseSpecifier, null, context);
+
+        waitALittle();
+
+        // BST should have one transition
+        final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
+        Assert.assertEquals(transitions.size(), 1);
+        final BusinessSubscriptionTransition transition = transitions.get(0);
+        Assert.assertEquals(transition.getExternalKey(), bundle.getKey());
+        Assert.assertEquals(transition.getAccountKey(), account.getExternalKey());
+        Assert.assertEquals(transition.getEvent().getCategory(), phaseSpecifier.getProductCategory());
+        Assert.assertEquals(transition.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.ADD);
+
+        // This is the first transition
+        Assert.assertNull(transition.getPreviousSubscription());
+
+        Assert.assertEquals(transition.getNextSubscription().getBillingPeriod(), subscription.getCurrentPhase().getBillingPeriod().toString());
+        Assert.assertEquals(transition.getNextSubscription().getBundleId(), subscription.getBundleId());
+        Assert.assertEquals(transition.getNextSubscription().getCurrency(), account.getCurrency().toString());
+        Assert.assertEquals(transition.getNextSubscription().getPhase(), subscription.getCurrentPhase().getPhaseType().toString());
+        // Trial: fixed price of zero
+        Assert.assertEquals(transition.getNextSubscription().getPrice().doubleValue(), subscription.getCurrentPhase().getFixedPrice().getPrice(account.getCurrency()).doubleValue());
+        Assert.assertEquals(transition.getNextSubscription().getPriceList(), subscription.getCurrentPriceList().getName());
+        Assert.assertEquals(transition.getNextSubscription().getProductCategory(), subscription.getCurrentPlan().getProduct().getCategory());
+        Assert.assertEquals(transition.getNextSubscription().getProductName(), subscription.getCurrentPlan().getProduct().getName());
+        Assert.assertEquals(transition.getNextSubscription().getProductType(), subscription.getCurrentPlan().getProduct().getCatalogName());
+        Assert.assertEquals(transition.getNextSubscription().getSlug(), subscription.getCurrentPhase().getName());
+        Assert.assertEquals(transition.getNextSubscription().getStartDate(), subscription.getStartDate());
+        Assert.assertEquals(transition.getNextSubscription().getState(), subscription.getState());
+        Assert.assertEquals(transition.getNextSubscription().getSubscriptionId(), subscription.getId());
+
+        return subscription;
+    }
+
+    private void waitALittle() throws InterruptedException {
+        // We especially need to wait for entitlement events
+        Thread.sleep(1000);
+    }
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
index 43ccf5d..48202da 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
@@ -37,6 +37,8 @@ import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountData;
 import com.ning.billing.account.api.AccountService;
 import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.analytics.AnalyticsListener;
+import com.ning.billing.analytics.api.user.DefaultAnalyticsUserApi;
 import com.ning.billing.api.TestApiListener;
 import com.ning.billing.api.TestListenerStatus;
 import com.ning.billing.beatrix.lifecycle.Lifecycle;
@@ -124,6 +126,12 @@ public class TestIntegrationBase implements TestListenerStatus {
     @Inject
     protected AccountUserApi accountUserApi;
 
+    @Inject
+    protected DefaultAnalyticsUserApi analyticsUserApi;
+
+    @Inject
+    protected AnalyticsListener analyticsListener;
+
     protected TestApiListener busHandler;
 
 
@@ -152,6 +160,7 @@ public class TestIntegrationBase implements TestListenerStatus {
 
     protected void setupMySQL() throws IOException {
         final String accountDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/account/ddl.sql"));
+        final String analyticsDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/analytics/ddl.sql"));
         final String entitlementDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/entitlement/ddl.sql"));
         final String invoiceDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/invoice/ddl.sql"));
         final String paymentDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/payment/ddl.sql"));
@@ -161,6 +170,7 @@ public class TestIntegrationBase implements TestListenerStatus {
         helper.startMysql();
 
         helper.initDb(accountDdl);
+        helper.initDb(analyticsDdl);
         helper.initDb(entitlementDdl);
         helper.initDb(invoiceDdl);
         helper.initDb(paymentDdl);