]> git.basschouten.com Git - openhab-addons.git/blob
c944a814e44b9eae38f7c98660ac80684eb35b0c
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.mielecloud.internal.webservice.retry;
14
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.mockito.ArgumentMatchers.any;
17 import static org.mockito.Mockito.*;
18
19 import java.util.Objects;
20 import java.util.function.Consumer;
21 import java.util.function.Supplier;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.junit.jupiter.api.Test;
26 import org.junit.jupiter.api.extension.ExtendWith;
27 import org.mockito.Mock;
28 import org.mockito.junit.jupiter.MockitoExtension;
29 import org.openhab.binding.mielecloud.internal.webservice.exception.MieleWebserviceException;
30 import org.openhab.binding.mielecloud.internal.webservice.exception.MieleWebserviceTransientException;
31
32 /**
33  * @author Björn Lange - Initial contribution
34  */
35 @ExtendWith(MockitoExtension.class)
36 @NonNullByDefault
37 public class NTimesRetryStrategyTest {
38     private static final int SUCCESSFUL_RETURN_VALUE = 42;
39
40     @Mock
41     @Nullable
42     private Supplier<@Nullable Integer> operation;
43
44     @Mock
45     @Nullable
46     private Consumer<Exception> onTransientException;
47
48     private Supplier<@Nullable Integer> getOperation() {
49         assertNotNull(operation);
50         return Objects.requireNonNull(operation);
51     }
52
53     private Consumer<Exception> getOnTransientException() {
54         assertNotNull(onTransientException);
55         return Objects.requireNonNull(onTransientException);
56     }
57
58     @Test
59     public void testConstructorThrowsIllegalArgumentExceptionIfNumberOfRetriesIsSmallerThanZero() {
60         // when:
61         assertThrows(IllegalArgumentException.class, () -> {
62             new NTimesRetryStrategy(-1);
63         });
64     }
65
66     @Test
67     public void testSuccessfulOperationReturnsCorrectValue() {
68         // given:
69         when(getOperation().get()).thenReturn(SUCCESSFUL_RETURN_VALUE);
70
71         NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
72
73         // when:
74         Integer result = retryStrategy.performRetryableOperation(getOperation(), getOnTransientException());
75
76         // then:
77         assertEquals(Integer.valueOf(SUCCESSFUL_RETURN_VALUE), result);
78         verifyNoMoreInteractions(onTransientException);
79     }
80
81     @Test
82     public void testFailingOperationReturnsCorrectValueOnRetry() {
83         // given:
84         when(getOperation().get()).thenThrow(MieleWebserviceTransientException.class)
85                 .thenReturn(SUCCESSFUL_RETURN_VALUE);
86
87         NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
88
89         // when:
90         Integer result = retryStrategy.performRetryableOperation(getOperation(), getOnTransientException());
91
92         // then:
93         assertEquals(Integer.valueOf(SUCCESSFUL_RETURN_VALUE), result);
94         verify(getOnTransientException()).accept(any());
95         verifyNoMoreInteractions(onTransientException);
96     }
97
98     @Test
99     public void testFailingOperationReturnsCorrectValueOnSecondRetry() {
100         // given:
101         when(getOperation().get()).thenThrow(MieleWebserviceTransientException.class)
102                 .thenThrow(MieleWebserviceTransientException.class).thenReturn(SUCCESSFUL_RETURN_VALUE);
103
104         NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(2);
105
106         // when:
107         Integer result = retryStrategy.performRetryableOperation(getOperation(), getOnTransientException());
108
109         // then:
110         assertEquals(Integer.valueOf(SUCCESSFUL_RETURN_VALUE), result);
111         verify(getOnTransientException(), times(2)).accept(any());
112         verifyNoMoreInteractions(onTransientException);
113     }
114
115     @Test
116     public void testAlwaysFailingOperationThrowsMieleWebserviceException() {
117         // given:
118         when(getOperation().get()).thenThrow(MieleWebserviceTransientException.class);
119
120         NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
121
122         // when:
123         try {
124             retryStrategy.performRetryableOperation(getOperation(), getOnTransientException());
125             fail();
126             return;
127         } catch (MieleWebserviceException e) {
128         }
129
130         // then:
131         verify(getOnTransientException()).accept(any());
132         verifyNoMoreInteractions(onTransientException);
133     }
134
135     @Test
136     public void testNullReturnValueDoesNotCauseMultipleRetries() {
137         // given:
138         when(getOperation().get()).thenReturn(null);
139
140         NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
141
142         // when:
143         retryStrategy.performRetryableOperation(getOperation(), getOnTransientException());
144
145         // then:
146         verifyNoInteractions(getOnTransientException());
147     }
148
149     @Test
150     public void testSuccessfulOperation() {
151         // given:
152         Runnable operation = mock(Runnable.class);
153         doNothing().when(operation).run();
154
155         NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
156
157         // when:
158         retryStrategy.performRetryableOperation(operation, getOnTransientException());
159
160         // then:
161         verify(operation).run();
162         verifyNoInteractions(getOnTransientException());
163     }
164
165     @Test
166     public void testFailingOperationCausesRetry() {
167         // given:
168         Runnable operation = mock(Runnable.class);
169         doThrow(MieleWebserviceTransientException.class).doNothing().when(operation).run();
170
171         NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
172
173         // when:
174         retryStrategy.performRetryableOperation(operation, getOnTransientException());
175
176         // then:
177         verify(getOnTransientException()).accept(any());
178         verify(operation, times(2)).run();
179         verifyNoMoreInteractions(getOnTransientException());
180     }
181
182     @Test
183     public void testTwoTimesFailingOperationCausesTwoRetries() {
184         // given:
185         Runnable operation = mock(Runnable.class);
186         doThrow(MieleWebserviceTransientException.class).doThrow(MieleWebserviceTransientException.class).doNothing()
187                 .when(operation).run();
188
189         NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(2);
190
191         // when:
192         retryStrategy.performRetryableOperation(operation, getOnTransientException());
193
194         // then:
195         verify(getOnTransientException(), times(2)).accept(any());
196         verify(operation, times(3)).run();
197         verifyNoMoreInteractions(getOnTransientException());
198     }
199
200     @Test
201     public void testAlwaysFailingRunnableOperationThrowsMieleWebserviceException() {
202         // given:
203         Runnable operation = mock(Runnable.class);
204         doThrow(MieleWebserviceTransientException.class).when(operation).run();
205
206         NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
207
208         // when:
209         try {
210             retryStrategy.performRetryableOperation(operation, getOnTransientException());
211             fail();
212             return;
213         } catch (MieleWebserviceException e) {
214         }
215
216         // then:
217         verify(getOnTransientException()).accept(any());
218         verifyNoMoreInteractions(getOnTransientException());
219     }
220 }