Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.bookkeeper.common.util; import static org.apache.bookkeeper.common.util.Backoff.Jitter.Type.DECORRELATED; import static org.apache.bookkeeper.common.util.Backoff.Jitter.Type.EQUAL; import static org.apache.bookkeeper.common.util.Backoff.Jitter.Type.EXPONENTIAL; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.Iterator; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.LongStream; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; import org.junit.Test; /** * Unit test for {@link Backoff}. */ public class TestBackoff { static <T> void assertStreamEquals(Stream<T> s1, Stream<T> s2) { Iterator<T> iter1 = s1.iterator(), iter2 = s2.iterator(); while (iter1.hasNext() && iter2.hasNext()) { T expectedValue = iter1.next(); T actualValue = iter2.next(); assertEquals("Expected = " + expectedValue + ", Actual = " + actualValue, expectedValue, actualValue); } assertTrue(!iter1.hasNext() && !iter2.hasNext()); } @Test public void testExponential() throws Exception { Stream<Long> backoffs = Backoff.exponential(1000, 2, Long.MAX_VALUE).limit(10); Stream<Long> expectedBackoffs = LongStream.range(0L, 10L).mapToObj(i -> (1000L << i)); assertStreamEquals(expectedBackoffs, backoffs); } @Test public void testExponentialPolicy() throws Exception { Stream<Long> expectedBackoffs = LongStream.range(0L, 10L).mapToObj(i -> (1000L << i)); Backoff.Policy policy = Backoff.Exponential.of(1000, Long.MAX_VALUE, 2, 10); assertStreamEquals(expectedBackoffs, policy.toBackoffs()); } @Test public void testExponentialWithUpperLimit() throws Exception { Stream<Long> backoffs = Backoff.exponential(1000, 2, 32000).limit(10); Stream<Long> expectedBackoffs = LongStream.range(0L, 10L).mapToObj(i -> Math.min(1000L << i, 32000)); assertStreamEquals(expectedBackoffs, backoffs); } @Test public void testExponentialPolicyWithUpperLimit() throws Exception { Stream<Long> expectedBackoffs = LongStream.range(0L, 10L).mapToObj(i -> Math.min(1000L << i, 32000)); Backoff.Policy policy = Backoff.Exponential.of(1000, 32000, 2, 10); assertStreamEquals(expectedBackoffs, policy.toBackoffs()); } @Test public void testExponentialJittered() throws Exception { Stream<Long> backoffs = Backoff.exponentialJittered(5, 120).limit(10); // Expected: 5, then randos up to: 10, 20, 40, 80, 120, 120, 120 ... Stream<Long> maxBackoffs = Stream.of(5L, 10L, 20L, 40L, 80L, 120L, 120L, 120L, 120L, 120L); StreamUtil.<Long, Long, Void>zip(backoffs, maxBackoffs, (expected, actual) -> { assertTrue(expected <= actual); return null; }); } @Test public void testExponentialJitteredPolicy() throws Exception { Stream<Long> backoffs = Backoff.Jitter.of(EXPONENTIAL, 5, 120, 10).toBackoffs(); // Expected: 5, then randos up to: 10, 20, 40, 80, 120, 120, 120 ... Stream<Long> maxBackoffs = Stream.of(5L, 10L, 20L, 40L, 80L, 120L, 120L, 120L, 120L, 120L); StreamUtil.<Long, Long, Void>zip(backoffs, maxBackoffs, (expected, actual) -> { assertTrue(expected <= actual); return null; }); } @Test public void testConstant() throws Exception { Stream<Long> backoffs = Backoff.constant(12345L).limit(10); Stream<Long> expectedBackoffs = LongStream.range(0L, 10L).mapToObj(i -> 12345L); assertStreamEquals(expectedBackoffs, backoffs); } @Test public void testConstantPolicy() throws Exception { Stream<Long> backoffs = Backoff.Constant.of(12345L, 10).toBackoffs(); Stream<Long> expectedBackoffs = LongStream.range(0L, 10L).mapToObj(i -> 12345L); assertStreamEquals(expectedBackoffs, backoffs); } @Test public void testEqualJittered() throws Exception { Stream<Long> backoffs = Backoff.equalJittered(5, 120).limit(10); Stream<Pair<Long, Long>> ranges = Stream.of(Pair.of(5L, 10L), Pair.of(10L, 20L), Pair.of(20L, 40L), Pair.of(40L, 80L), Pair.of(80L, 120L), Pair.of(80L, 120L), Pair.of(80L, 120L), Pair.of(80L, 120L), Pair.of(80L, 120L)); StreamUtil.<Long, Pair<Long, Long>, Void>zip(backoffs, ranges, (backoff, maxPair) -> { assertTrue(backoff >= maxPair.getLeft()); assertTrue(backoff <= maxPair.getRight()); return null; }); } @Test public void testEqualJitteredPolicy() throws Exception { Stream<Long> backoffs = Backoff.Jitter.of(EQUAL, 5, 120, 10).toBackoffs(); Stream<Pair<Long, Long>> ranges = Stream.of(Pair.of(5L, 10L), Pair.of(10L, 20L), Pair.of(20L, 40L), Pair.of(40L, 80L), Pair.of(80L, 120L), Pair.of(80L, 120L), Pair.of(80L, 120L), Pair.of(80L, 120L), Pair.of(80L, 120L)); StreamUtil.<Long, Pair<Long, Long>, Void>zip(backoffs, ranges, (backoff, maxPair) -> { assertTrue(backoff >= maxPair.getLeft()); assertTrue(backoff <= maxPair.getRight()); return null; }); } @Test public void testDecorrelatedJittered() throws Exception { long startMs = ThreadLocalRandom.current().nextLong(1L, 1000L); long maxMs = ThreadLocalRandom.current().nextLong(startMs, startMs * 2); Stream<Long> backoffs = Backoff.decorrelatedJittered(startMs, maxMs).limit(10); Iterator<Long> backoffIter = backoffs.iterator(); assertTrue(backoffIter.hasNext()); assertEquals(startMs, backoffIter.next().longValue()); AtomicLong prevMs = new AtomicLong(startMs); backoffIter.forEachRemaining(backoffMs -> { assertTrue(backoffMs >= startMs); assertTrue(backoffMs <= prevMs.get() * 3); assertTrue(backoffMs <= maxMs); prevMs.set(backoffMs); }); } @Test public void testDecorrelatedJitteredPolicy() throws Exception { long startMs = ThreadLocalRandom.current().nextLong(1L, 1000L); long maxMs = ThreadLocalRandom.current().nextLong(startMs, startMs * 2); Stream<Long> backoffs = Backoff.Jitter.of(DECORRELATED, startMs, maxMs, 10).toBackoffs(); Iterator<Long> backoffIter = backoffs.iterator(); assertTrue(backoffIter.hasNext()); assertEquals(startMs, backoffIter.next().longValue()); AtomicLong prevMs = new AtomicLong(startMs); backoffIter.forEachRemaining(backoffMs -> { assertTrue(backoffMs >= startMs); assertTrue(backoffMs <= prevMs.get() * 3); assertTrue(backoffMs <= maxMs); prevMs.set(backoffMs); }); } }