You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by mm...@apache.org on 2018/02/27 23:02:15 UTC

[incubator-pulsar] branch master updated: Make BackoffTest deterministic, fixes #1299 (#1301)

This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pulsar.git


The following commit(s) were added to refs/heads/master by this push:
     new 90fb9b2  Make BackoffTest deterministic, fixes #1299 (#1301)
90fb9b2 is described below

commit 90fb9b2c7cfabf8035496936de0441008aa2dc32
Author: Dave Rusek <da...@gmail.com>
AuthorDate: Tue Feb 27 16:02:13 2018 -0700

    Make BackoffTest deterministic, fixes #1299 (#1301)
---
 .../org/apache/pulsar/client/impl/Backoff.java     |  24 +++-
 .../org/apache/pulsar/client/impl/BackoffTest.java | 134 +++++++++++++--------
 2 files changed, 101 insertions(+), 57 deletions(-)

diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/Backoff.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/Backoff.java
index 9f79680..aa506da 100644
--- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/Backoff.java
+++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/Backoff.java
@@ -18,6 +18,8 @@
  */
 package org.apache.pulsar.client.impl;
 
+import com.google.common.annotations.VisibleForTesting;
+import java.time.Clock;
 import java.util.Random;
 import java.util.concurrent.TimeUnit;
 
