killbill-aplcache
Merge remote-tracking branch 'origin/test-fixes' into test-fixes-doc Signed-off-by: …
5/2/2018 8:09:53 AM
Changes
Details
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index ce7474f..5a996c0 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -356,6 +356,10 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
@AfterMethod(groups = "slow")
public void afterMethod() throws Exception {
+ if (hasFailed()) {
+ return;
+ }
+
lifecycle.fireShutdownSequencePriorEventUnRegistration();
busService.getBus().unregister(busHandler);
lifecycle.fireShutdownSequencePostEventUnRegistration();
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/CallbackServlet.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/CallbackServlet.java
index 9f47378..eedba91 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/CallbackServlet.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/CallbackServlet.java
@@ -22,6 +22,8 @@ import java.io.InputStreamReader;
import java.util.Collection;
import java.util.Iterator;
import java.util.Stack;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
@@ -56,8 +58,18 @@ public class CallbackServlet extends HttpServlet {
private String listenerFailedMsg;
private boolean completed = true;
+ final AtomicInteger receivedCalls = new AtomicInteger(0);
+ final AtomicBoolean forceToFail = new AtomicBoolean(false);
+
@Override
protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
+ final int current = receivedCalls.incrementAndGet();
+ if (forceToFail.get()) {
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ log.info("CallmebackServlet is forced to fail for testing purposes");
+ return;
+ }
+
final String body = CharStreams.toString(new InputStreamReader(request.getInputStream(), "UTF-8"));
response.setStatus(HttpServletResponse.SC_OK);
@@ -87,6 +99,8 @@ public class CallbackServlet extends HttpServlet {
}
public synchronized void reset() {
+ receivedCalls.set(0);
+ forceToFail.set(false);
nextExpectedEvent.clear();
completed = true;
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
index 1b11937..ce48bda 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
@@ -203,14 +203,18 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
protected Account createAccount(final UUID parentAccountId) throws Exception {
callbackServlet.pushExpectedEvent(ExtBusEventType.ACCOUNT_CREATION);
- final Account input = getAccount(parentAccountId);
- final Account account = accountApi.createAccount(input, requestOptions);
+ final Account account = createAccountNoEvent(parentAccountId);
callbackServlet.assertListenerStatus();
return account;
}
+ protected Account createAccountNoEvent(final UUID parentAccountId) throws KillBillClientException {
+ final Account input = getAccount(parentAccountId);
+ return accountApi.createAccount(input, requestOptions);
+ }
+
protected Subscription createSubscription(final UUID accountId, final String bundleExternalKey, final String productName,
- final ProductCategory productCategory, final BillingPeriod billingPeriod, final boolean waitCompletion) throws Exception {
+ final ProductCategory productCategory, final BillingPeriod billingPeriod, final boolean waitCompletion) throws Exception {
final Account account = accountApi.getAccount(accountId, requestOptions);
if (account.getBillCycleDayLocal() == null || account.getBillCycleDayLocal() == 0) {
callbackServlet.pushExpectedEvent(ExtBusEventType.ACCOUNT_CHANGE);
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPushNotification.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPushNotification.java
index 9e752f6..d7d1d89 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPushNotification.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPushNotification.java
@@ -18,132 +18,31 @@
package org.killbill.billing.jaxrs;
-import java.io.IOException;
-import java.io.InputStreamReader;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
import org.awaitility.Awaitility;
import org.joda.time.DateTime;
import org.killbill.CreatorName;
-import org.killbill.billing.api.FlakyRetryAnalyzer;
-import org.killbill.billing.client.KillBillClientException;
-import org.killbill.billing.client.model.gen.TenantKeyValue;
-import org.killbill.billing.jaxrs.json.NotificationJson;
import org.killbill.billing.notification.plugin.api.ExtBusEventType;
import org.killbill.billing.server.DefaultServerService;
import org.killbill.billing.server.notifications.PushNotificationKey;
-import org.killbill.billing.server.notifications.PushNotificationListener;
-import org.killbill.billing.tenant.api.TenantKV;
import org.killbill.notificationq.NotificationQueueDispatcher;
import org.killbill.notificationq.api.NotificationEvent;
import org.killbill.notificationq.api.NotificationQueue;
import org.killbill.notificationq.api.NotificationQueueService.NotificationQueueHandler;
import org.killbill.notificationq.dao.NotificationEventModelDao;
import org.killbill.queue.QueueObjectMapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.io.CharStreams;
public class TestPushNotification extends TestJaxrsBase {
- private CallbackServer callbackServer;
-
- private volatile boolean callbackCompleted;
- private volatile boolean callbackCompletedWithError;
- private volatile int expectedNbCalls = 1;
- private volatile boolean forceToFail = false;
- private volatile int failedResponseStatus = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
-
- @Override
- @BeforeMethod(groups = "slow")
- public void beforeMethod() throws Exception {
- if (hasFailed()) {
- return;
- }
-
- super.beforeMethod();
- callbackServer = new CallbackServer(new CallmebackServlet(this));
- resetCallbackStatusProperties();
- callbackServer.startServer();
- this.expectedNbCalls = 1;
- }
-
- @AfterMethod(groups = "slow")
- public void afterMethod() throws Exception {
- if (hasFailed()) {
- return;
- }
-
- callbackServer.stopServer();
- }
-
- private void assertAllCallbacksCompleted() throws InterruptedException {
- final boolean waitForCallbacksToComplete = waitForCallbacksToComplete();
- if (!waitForCallbacksToComplete) {
- printThreadDump();
- }
- Assert.assertTrue(waitForCallbacksToComplete, "Fail to see push notification callbacks");
- }
-
- private boolean waitForCallbacksToComplete() throws InterruptedException {
- long remainingMs = DEFAULT_REQUEST_TIMEOUT_SEC * 1000;
- do {
- if (callbackCompleted) {
- break;
- }
- Thread.sleep(100);
- remainingMs -= 100;
- } while (remainingMs > 0);
- return (remainingMs > 0);
- }
-
- public void retrieveAccountWithAsserts(final UUID accountId) {
- try {
- // Just check we can retrieve the account with the id from the callback
- accountApi.getAccount(accountId, requestOptions);
- } catch (final Exception e) {
- Assert.fail(e.getMessage());
- }
- }
-
- @Test(groups = "slow")
- public void testPushNotification() throws Exception {
- final String callback = registerTenantForCallback();
-
- // set expected number of calls
- // 1st: was "eventType":"TENANT_CONFIG_CHANGE"
- // 2nd: is "eventType":"ACCOUNT_CREATION"
- this.expectedNbCalls = 2;
-
- // Create account to trigger a push notification
- createAccount();
-
- assertAllCallbacksCompleted();
-
- if (callbackCompletedWithError) {
- Assert.fail("Assertion during callback failed...");
- }
-
- unregisterTenantForCallback(callback);
- }
-
@Test(groups = "slow", description = "https://github.com/killbill/killbill/issues/726")
public void testVerify726Backport() throws Exception {
// Record an event without the metadata field
@@ -210,233 +109,170 @@ public class TestPushNotification extends TestJaxrsBase {
Assert.assertNull(retrievedKey.getMetaData());
}
- private void unregisterTenantForCallback(final String callback) throws KillBillClientException {
- final TenantKeyValue result = tenantApi.registerPushNotificationCallback(callback, requestOptions);
- Assert.assertEquals(result.getKey(), TenantKV.TenantKey.PUSH_NOTIFICATION_CB.toString());
- Assert.assertEquals(result.getValues().size(), 1);
- Assert.assertEquals(result.getValues().get(0), callback);
-
- tenantApi.deletePushNotificationCallbacks(requestOptions);
- final TenantKeyValue result2 = tenantApi.getPushNotificationCallbacks(requestOptions);
- Assert.assertEquals(result2.getKey(), TenantKV.TenantKey.PUSH_NOTIFICATION_CB.toString());
- Assert.assertEquals(result2.getValues().size(), 0);
- }
-
- private String registerTenantForCallback() throws KillBillClientException, InterruptedException {// Register tenant for callback
- final String callback = callbackServer.getServletEndpoint();
- final TenantKeyValue result0 = tenantApi.registerPushNotificationCallback(callback, requestOptions);
-
- Assert.assertTrue(waitForCallbacksToComplete());
-
- Assert.assertEquals(result0.getKey(), TenantKV.TenantKey.PUSH_NOTIFICATION_CB.toString());
- Assert.assertEquals(result0.getValues().size(), 1);
- Assert.assertEquals(result0.getValues().get(0), callback);
-
- // reset values
- resetCallbackStatusProperties();
-
- return callback;
- }
-
- // Flaky, see https://github.com/killbill/killbill/issues/860
- @Test(groups = "slow", retryAnalyzer = FlakyRetryAnalyzer.class)
+ @Test(groups = "slow")
public void testPushNotificationRetries() throws Exception {
- final String callback = registerTenantForCallback();
+ Assert.assertEquals(callbackServlet.receivedCalls.get(), 1);
// force server to fail
// Notifications retries are set to:
// org.killbill.billing.server.notifications.retries=15m,1h,1d,2d
- this.forceToFail = true;
+ callbackServlet.forceToFail.set(true);
- // set expected number of calls
// 1st: was "eventType":"TENANT_CONFIG_CHANGE"
// 2nd: is original "eventType":"ACCOUNT_CREATION" call [force error]
// 3rd: is 1st notification retry (+ 15m) [force error]
// 4th: is 1st notification retry (+ 1h) [force error]
// 5th: is 1st notification retry (+ 1d) [success]
- this.expectedNbCalls = 5;
// Create account to trigger a push notification
- createAccount();
-
- assertAllCallbacksCompleted();
- Assert.assertTrue(callbackCompletedWithError);
-
- resetCallbackStatusProperties();
+ createAccountNoEvent(null);
+ Awaitility.await()
+ .atMost(10, TimeUnit.SECONDS)
+ .until(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return callbackServlet.receivedCalls.get() == 2;
+ }
+ });
+ callbackServlet.assertListenerStatus();
+ Assert.assertEquals(callbackServlet.receivedCalls.get(), 2);
// move clock 15 minutes and get 1st retry
clock.addDeltaFromReality(900000);
- assertAllCallbacksCompleted();
- Assert.assertTrue(callbackCompletedWithError);
-
- resetCallbackStatusProperties();
+ Awaitility.await()
+ .atMost(10, TimeUnit.SECONDS)
+ .until(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return callbackServlet.receivedCalls.get() == 3;
+ }
+ });
+ callbackServlet.assertListenerStatus();
+ Assert.assertEquals(callbackServlet.receivedCalls.get(), 3);
// move clock an hour and get 2nd retry
clock.addDeltaFromReality(3600000);
- assertAllCallbacksCompleted();
- Assert.assertTrue(callbackCompletedWithError);
-
- resetCallbackStatusProperties();
+ Awaitility.await()
+ .atMost(10, TimeUnit.SECONDS)
+ .until(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return callbackServlet.receivedCalls.get() == 4;
+ }
+ });
+ callbackServlet.assertListenerStatus();
+ Assert.assertEquals(callbackServlet.receivedCalls.get(), 4);
// make call success
- this.forceToFail = false;
+ callbackServlet.pushExpectedEvents(ExtBusEventType.ACCOUNT_CREATION);
+ callbackServlet.forceToFail.set(false);
// move clock a day, get 3rd retry and wait for a success push notification
clock.addDays(1);
- assertAllCallbacksCompleted();
- Assert.assertFalse(callbackCompletedWithError);
-
- unregisterTenantForCallback(callback);
+ Awaitility.await()
+ .atMost(10, TimeUnit.SECONDS)
+ .until(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return callbackServlet.receivedCalls.get() == 5;
+ }
+ });
+ callbackServlet.assertListenerStatus();
+ Assert.assertEquals(callbackServlet.receivedCalls.get(), 5);
}
- // Flaky, see https://github.com/killbill/killbill/issues/860
- @Test(groups = "slow", retryAnalyzer = FlakyRetryAnalyzer.class)
+ @Test(groups = "slow")
public void testPushNotificationRetriesMaxAttemptNumber() throws Exception {
- final String callback = registerTenantForCallback();
+ Assert.assertEquals(callbackServlet.receivedCalls.get(), 1);
// force server to fail
// Notifications retries are set to:
// org.killbill.billing.server.notifications.retries=15m,1h,1d,2d
- this.forceToFail = true;
+ callbackServlet.forceToFail.set(true);
- // set expected number of calls
// 1st: was "eventType":"TENANT_CONFIG_CHANGE"
// 2nd: is original "eventType":"ACCOUNT_CREATION" call [force error]
// 3rd: is 1st notification retry (+ 15m) [force error]
// 4th: is 2nd notification retry (+ 1h) [force error]
// 5th: is 3rd notification retry (+ 1d) [force error]
// 6th: is 4th notification retry (+ 2d) [force error]
- this.expectedNbCalls = 6;
// Create account to trigger a push notification
- createAccount();
-
- assertAllCallbacksCompleted();
- Assert.assertTrue(callbackCompletedWithError);
-
- resetCallbackStatusProperties();
+ createAccountNoEvent(null);
+ Awaitility.await()
+ .atMost(10, TimeUnit.SECONDS)
+ .until(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return callbackServlet.receivedCalls.get() == 2;
+ }
+ });
+ callbackServlet.assertListenerStatus();
+ Assert.assertEquals(callbackServlet.receivedCalls.get(), 2);
// move clock 15 minutes (+10s for flakiness) and get 1st retry
clock.addDeltaFromReality(910000);
- assertAllCallbacksCompleted();
- Assert.assertTrue(callbackCompletedWithError);
-
- resetCallbackStatusProperties();
+ Awaitility.await()
+ .atMost(10, TimeUnit.SECONDS)
+ .until(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return callbackServlet.receivedCalls.get() == 3;
+ }
+ });
+ callbackServlet.assertListenerStatus();
+ Assert.assertEquals(callbackServlet.receivedCalls.get(), 3);
// move clock an hour (+10s for flakiness) and get 2nd retry
clock.addDeltaFromReality(3610000);
- assertAllCallbacksCompleted();
- Assert.assertTrue(callbackCompletedWithError);
-
- resetCallbackStatusProperties();
+ Awaitility.await()
+ .atMost(10, TimeUnit.SECONDS)
+ .until(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return callbackServlet.receivedCalls.get() == 4;
+ }
+ });
+ callbackServlet.assertListenerStatus();
+ Assert.assertEquals(callbackServlet.receivedCalls.get(), 4);
// move clock a day and get 3rd retry
clock.addDays(1);
- assertAllCallbacksCompleted();
- Assert.assertTrue(callbackCompletedWithError);
-
- resetCallbackStatusProperties();
-
- // move clock a day and get 4rd retry
+ Awaitility.await()
+ .atMost(10, TimeUnit.SECONDS)
+ .until(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return callbackServlet.receivedCalls.get() == 5;
+ }
+ });
+ callbackServlet.assertListenerStatus();
+ Assert.assertEquals(callbackServlet.receivedCalls.get(), 5);
+
+ // move clock a day and get 4th retry
clock.addDays(2);
- assertAllCallbacksCompleted();
- Assert.assertTrue(callbackCompletedWithError);
- resetCallbackStatusProperties();
+ Awaitility.await()
+ .atMost(10, TimeUnit.SECONDS)
+ .until(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return callbackServlet.receivedCalls.get() == 6;
+ }
+ });
+ callbackServlet.assertListenerStatus();
+ Assert.assertEquals(callbackServlet.receivedCalls.get(), 6);
clock.addDays(4);
- Assert.assertFalse(waitForCallbacksToComplete());
- Assert.assertFalse(callbackCompletedWithError);
-
- unregisterTenantForCallback(callback);
- }
-
- private void resetCallbackStatusProperties() {
- // reset values
- this.callbackCompleted = false;
- this.callbackCompletedWithError = false;
- }
-
- public void setCompleted(final boolean withError) {
- callbackCompleted = true;
- callbackCompletedWithError = withError;
- }
-
- public static class CallmebackServlet extends HttpServlet {
-
- private static final long serialVersionUID = -5181211514918217301L;
-
- private static final Logger log = LoggerFactory.getLogger(CallmebackServlet.class);
-
- private final AtomicInteger receivedCalls;
- private final TestPushNotification test;
- private final ObjectMapper objectMapper = new ObjectMapper();
-
- private boolean withError;
-
- public CallmebackServlet(final TestPushNotification test) {
- this.test = test;
- this.receivedCalls = new AtomicInteger(0);
- }
-
- @Override
- protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
- final int current = receivedCalls.incrementAndGet();
- final String body = CharStreams.toString(new InputStreamReader(request.getInputStream(), "UTF-8"));
-
- log.info("CallmebackServlet received {} calls , current = {} at {}", current, body, getClock().getUTCNow());
-
- if (test.forceToFail) {
- response.setStatus(test.failedResponseStatus);
- log.info("CallmebackServlet is force to fail for testing purposes");
- test.setCompleted(true);
- return;
- }
-
- response.setStatus(HttpServletResponse.SC_OK);
-
- log.info("Got body {}", body);
-
- final NotificationJson notification = objectMapper.readValue(body, NotificationJson.class);
-
- final ExtBusEventType type = ExtBusEventType.valueOf(notification.getEventType());
- switch (type) {
- case TENANT_CONFIG_CHANGE:
- Assert.assertEquals(notification.getEventType(), "TENANT_CONFIG_CHANGE");
- Assert.assertEquals(notification.getObjectType(), "TENANT_KVS");
- Assert.assertNotNull(notification.getObjectId());
- Assert.assertNull(notification.getAccountId());
- Assert.assertNotNull(notification.getMetaData());
- Assert.assertEquals(notification.getMetaData(), "PUSH_NOTIFICATION_CB");
- break;
- case ACCOUNT_CREATION:
- Assert.assertEquals(notification.getEventType(), "ACCOUNT_CREATION");
- Assert.assertEquals(notification.getObjectType(), "ACCOUNT");
- Assert.assertNotNull(notification.getObjectId());
- Assert.assertNotNull(notification.getAccountId());
- Assert.assertEquals(notification.getObjectId(), notification.getAccountId());
- break;
- }
-
- test.retrieveAccountWithAsserts(notification.getObjectId());
-
- Assert.assertEquals(request.getHeader(PushNotificationListener.HTTP_HEADER_CONTENT_TYPE), PushNotificationListener.CONTENT_TYPE_JSON);
- stopServerWhenComplete(current, false);
- }
-
- private void stopServerWhenComplete(final int current, final boolean withError) {
- if (current == test.expectedNbCalls) {
- log.info("Excellent, we are done!");
- test.setCompleted(withError);
- }
- }
+ callbackServlet.assertListenerStatus();
+ Assert.assertEquals(callbackServlet.receivedCalls.get(), 6);
}
public static final class PushNotificationKeyPre726 implements NotificationEvent {
diff --git a/util/src/test/java/org/killbill/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java b/util/src/test/java/org/killbill/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java
index a2acf84..90f54ba 100644
--- a/util/src/test/java/org/killbill/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java
+++ b/util/src/test/java/org/killbill/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java
@@ -50,6 +50,10 @@ public class TestDefaultCustomFieldUserApi extends UtilTestSuiteWithEmbeddedDB {
@Override
@BeforeMethod(groups = "slow")
public void beforeMethod() throws Exception {
+ if (hasFailed()) {
+ return;
+ }
+
super.beforeMethod();
final ImmutableAccountData immutableAccountData = Mockito.mock(ImmutableAccountData.class);