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 <dave.ru...@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 mme...@apache.org.