@@ -27,19 +29,28 @@ public class Backoff {
     private static final long MAX_BACKOFF_INTERVAL_NANOSECONDS = TimeUnit.SECONDS.toNanos(30);
     private final long initial;
     private final long max;
+    private final Clock clock;
     private long next;
     private long mandatoryStop;
-    long firstBackoffTimeInMillis;
+
+    private long firstBackoffTimeInMillis;
     private boolean mandatoryStopMade = false;
 
     private static final Random random = new Random();
 
-    public Backoff(long initial, TimeUnit unitInitial, long max, TimeUnit unitMax, long mandatoryStop,
-            TimeUnit unitMandatoryStop) {
+    @VisibleForTesting
+    Backoff(long initial, TimeUnit unitInitial, long max, TimeUnit unitMax, long mandatoryStop,
+            TimeUnit unitMandatoryStop, Clock clock) {
         this.initial = unitInitial.toMillis(initial);
         this.max = unitMax.toMillis(max);
         this.next = this.initial;
         this.mandatoryStop = unitMandatoryStop.toMillis(mandatoryStop);
+        this.clock = clock;
+    }
+
+    public Backoff(long initial, TimeUnit unitInitial, long max, TimeUnit unitMax, long mandatoryStop,
+            TimeUnit unitMandatoryStop) {
+        this(initial, unitInitial, max, unitMax, mandatoryStop, unitMandatoryStop, Clock.systemDefaultZone());
     }
 
     public long next() {
@@ -50,7 +61,7 @@ public class Backoff {
         
         // Check for mandatory stop
         if (!mandatoryStopMade) {
-            long now = System.currentTimeMillis();
+            long now = clock.millis();
             long timeElapsedSinceFirstBackoff = 0;
             if (initial == current) {
                 firstBackoffTimeInMillis = now;
@@ -83,6 +94,11 @@ public class Backoff {
         this.mandatoryStopMade = false;
     }
 
+    @VisibleForTesting
+    long getFirstBackoffTimeInMillis() {
+        return firstBackoffTimeInMillis;
+    }
+
     public static boolean shouldBackoff(long initialTimestamp, TimeUnit unitInitial, int failedAttempts) {
         long initialTimestampInNano = unitInitial.toNanos(initialTimestamp);
         long currentTime = System.nanoTime();
diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/BackoffTest.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/BackoffTest.java
index 0463954..6bdb213 100644
--- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/BackoffTest.java
+++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/BackoffTest.java
@@ -18,35 +18,34 @@
  */
 package org.apache.pulsar.client.impl;
 
-import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
 
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
 import java.util.concurrent.TimeUnit;
-
-import org.apache.pulsar.client.impl.Backoff;
+import org.mockito.Mockito;
 import org.testng.annotations.Test;
 
 public class BackoffTest {
     boolean withinTenPercentAndDecrementTimer(Backoff backoff, long t2) {
         long t1 = backoff.next();
-        backoff.firstBackoffTimeInMillis -= t2;
         return (t1 >= t2 * 0.9 && t1 <= t2);
     }
 
     boolean checkExactAndDecrementTimer(Backoff backoff, long t2) {
         long t1 = backoff.next();
-        backoff.firstBackoffTimeInMillis -= t2;
         return t1 == t2;
     }
     @Test
     public void shouldBackoffTest() {
-        long currentTimestamp = System.nanoTime();
-        Backoff testBackoff = new Backoff(currentTimestamp, TimeUnit.NANOSECONDS, 100, TimeUnit.MICROSECONDS, 0,
-                TimeUnit.NANOSECONDS);
         // gives false
-        assertTrue(!testBackoff.shouldBackoff(0L, TimeUnit.NANOSECONDS, 0));
-        currentTimestamp = System.nanoTime();
+        assertTrue(!Backoff.shouldBackoff(0L, TimeUnit.NANOSECONDS, 0));
+        long currentTimestamp = System.nanoTime();
         // gives true
-        assertTrue(testBackoff.shouldBackoff(currentTimestamp, TimeUnit.NANOSECONDS, 100));
+        assertTrue(Backoff.shouldBackoff(currentTimestamp, TimeUnit.NANOSECONDS, 100));
     }
 
     @Test
@@ -60,23 +59,32 @@ public class BackoffTest {
     }
     
     @Test
-    public void firstBackoffTimerTest() throws InterruptedException {
-        Backoff backoff = new Backoff(100, TimeUnit.MILLISECONDS, 60, TimeUnit.SECONDS, 1900, TimeUnit.MILLISECONDS);
+    public void firstBackoffTimerTest() {
+        Clock mockClock = Mockito.mock(Clock.class);
+        Mockito.when(mockClock.millis())
+            .thenReturn(0L)
+            .thenReturn(300L);
+
+        Backoff backoff = new Backoff(
+            100, TimeUnit.MILLISECONDS,
+            60, TimeUnit.SECONDS,
+            1900, TimeUnit.MILLISECONDS,
+            mockClock
+        );
+
         assertEquals(backoff.next(), 100);
-        long firstBackOffTime = backoff.firstBackoffTimeInMillis;
-        Thread.sleep(300);
-        long diffBackOffTime = backoff.firstBackoffTimeInMillis - firstBackOffTime;
-        assertEquals(diffBackOffTime, 0);
-        
+
+        long firstBackOffTime = backoff.getFirstBackoffTimeInMillis();
         backoff.reset();
         assertEquals(backoff.next(), 100);
-        diffBackOffTime = backoff.firstBackoffTimeInMillis - firstBackOffTime;
-        assertTrue(diffBackOffTime >= 300 && diffBackOffTime < 310);
+        long diffBackOffTime = backoff.getFirstBackoffTimeInMillis() - firstBackOffTime;
+        assertTrue(diffBackOffTime == 300);
     }
     
     @Test
     public void basicTest() {
-        Backoff backoff = new Backoff(5, TimeUnit.MILLISECONDS, 60, TimeUnit.SECONDS, 60, TimeUnit.SECONDS);
+        Clock mockClock = Clock.fixed(Instant.EPOCH, ZoneId.systemDefault());
+        Backoff backoff = new Backoff(5, TimeUnit.MILLISECONDS, 60, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, mockClock);
         assertTrue(checkExactAndDecrementTimer(backoff, 5));
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 10));
         backoff.reset();
@@ -85,7 +93,20 @@ public class BackoffTest {
 
     @Test
     public void maxTest() {
-        Backoff backoff = new Backoff(5, TimeUnit.MILLISECONDS, 20, TimeUnit.MILLISECONDS, 20, TimeUnit.MILLISECONDS);
+        Clock mockClock = Mockito.mock(Clock.class);
+        Mockito.when(mockClock.millis())
+            .thenReturn(0L)
+            .thenReturn(10L)
+            .thenReturn(20L)
+            .thenReturn(40L);
+
+        Backoff backoff = new Backoff(
+            5, TimeUnit.MILLISECONDS,
+            20, TimeUnit.MILLISECONDS,
+            20, TimeUnit.MILLISECONDS,
+            mockClock
+        );
+
         assertTrue(checkExactAndDecrementTimer(backoff, 5));
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 10));
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 5));
@@ -94,68 +115,75 @@ public class BackoffTest {
 
     @Test
     public void mandatoryStopTest() {
-        Backoff backoff = new Backoff(100, TimeUnit.MILLISECONDS, 60, TimeUnit.SECONDS, 1900, TimeUnit.MILLISECONDS);
+        Clock mockClock = Mockito.mock(Clock.class);
+
+        Backoff backoff = new Backoff(
+            100, TimeUnit.MILLISECONDS,
+            60, TimeUnit.SECONDS,
+            1900, TimeUnit.MILLISECONDS,
+            mockClock
+        );
+
+        Mockito.when(mockClock.millis()).thenReturn(0L);
         assertTrue(checkExactAndDecrementTimer(backoff, 100));
+        Mockito.when(mockClock.millis()).thenReturn(100L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 200));
+        Mockito.when(mockClock.millis()).thenReturn(300L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 400));
+        Mockito.when(mockClock.millis()).thenReturn(700L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 800));
-        // would have been 1600 w/o the mandatory stop 
+        Mockito.when(mockClock.millis()).thenReturn(1500L);
+
+        // would have been 1600 w/o the mandatory stop
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 400));
+        Mockito.when(mockClock.millis()).thenReturn(1900L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 3200));
+        Mockito.when(mockClock.millis()).thenReturn(3200L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 6400));
+        Mockito.when(mockClock.millis()).thenReturn(3200L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 12800));
+        Mockito.when(mockClock.millis()).thenReturn(6400L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 25600));
+        Mockito.when(mockClock.millis()).thenReturn(12800L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 51200));
+        Mockito.when(mockClock.millis()).thenReturn(25600L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 60000));
+        Mockito.when(mockClock.millis()).thenReturn(51200L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 60000));
+        Mockito.when(mockClock.millis()).thenReturn(60000L);
+
         backoff.reset();
