]> git.basschouten.com Git - openhab-addons.git/blob
b16621a5b5b4f0e416ed76f33a1dabc9278284b7
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.bluetooth.util;
14
15 import static org.junit.jupiter.api.Assertions.*;
16
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;
26
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;
31
32 /**
33  * @author Connor Petty - Initial contribution
34  *
35  */
36 class RetryFutureTest {
37
38     private ScheduledExecutorService scheduler;
39
40     @BeforeEach
41     public void init() {
42         ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(1,
43                 new NamedThreadFactory("RetryFutureTest", true));
44         scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
45         scheduler.setRemoveOnCancelPolicy(true);
46         this.scheduler = scheduler;
47     }
48
49     @AfterEach
50     public void cleanup() {
51         scheduler.shutdownNow();
52     }
53
54     @Test
55     void callWithRetryNormal() throws InterruptedException {
56         Future<String> retryFuture = RetryFuture.callWithRetry(() -> "test", scheduler);
57         try {
58             assertEquals("test", retryFuture.get(100, TimeUnit.MILLISECONDS));
59         } catch (InterruptedException | ExecutionException | TimeoutException e) {
60             fail(e);
61         }
62     }
63
64     @Test
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);
70             }
71             return "test";
72         }, scheduler);
73         try {
74             assertEquals("test", retryFuture.get(100, TimeUnit.MILLISECONDS));
75         } catch (InterruptedException | ExecutionException | TimeoutException e) {
76             fail(e);
77         }
78     }
79
80     @Test
81     void composeWithRetryNormal() throws InterruptedException {
82         CompletableFuture<?> composedFuture = new CompletableFuture<>();
83
84         Future<?> retryFuture = RetryFuture.composeWithRetry(() -> {
85             composedFuture.complete(null);
86             return composedFuture;
87         }, scheduler);
88
89         try {
90             retryFuture.get(100, TimeUnit.MILLISECONDS);
91         } catch (InterruptedException | ExecutionException | TimeoutException e) {
92             fail(e);
93         }
94         assertTrue(composedFuture.isDone());
95     }
96
97     @Test
98     void composeWithRetryThrow() throws InterruptedException {
99         CompletableFuture<?> composedFuture = new CompletableFuture<>();
100
101         Future<?> retryFuture = RetryFuture.composeWithRetry(() -> {
102             composedFuture.completeExceptionally(new DummyException());
103             return composedFuture;
104         }, scheduler);
105
106         try {
107             retryFuture.get(100, TimeUnit.MILLISECONDS);
108         } catch (InterruptedException | TimeoutException e) {
109             fail(e);
110         } catch (ExecutionException ex) {
111             assertTrue(ex.getCause() instanceof DummyException);
112         }
113         assertTrue(composedFuture.isDone());
114     }
115
116     @Test
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));
123             }
124             composedFuture.complete("test");
125             return composedFuture;
126         }, scheduler);
127
128         try {
129             assertEquals("test", retryFuture.get(100, TimeUnit.MILLISECONDS));
130         } catch (InterruptedException | ExecutionException | TimeoutException e) {
131             fail(e);
132         }
133         assertEquals(2, visitCount.get());
134         assertTrue(composedFuture.isDone());
135     }
136
137     @Test
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));
145             }
146             latch.countDown();
147             return composedFuture;
148         }, scheduler);
149
150         try {
151             if (!latch.await(100, TimeUnit.MILLISECONDS)) {
152                 fail("Timeout while waiting for latch");
153             }
154             Thread.sleep(1);
155             retryFuture.cancel(false);
156
157             assertTrue(composedFuture.isCancelled());
158         } catch (InterruptedException e) {
159             fail(e);
160         }
161         assertEquals(2, visitCount.get());
162         assertTrue(composedFuture.isDone());
163     }
164
165     private static class DummyException extends Exception {
166
167     }
168 }