killbill-aplcache

Details

diff --git a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
index 6929ecc..c193b16 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
@@ -122,6 +122,13 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
                 return i;
             }
         }
+        // If the only version we have are after the input date, we return the first version
+        // This is not strictly correct from an api point of view, but there is no real good use case
+        // where the system would ask for the catalog for a date prior any catalog was uploaded and
+        // yet time manipulation could end of inn that state -- see https://github.com/killbill/killbill/issues/760
+        if (versions.size() > 0) {
+            return 0;
+        }
         throw new CatalogApiException(ErrorCode.CAT_NO_CATALOG_FOR_GIVEN_DATE, date.toString());
     }
 
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java b/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java
index c4bd0b9..3dcb60f 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java
@@ -18,24 +18,16 @@
 
 package org.killbill.billing.catalog;
 
-import java.io.IOException;
 import java.math.BigDecimal;
-import java.net.URISyntaxException;
-
-import javax.xml.bind.JAXBException;
-import javax.xml.transform.TransformerException;
 
 import org.joda.time.DateTime;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Currency;
-import org.killbill.billing.catalog.api.InvalidConfigException;
 import org.killbill.billing.catalog.api.Plan;
-import org.killbill.billing.platform.api.KillbillService.ServiceException;
 import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
-import org.xml.sax.SAXException;
 
 public class TestVersionedCatalog extends CatalogTestSuiteNoDB {
 
@@ -88,13 +80,35 @@ public class TestVersionedCatalog extends CatalogTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testErrorOnDateTooEarly() {
+    public void testErrorOnDateTooEarly() throws CatalogApiException {
         final DateTime dt0 = new DateTime("1977-01-01T00:00:00+00:00");
+
+        // We find it although the date provided is too early because we default to first catalog version
+        vc.findPlan("shotgun-monthly", dt0);
+
         try {
-            vc.findPlan("foo", dt0);
+            // We **don't find it** because date is too early and not part of first catalog version
+            vc.findPlan("shotgun-quarterly", dt0);
             Assert.fail("Date is too early an exception should have been thrown");
         } catch (CatalogApiException e) {
-            Assert.assertEquals(e.getCode(), ErrorCode.CAT_NO_CATALOG_FOR_GIVEN_DATE.getCode());
+            Assert.assertEquals(e.getCode(), ErrorCode.CAT_NO_SUCH_PLAN.getCode());
         }
     }
+
+
+    @Test(groups = "fast")
+    public void testWithDeletedPlan() throws CatalogApiException {
+
+        // We find it because this is version 2 whose effectiveDate is "2011-02-02T00:00:00+00:00"
+        vc.findPlan("shotgun-quarterly", new DateTime("2011-02-02T00:01:00+00:00"));
+
+        try {
+            // We **don't find it** because date provided matches version 3 where plan was removed
+            vc.findPlan("shotgun-quarterly", new DateTime("2011-03-03T00:01:00+00:00"));
+            Assert.fail("Plan has been removed");
+        } catch (CatalogApiException e) {
+            Assert.assertEquals(e.getCode(), ErrorCode.CAT_NO_SUCH_PLAN.getCode());
+        }
+
+    }
 }
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
index df1c09d..3fee3ea 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
@@ -183,6 +183,44 @@
                 </recurring>
             </finalPhase>
         </plan>
+        <plan name="shotgun-quarterly">
+            <product>Shotgun</product>
+            <initialPhases>
+                <phase type="TRIAL">
+                    <duration>
+                        <unit>DAYS</unit>
+                        <number>30</number>
+                    </duration>
+                    <fixed>
+                        <fixedPrice> <!-- empty price implies $0 -->
+                        </fixedPrice>
+                    </fixed>
+                </phase>
+            </initialPhases>
+            <finalPhase type="EVERGREEN">
+                <duration>
+                    <unit>UNLIMITED</unit>
+                    <number>-1</number>
+                </duration>
+                <recurring>
+                    <billingPeriod>QUARTERLY</billingPeriod>
+                    <recurringPrice>
+                        <price>
+                            <currency>USD</currency>
+                            <value>249.95</value>
+                        </price>
+                        <price>
+                            <currency>EUR</currency>
+                            <value>149.95</value>
+                        </price>
+                        <price>
+                            <currency>GBP</currency>
+                            <value>169.95</value>
+                        </price>
+                    </recurringPrice>
+                </recurring>
+            </finalPhase>
+        </plan>
         <plan name="shotgun-annual">
             <product>Shotgun</product>
             <initialPhases>
@@ -285,6 +323,7 @@
             <plans>
                 <plan>pistol-monthly</plan>
                 <plan>shotgun-monthly</plan>
+                <plan>shotgun-quarterly</plan>
                 <plan>shotgun-annual</plan>
                 <plan>laser-scope-monthly</plan>
                 <plan>extra-ammo-monthly</plan>
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java
index 17ab9cd..b0cc317 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java
@@ -125,7 +125,7 @@ public class TenantResource extends JaxRsResourceBase {
     @ApiOperation(value = "Create a tenant")
     @ApiResponses(value = {@ApiResponse(code = 500, message = "Tenant already exists")})
     public Response createTenant(final TenantJson json,
-                                 @QueryParam(QUERY_TENANT_USE_GLOBAL_DEFAULT) @DefaultValue("true") final Boolean useGlobalDefault,
+                                 @QueryParam(QUERY_TENANT_USE_GLOBAL_DEFAULT) @DefaultValue("false") final Boolean useGlobalDefault,
                                  @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                  @HeaderParam(HDR_REASON) final String reason,
                                  @HeaderParam(HDR_COMMENT) final String comment,
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TestResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TestResource.java
index 54bcfa6..32ad1f1 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TestResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TestResource.java
@@ -21,8 +21,10 @@ package org.killbill.billing.jaxrs.resources;
 import javax.inject.Inject;
 import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.DELETE;
 import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
@@ -30,19 +32,28 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.AccountUserApi;
+import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.CatalogUserApi;
 import org.killbill.billing.jaxrs.util.Context;
 import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
 import org.killbill.billing.payment.api.PaymentApi;
+import org.killbill.billing.tenant.api.TenantApiException;
+import org.killbill.billing.tenant.api.TenantKV.TenantKey;
+import org.killbill.billing.tenant.api.TenantUserApi;
 import org.killbill.billing.util.api.AuditUserApi;
 import org.killbill.billing.util.api.CustomFieldUserApi;
 import org.killbill.billing.util.api.RecordIdApi;
 import org.killbill.billing.util.api.TagUserApi;
+import org.killbill.billing.util.cache.Cachable.CacheType;
+import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.TenantContext;
 import org.killbill.bus.api.BusEvent;
 import org.killbill.bus.api.BusEventWithMetadata;
@@ -85,16 +96,23 @@ public class TestResource extends JaxRsResourceBase {
     private final PersistentBus persistentBus;
     private final NotificationQueueService notificationQueueService;
     private final RecordIdApi recordIdApi;
+    private final TenantUserApi tenantApi;
+    private final CatalogUserApi catalogUserApi;
+    private final CacheControllerDispatcher cacheControllerDispatcher;
 
     @Inject
     public TestResource(final JaxrsUriBuilder uriBuilder, final TagUserApi tagUserApi, final CustomFieldUserApi customFieldUserApi,
                         final AuditUserApi auditUserApi, final AccountUserApi accountUserApi, final RecordIdApi recordIdApi,
                         final PersistentBus persistentBus, final NotificationQueueService notificationQueueService, final PaymentApi paymentApi,
-                        final Clock clock, final Context context) {
+                        final TenantUserApi tenantApi, final CatalogUserApi catalogUserApi,
+                        final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final Context context) {
         super(uriBuilder, tagUserApi, customFieldUserApi, auditUserApi, accountUserApi, paymentApi, null, clock, context);
         this.persistentBus = persistentBus;
         this.notificationQueueService = notificationQueueService;
         this.recordIdApi = recordIdApi;
+        this.catalogUserApi = catalogUserApi;
+        this.tenantApi = tenantApi;
+        this.cacheControllerDispatcher = cacheControllerDispatcher;
     }
 
     public final class ClockResource {
@@ -201,6 +219,34 @@ public class TestResource extends JaxRsResourceBase {
         return getCurrentTime(timeZoneStr);
     }
 
+
+
+    @DELETE
+    @Path("/catalog")
+    @Produces(APPLICATION_JSON)
+    @ApiOperation(value = "Delete all versions for a per tenant catalog")
+    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid subscription id supplied"),
+                           @ApiResponse(code = 404, message = "Entitlement not found")})
+    public Response deleteCatalog(@HeaderParam(HDR_CREATED_BY) final String createdBy,
+                                  @HeaderParam(HDR_REASON) final String reason,
+                                  @HeaderParam(HDR_COMMENT) final String comment,
+                                  @javax.ws.rs.core.Context final UriInfo uriInfo,
+                                  @javax.ws.rs.core.Context final HttpServletRequest request) throws TenantApiException, CatalogApiException {
+
+        final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+
+        // remove for all tenants-- otherwise we need to convert the callContext into an internalTenantContext to get the key
+        cacheControllerDispatcher.getCacheController(CacheType.TENANT_CATALOG).removeAll();
+        // Soft delete the current entry
+        tenantApi.deleteTenantKey(TenantKey.CATALOG.toString(), callContext);
+
+        // Recreate default entry so that user does not default to KB default catalog
+        catalogUserApi.createDefaultEmptyCatalog(clock.getUTCNow(),callContext);
+
+        return Response.status(Status.OK).build();
+    }
+
+
     private boolean waitForNotificationToComplete(final ServletRequest request, final Long timeoutSec) {
         final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
         final Long tenantRecordId = recordIdApi.getRecordId(tenantContext.getTenantId(), ObjectType.TENANT, tenantContext);
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
index 7aa8f80..1506cc6 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
@@ -32,6 +32,7 @@ import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.catalog.api.TimeUnit;
 import org.killbill.billing.client.KillBillClientException;
+import org.killbill.billing.client.KillBillHttpClient;
 import org.killbill.billing.client.RequestOptions;
 import org.killbill.billing.client.model.Catalog;
 import org.killbill.billing.client.model.Plan;
@@ -40,10 +41,13 @@ import org.killbill.billing.client.model.Product;
 import org.killbill.billing.client.model.SimplePlan;
 import org.killbill.billing.client.model.Tenant;
 import org.killbill.billing.client.model.Usage;
+import org.killbill.billing.jaxrs.json.AdminPaymentJson;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multimap;
 import com.google.common.io.Resources;
 
 public class TestCatalog extends TestJaxrsBase {
@@ -222,6 +226,24 @@ public class TestCatalog extends TestJaxrsBase {
         Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getPlans().size(), 2);
     }
 
+    @Test(groups = "slow")
+    public void testCatalogDeletionInTestMode() throws Exception {
+
+        killBillClient.addSimplePan(new SimplePlan("something-monthly", "Something", ProductCategory.BASE, Currency.USD, BigDecimal.TEN, BillingPeriod.MONTHLY, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()), requestOptions);
+        List<Catalog> catalogsJson = killBillClient.getJSONCatalog(requestOptions);
+        Assert.assertEquals(catalogsJson.size(), 1);
+
+        final String uri = "/1.0/kb/test/catalog";
 
+        final Multimap result = HashMultimap.create();
+        result.put(KillBillHttpClient.AUDIT_OPTION_CREATED_BY, createdBy);
+        result.put(KillBillHttpClient.AUDIT_OPTION_REASON, reason);
+        result.put(KillBillHttpClient.AUDIT_OPTION_COMMENT, comment);
+        killBillHttpClient.doDelete(uri, requestOptions);
 
+        // Verify that we see no catalog -- and in particular not the KB default catalog
+        catalogsJson = killBillClient.getJSONCatalog(requestOptions);
+        Assert.assertEquals(catalogsJson.size(), 0);
+
+    }
 }