+        Mockito.when(mockClock.millis()).thenReturn(0L);
         assertTrue(checkExactAndDecrementTimer(backoff, 100));
+        Mockito.when(mockClock.millis()).thenReturn(100L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 200));
+        Mockito.when(mockClock.millis()).thenReturn(300L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 400));
+        Mockito.when(mockClock.millis()).thenReturn(700L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 800));
+        Mockito.when(mockClock.millis()).thenReturn(1500L);
         // would have been 1600 w/o the mandatory stop
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 400));
 
         backoff.reset();
+        Mockito.when(mockClock.millis()).thenReturn(0L);
         assertTrue(checkExactAndDecrementTimer(backoff, 100));
+        Mockito.when(mockClock.millis()).thenReturn(100L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 200));
+        Mockito.when(mockClock.millis()).thenReturn(300L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 400));
+        Mockito.when(mockClock.millis()).thenReturn(700L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 800));
 
         backoff.reset();
+        Mockito.when(mockClock.millis()).thenReturn(0L);
         assertTrue(checkExactAndDecrementTimer(backoff, 100));
+        Mockito.when(mockClock.millis()).thenReturn(100L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 200));
+        Mockito.when(mockClock.millis()).thenReturn(300L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 400));
+        Mockito.when(mockClock.millis()).thenReturn(700L);
         assertTrue(withinTenPercentAndDecrementTimer(backoff, 800));
     }
 
-    public void ignoringMandatoryStopTest() {
-        Backoff backoff = new Backoff(100, TimeUnit.MILLISECONDS, 60, TimeUnit.SECONDS, 0, TimeUnit.MILLISECONDS);
-        assertTrue(checkExactAndDecrementTimer(backoff, 100));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 200));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 400));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 800));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 1600));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 3200));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 6400));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 12800));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 25600));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 51200));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 60000));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 60000));
-
-        backoff.reset();
-        assertTrue(checkExactAndDecrementTimer(backoff, 100));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 200));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 400));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 800));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 1600));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 3200));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 6400));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 12800));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 25600));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 51200));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 60000));
-        assertTrue(withinTenPercentAndDecrementTimer(backoff, 60000));
-    }
 }

-- 
To stop receiving notification emails like this one, please contact
mmerli@apache.org.