killbill-memoizeit

jaxrs: fix catalog endpoints Reported-by: Praveen Agrawal

7/27/2013 11:46:22 AM

Details

diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CatalogJsonSimple.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CatalogJsonSimple.java
index e723de3..e55829c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CatalogJsonSimple.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CatalogJsonSimple.java
@@ -13,123 +13,153 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
+
 package com.ning.billing.jaxrs.json;
 
 import java.math.BigDecimal;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Function;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Lists;
 import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.CurrencyValueNull;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.Price;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.StaticCatalog;
 
-@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
 public class CatalogJsonSimple {
 
     private final String name;
-    private final ProductJson [] products;
+    private final List<ProductJson> products;
 
-    public CatalogJsonSimple(StaticCatalog catalog) throws CatalogApiException {
-        name = catalog.getCatalogName();
-
-        Map<String, ProductJson> productMap = new HashMap<String, CatalogJsonSimple.ProductJson>();
+    @JsonCreator
+    public CatalogJsonSimple(@JsonProperty("name") final String name,
+                             @JsonProperty("products") final List<ProductJson> products) {
+        this.name = name;
+        this.products = products;
+    }
 
-        Plan [] plans = catalog.getCurrentPlans();
-        for (Plan plan : plans) {
+    public CatalogJsonSimple(final StaticCatalog catalog) throws CatalogApiException {
+        name = catalog.getCatalogName();
 
-            Product product = plan.getProduct();
-            ProductJson jProduct = productMap.get(product.getName());
-            if (jProduct == null) {
-                jProduct = new ProductJson(product.getCategory().toString(),
-                        product.getName(),
-                        toProductNames(product.getIncluded()), toProductNames(product.getAvailable()));
-                productMap.put(product.getName(), jProduct);
+        final Plan[] plans = catalog.getCurrentPlans();
+        final Map<String, ProductJson> productMap = new HashMap<String, ProductJson>();
+        for (final Plan plan : plans) {
+            // Build the product associated with this plan
+            final Product product = plan.getProduct();
+            ProductJson productJson = productMap.get(product.getName());
+            if (productJson == null) {
+                productJson = new ProductJson(product.getCategory().toString(),
+                                              product.getName(),
+                                              toProductNames(product.getIncluded()),
+                                              toProductNames(product.getAvailable()));
+                productMap.put(product.getName(), productJson);
             }
 
-            int i = 0 ;
-            PhaseJson [] phases = new PhaseJson[plan.getAllPhases().length];
-            for (PlanPhase phase : plan.getAllPhases()) {
-
-                Map<String, BigDecimal> prices = new HashMap<String, BigDecimal>();
+            // Build the phases associated with this plan
+            final List<PhaseJson> phases = new LinkedList<PhaseJson>();
+            for (final PlanPhase phase : plan.getAllPhases()) {
+                final List<PriceJson> prices = new LinkedList<PriceJson>();
                 if (phase.getRecurringPrice() != null) {
-                    for (Price cur : phase.getRecurringPrice().getPrices()) {
-                        prices.put(cur.getCurrency().toString(), cur.getValue());
+                    for (final Price price : phase.getRecurringPrice().getPrices()) {
+                        prices.add(new PriceJson(price));
                     }
                 }
-                PhaseJson jPhase = new PhaseJson(phase.getPhaseType().toString(), prices);
-                phases[i++] = jPhase;
+
+                final PhaseJson phaseJson = new PhaseJson(phase.getPhaseType().toString(), prices);
+                phases.add(phaseJson);
             }
-            PlanJson jPlan = new PlanJson(plan.getName(), phases);
-            jProduct.addPlan(jPlan);
+
+            final PlanJson planJson = new PlanJson(plan.getName(), phases);
+            productJson.getPlans().add(planJson);
         }
-        products = productMap.values().toArray(new ProductJson[productMap.values().size()]);
+
+        products = ImmutableList.<ProductJson>copyOf(productMap.values());
     }
 
-    private Collection<String> toProductNames(Product [] in) {
-        return Collections2.transform(Lists.newArrayList(in), new Function<Product, String>() {
-            @Override
-            public String apply(Product input) {
-                return input.getName();
-            }
-        });
+    private List<String> toProductNames(final Product[] in) {
+        return Lists.transform(ImmutableList.<Product>copyOf(in),
+                               new Function<Product, String>() {
+                                   @Override
+                                   public String apply(final Product input) {
+                                       return input.getName();
+                                   }
+                               });
     }
 
-    @JsonCreator
-    public CatalogJsonSimple(@JsonProperty("name") final String name,
-                             @JsonProperty("products") ProductJson[] products) {
-        this.name = name;
-        this.products = products;
+    public List<ProductJson> getProducts() {
+        return products;
     }
 
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("CatalogJsonSimple{");
+        sb.append("name='").append(name).append('\'');
+        sb.append(", products=").append(products);
+        sb.append('}');
+        return sb.toString();
+    }
 
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
 
-    public ProductJson[] getProducts() {
-        return products;
+        final CatalogJsonSimple that = (CatalogJsonSimple) o;
+
+        if (name != null ? !name.equals(that.name) : that.name != null) {
+            return false;
+        }
+        if (products != null ? !products.equals(that.products) : that.products != null) {
+            return false;
+        }
+
+        return true;
     }
 
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (products != null ? products.hashCode() : 0);
+        return result;
+    }
 
-    @JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
     public static class ProductJson {
 
         private final String type;
         private final String name;
-        private final String [] included;
-        private final String [] available;
         private final List<PlanJson> plans;
-
+        private final List<String> included;
+        private final List<String> available;
 
         @JsonCreator
-        public ProductJson(@JsonProperty("type") String type,
-                @JsonProperty("name") String name,
-                @JsonProperty("plans") List<PlanJson> plans,
-                @JsonProperty("included") Collection<String> included,
-                @JsonProperty("available") Collection<String> available) {
-            super();
+        public ProductJson(@JsonProperty("type") final String type,
+                           @JsonProperty("name") final String name,
+                           @JsonProperty("plans") final List<PlanJson> plans,
+                           @JsonProperty("included") final List<String> included,
+                           @JsonProperty("available") final List<String> available) {
             this.type = type;
             this.name = name;
-            this.included = included.toArray(new String[included.size()]);
-            this.available = available.toArray(new String[available.size()]);
             this.plans = plans;
+            this.included = included;
+            this.available = available;
         }
 
-        public ProductJson(String type, String name, Collection<String> included, Collection<String> available) {
-            this(type, name, new LinkedList<CatalogJsonSimple.PlanJson>(), included, available);
-        }
-
-        public void addPlan(PlanJson plan) {
-            plans.add(plan);
+        public ProductJson(final String type, final String name, final List<String> included, final List<String> available) {
+            this(type, name, new LinkedList<PlanJson>(), included, available);
         }
 
         public String getType() {
@@ -144,54 +174,242 @@ public class CatalogJsonSimple {
             return plans;
         }
 
-        public String[] getIncluded() {
+        public List<String> getIncluded() {
             return included;
         }
 
-        public String[] getAvailable() {
+        public List<String> getAvailable() {
             return available;
         }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("ProductJson{");
+            sb.append("type='").append(type).append('\'');
+            sb.append(", name='").append(name).append('\'');
+            sb.append(", plans=").append(plans);
+            sb.append(", included=").append(included);
+            sb.append(", available=").append(available);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            final ProductJson that = (ProductJson) o;
+
+            if (available != null ? !available.equals(that.available) : that.available != null) {
+                return false;
+            }
+            if (included != null ? !included.equals(that.included) : that.included != null) {
+                return false;
+            }
+            if (name != null ? !name.equals(that.name) : that.name != null) {
+                return false;
+            }
+            if (plans != null ? !plans.equals(that.plans) : that.plans != null) {
+                return false;
+            }
+            if (type != null ? !type.equals(that.type) : that.type != null) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = type != null ? type.hashCode() : 0;
+            result = 31 * result + (name != null ? name.hashCode() : 0);
+            result = 31 * result + (plans != null ? plans.hashCode() : 0);
+            result = 31 * result + (included != null ? included.hashCode() : 0);
+            result = 31 * result + (available != null ? available.hashCode() : 0);
+            return result;
+        }
     }
 
-    @JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
     public static class PlanJson {
 
         private final String name;
-        private final PhaseJson [] phases;
+        private final List<PhaseJson> phases;
 
         @JsonCreator
-        public PlanJson(@JsonProperty("name") String name,
-                @JsonProperty("phases") PhaseJson[] phases) {
-            super();
+        public PlanJson(@JsonProperty("name") final String name,
+                        @JsonProperty("phases") final List<PhaseJson> phases) {
             this.name = name;
             this.phases = phases;
         }
+
         public String getName() {
             return name;
         }
-        public PhaseJson[] getPhases() {
+
+        public List<PhaseJson> getPhases() {
             return phases;
         }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("PlanJson{");
+            sb.append("name='").append(name).append('\'');
+            sb.append(", phases=").append(phases);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            final PlanJson planJson = (PlanJson) o;
+
+            if (name != null ? !name.equals(planJson.name) : planJson.name != null) {
+                return false;
+            }
+            if (phases != null ? !phases.equals(planJson.phases) : planJson.phases != null) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = name != null ? name.hashCode() : 0;
+            result = 31 * result + (phases != null ? phases.hashCode() : 0);
+            return result;
+        }
     }
 
-    @JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
     public static class PhaseJson {
 
         private final String type;
-        private final Map<String, BigDecimal> prices;
+        private final List<PriceJson> prices;
 
         @JsonCreator
-        public PhaseJson(@JsonProperty("type") String type,
-                @JsonProperty("prices") Map<String, BigDecimal> prices) {
-            super();
+        public PhaseJson(@JsonProperty("type") final String type,
+                         @JsonProperty("prices") final List<PriceJson> prices) {
             this.type = type;
             this.prices = prices;
         }
+
         public String getType() {
             return type;
         }
-        public Map<String, BigDecimal> getPrices() {
+
+        public List<PriceJson> getPrices() {
             return prices;
         }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("PhaseJson{");
+            sb.append("type='").append(type).append('\'');
+            sb.append(", prices=").append(prices);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            final PhaseJson phaseJson = (PhaseJson) o;
+
+            if (prices != null ? !prices.equals(phaseJson.prices) : phaseJson.prices != null) {
+                return false;
+            }
+            if (type != null ? !type.equals(phaseJson.type) : phaseJson.type != null) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = type != null ? type.hashCode() : 0;
+            result = 31 * result + (prices != null ? prices.hashCode() : 0);
+            return result;
+        }
+    }
+
+    public static class PriceJson {
+
+        private final String currency;
+        private final BigDecimal value;
+
+        @JsonCreator
+        public PriceJson(@JsonProperty("currency") final String currency,
+                         @JsonProperty("value") final BigDecimal value) {
+            this.currency = currency;
+            this.value = value;
+        }
+
+        public PriceJson(final Price price) throws CurrencyValueNull {
+            this(price.getCurrency().toString(), price.getValue());
+        }
+
+        public String getCurrency() {
+            return currency;
+        }
+
+        public BigDecimal getValue() {
+            return value;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("PriceJson{");
+            sb.append("currency='").append(currency).append('\'');
+            sb.append(", value=").append(value);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            final PriceJson priceJson = (PriceJson) o;
+
+            if (currency != null ? !currency.equals(priceJson.currency) : priceJson.currency != null) {
+                return false;
+            }
+            if (value != null ? !value.equals(priceJson.value) : priceJson.value != null) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = currency != null ? currency.hashCode() : 0;
+            result = 31 * result + (value != null ? value.hashCode() : 0);
+            return result;
+        }
     }
 }
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PlanDetailJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PlanDetailJson.java
index 42a0df6..ab7d008 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PlanDetailJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PlanDetailJson.java
@@ -16,25 +16,36 @@
 
 package com.ning.billing.jaxrs.json;
 
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
+import java.math.BigDecimal;
+import java.util.List;
+
 import com.ning.billing.catalog.api.BillingPeriod;
-import com.ning.billing.catalog.api.InternationalPrice;
+import com.ning.billing.catalog.api.CurrencyValueNull;
 import com.ning.billing.catalog.api.Listing;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.Price;
+import com.ning.billing.jaxrs.json.CatalogJsonSimple.PriceJson;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
 
 public class PlanDetailJson {
+
     final String productName;
     final String planName;
     final BillingPeriod billingPeriod;
     final String priceListName;
-    final InternationalPrice finalPhasePrice;
+    final List<PriceJson> finalPhasePrice;
 
     @JsonCreator
     public PlanDetailJson(@JsonProperty("product") final String productName,
                           @JsonProperty("plan") final String planName,
                           @JsonProperty("final_phase_billing_period") final BillingPeriod billingPeriod,
                           @JsonProperty("priceList") final String priceListName,
-                          @JsonProperty("final_phase_recurring_price") final InternationalPrice finalPhasePrice) {
+                          @JsonProperty("final_phase_recurring_price") final List<PriceJson> finalPhasePrice) {
         this.productName = productName;
         this.planName = planName;
         this.billingPeriod = billingPeriod;
@@ -43,8 +54,33 @@ public class PlanDetailJson {
     }
 
     public PlanDetailJson(final Listing listing) {
-        this(listing.getPlan().getProduct().getName(), listing.getPlan().getName(), listing.getPlan().getBillingPeriod(),
-             listing.getPriceList().getName(), listing.getPlan().getFinalPhase().getRecurringPrice());
+        final Plan plan = listing.getPlan();
+        if (plan == null) {
+            this.productName = null;
+            this.planName = null;
+            this.billingPeriod = null;
+            this.finalPhasePrice = ImmutableList.<PriceJson>of();
+        } else {
+            this.productName = plan.getProduct() == null ? null : plan.getProduct().getName();
+            this.planName = plan.getName();
+            this.billingPeriod = plan.getBillingPeriod();
+            if (plan.getFinalPhase() == null || plan.getFinalPhase().getRecurringPrice() == null || plan.getFinalPhase().getRecurringPrice().getPrices() == null) {
+                this.finalPhasePrice = ImmutableList.<PriceJson>of();
+            } else {
+                this.finalPhasePrice = Lists.transform(ImmutableList.<Price>copyOf(plan.getFinalPhase().getRecurringPrice().getPrices()),
+                                                       new Function<Price, PriceJson>() {
+                                                           @Override
+                                                           public PriceJson apply(final Price price) {
+                                                               try {
+                                                                   return new PriceJson(price);
+                                                               } catch (CurrencyValueNull e) {
+                                                                   return new PriceJson(price.getCurrency().toString(), BigDecimal.ZERO);
+                                                               }
+                                                           }
+                                                       });
+            }
+        }
+        this.priceListName = listing.getPriceList() == null ? null : listing.getPriceList().getName();
     }
 
     public String getProductName() {
@@ -63,11 +99,23 @@ public class PlanDetailJson {
         return priceListName;
     }
 
-    public InternationalPrice getFinalPhasePrice() {
+    public List<PriceJson> getFinalPhasePrice() {
         return finalPhasePrice;
     }
 
     @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("PlanDetailJson{");
+        sb.append("productName='").append(productName).append('\'');
+        sb.append(", planName='").append(planName).append('\'');
+        sb.append(", billingPeriod=").append(billingPeriod);
+        sb.append(", priceListName='").append(priceListName).append('\'');
+        sb.append(", finalPhasePrice=").append(finalPhasePrice);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
     public boolean equals(final Object o) {
         if (this == o) {
             return true;
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestPlanDetailJason.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestPlanDetailJason.java
index 003b541..b273e71 100644
--- a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestPlanDetailJason.java
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestPlanDetailJason.java
@@ -84,6 +84,6 @@ public class TestPlanDetailJason extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(planDetailJason.getPlanName(), plan.getName());
         Assert.assertEquals(planDetailJason.getBillingPeriod(), plan.getBillingPeriod());
         Assert.assertEquals(planDetailJason.getPriceListName(), priceList.getName());
-        Assert.assertEquals(planDetailJason.getFinalPhasePrice(), plan.getFinalPhase().getRecurringPrice());
+        Assert.assertEquals(planDetailJason.getFinalPhasePrice().size(), 0);
     }
 }
diff --git a/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java b/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
index bc50ba1..80d7944 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
@@ -45,6 +45,7 @@ import com.ning.billing.jaxrs.json.AccountEmailJson;
 import com.ning.billing.jaxrs.json.AccountJson;
 import com.ning.billing.jaxrs.json.AccountTimelineJson;
 import com.ning.billing.jaxrs.json.BundleJsonNoSubscriptions;
+import com.ning.billing.jaxrs.json.CatalogJsonSimple;
 import com.ning.billing.jaxrs.json.ChargebackJson;
 import com.ning.billing.jaxrs.json.CreditJson;
 import com.ning.billing.jaxrs.json.InvoiceItemJsonSimple;
@@ -56,6 +57,7 @@ import com.ning.billing.jaxrs.json.PaymentJsonWithBundleKeys;
 import com.ning.billing.jaxrs.json.PaymentMethodJson;
 import com.ning.billing.jaxrs.json.PaymentMethodJson.PaymentMethodPluginDetailJson;
 import com.ning.billing.jaxrs.json.PaymentMethodJson.PaymentMethodProperties;
+import com.ning.billing.jaxrs.json.PlanDetailJson;
 import com.ning.billing.jaxrs.json.RefundJson;
 import com.ning.billing.jaxrs.json.SubscriptionJsonNoEvents;
 import com.ning.billing.jaxrs.json.TenantJson;
@@ -895,6 +897,33 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
     }
 
     //
+    // CATALOG
+    //
+
+    public CatalogJsonSimple getSimpleCatalog() throws Exception {
+        final Response response = doGet(JaxrsResource.CATALOG_PATH + "/simpleCatalog", DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+        final String body = response.getResponseBody();
+        return mapper.readValue(body, CatalogJsonSimple.class);
+    }
+
+    public List<PlanDetailJson> getAvailableAddons(final String baseProductName) throws Exception {
+        final Response response = doGet(JaxrsResource.CATALOG_PATH + "/availableAddons",
+                                        ImmutableMap.<String, String>of("baseProductName", baseProductName),
+                                        DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+        final String body = response.getResponseBody();
+        return mapper.readValue(body, new TypeReference<List<PlanDetailJson>>() {});
+    }
+
+    public List<PlanDetailJson> getBasePlans() throws Exception {
+        final Response response = doGet(JaxrsResource.CATALOG_PATH + "/availableBasePlans", DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+        final String body = response.getResponseBody();
+        return mapper.readValue(body, new TypeReference<List<PlanDetailJson>>() {});
+    }
+
+    //
     // HTTP CLIENT HELPERS
     //
     protected Response doPost(final String uri, @Nullable final String body, final Map<String, String> queryParams, final int timeoutSec) {
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestCatalog.java b/server/src/test/java/com/ning/billing/jaxrs/TestCatalog.java
index 3390b7d..8291fb9 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestCatalog.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestCatalog.java
@@ -13,29 +13,55 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
+
 package com.ning.billing.jaxrs;
 
-import javax.ws.rs.core.Response.Status;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.ning.billing.jaxrs.json.CatalogJsonSimple;
-import com.ning.billing.jaxrs.resources.JaxrsResource;
-import com.ning.http.client.Response;
+import com.ning.billing.jaxrs.json.CatalogJsonSimple.PlanJson;
+import com.ning.billing.jaxrs.json.CatalogJsonSimple.ProductJson;
+import com.ning.billing.jaxrs.json.PlanDetailJson;
 
 public class TestCatalog extends TestJaxrsBase {
 
-    private static final Logger log = LoggerFactory.getLogger(TestAccount.class);
-
-    @Test(groups = "slow", enabled = true)
+    @Test(groups = "slow")
     public void testCatalogSimple() throws Exception {
-        Response response = doGet(JaxrsResource.CATALOG_PATH + "/simpleCatalog", DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
-        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
-        String body = response.getResponseBody();
-        CatalogJsonSimple objFromJson = mapper.readValue(body, CatalogJsonSimple.class);
-        log.info("Yeaahh...");
+        final Set<String> allBasePlans = new HashSet<String>();
+
+        final CatalogJsonSimple catalogJsonSimple = getSimpleCatalog();
+        for (final ProductJson productJson : catalogJsonSimple.getProducts()) {
+            if (!"BASE".equals(productJson.getType())) {
+                Assert.assertEquals(productJson.getIncluded().size(), 0);
+                Assert.assertEquals(productJson.getAvailable().size(), 0);
+                continue;
+            }
+
+            // Save all plans for later (see below)
+            for (final PlanJson planJson : productJson.getPlans()) {
+                allBasePlans.add(planJson.getName());
+            }
+
+            // Retrieve available products (addons) for that base product
+            final List<PlanDetailJson> availableAddons = getAvailableAddons(productJson.getName());
+            final Set<String> availableAddonsNames = new HashSet<String>();
+            for (final PlanDetailJson planDetailJson : availableAddons) {
+                availableAddonsNames.add(planDetailJson.getProductName());
+            }
+            Assert.assertEquals(availableAddonsNames, new HashSet<String>(productJson.getAvailable()));
+        }
+
+        // Verify base plans endpoint
+        final List<PlanDetailJson> basePlans = getBasePlans();
+        final Set<String> foundBasePlans = new HashSet<String>();
+        for (final PlanDetailJson planDetailJson : basePlans) {
+            foundBasePlans.add(planDetailJson.getPlanName());
+        }
+        Assert.assertEquals(foundBasePlans, allBasePlans);
     }
 }