2 * Copyright (c) 2010-2020 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.bluetooth.util;
15 import static org.junit.jupiter.api.Assertions.*;
17 import java.util.concurrent.CompletableFuture;
18 import java.util.concurrent.CountDownLatch;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Future;
21 import java.util.concurrent.ScheduledExecutorService;
22 import java.util.concurrent.ScheduledThreadPoolExecutor;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.TimeoutException;
25 import java.util.concurrent.atomic.AtomicInteger;
27 import org.junit.jupiter.api.AfterEach;
28 import org.junit.jupiter.api.BeforeEach;
29 import org.junit.jupiter.api.Test;
30 import org.openhab.core.common.NamedThreadFactory;
33 * @author Connor Petty - Initial contribution
36 class RetryFutureTest {
38 private ScheduledExecutorService scheduler;
42 ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(1,
43 new NamedThreadFactory("RetryFutureTest", true));
44 scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
45 scheduler.setRemoveOnCancelPolicy(true);
46 this.scheduler = scheduler;
50 public void cleanup() {
51 scheduler.shutdownNow();
55 void callWithRetryNormal() throws InterruptedException {
56 Future<String> retryFuture = RetryFuture.callWithRetry(() -> "test", scheduler);
58 assertEquals("test", retryFuture.get(100, TimeUnit.MILLISECONDS));
59 } catch (InterruptedException | ExecutionException | TimeoutException e) {
65 void callWithRetry1() throws InterruptedException {
66 AtomicInteger visitCount = new AtomicInteger();
67 Future<String> retryFuture = RetryFuture.callWithRetry(() -> {
68 if (visitCount.getAndIncrement() == 0) {
69 throw new RetryException(0, TimeUnit.SECONDS);
74 assertEquals("test", retryFuture.get(100, TimeUnit.MILLISECONDS));
75 } catch (InterruptedException | ExecutionException | TimeoutException e) {
81 void composeWithRetryNormal() throws InterruptedException {
82 CompletableFuture<?> composedFuture = new CompletableFuture<>();
84 Future<?> retryFuture = RetryFuture.composeWithRetry(() -> {
85 composedFuture.complete(null);
86 return composedFuture;
90 retryFuture.get(100, TimeUnit.MILLISECONDS);
91 } catch (InterruptedException | ExecutionException | TimeoutException e) {
94 assertTrue(composedFuture.isDone());
98 void composeWithRetryThrow() throws InterruptedException {
99 CompletableFuture<?> composedFuture = new CompletableFuture<>();
101 Future<?> retryFuture = RetryFuture.composeWithRetry(() -> {
102 composedFuture.completeExceptionally(new DummyException());
103 return composedFuture;
107 retryFuture.get(100, TimeUnit.MILLISECONDS);
108 } catch (InterruptedException | TimeoutException e) {
110 } catch (ExecutionException ex) {
111 assertTrue(ex.getCause() instanceof DummyException);
113 assertTrue(composedFuture.isDone());
117 void composeWithRetry1() throws InterruptedException {
118 AtomicInteger visitCount = new AtomicInteger();
119 CompletableFuture<String> composedFuture = new CompletableFuture<>();
120 Future<String> retryFuture = RetryFuture.composeWithRetry(() -> {
121 if (visitCount.getAndIncrement() == 0) {
122 return CompletableFuture.failedFuture(new RetryException(0, TimeUnit.SECONDS));
124 composedFuture.complete("test");
125 return composedFuture;
129 assertEquals("test", retryFuture.get(100, TimeUnit.MILLISECONDS));
130 } catch (InterruptedException | ExecutionException | TimeoutException e) {
133 assertEquals(2, visitCount.get());
134 assertTrue(composedFuture.isDone());
138 void composeWithRetry1Cancel() throws InterruptedException {
139 CountDownLatch latch = new CountDownLatch(1);
140 AtomicInteger visitCount = new AtomicInteger();
141 CompletableFuture<String> composedFuture = new CompletableFuture<>();
142 Future<String> retryFuture = RetryFuture.composeWithRetry(() -> {
143 if (visitCount.getAndIncrement() == 0) {
144 return CompletableFuture.failedFuture(new RetryException(0, TimeUnit.SECONDS));
147 return composedFuture;
151 if (!latch.await(100, TimeUnit.MILLISECONDS)) {
152 fail("Timeout while waiting for latch");
155 retryFuture.cancel(false);
157 assertTrue(composedFuture.isCancelled());
158 } catch (InterruptedException e) {
161 assertEquals(2, visitCount.get());
162 assertTrue(composedFuture.isDone());
165 private static class DummyException extends Exception {