2 * Copyright (c) 2010-2023 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.mielecloud.internal.webservice.retry;
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.mockito.ArgumentMatchers.any;
17 import static org.mockito.Mockito.*;
19 import java.util.Objects;
20 import java.util.function.Consumer;
21 import java.util.function.Supplier;
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;
33 * @author Björn Lange - Initial contribution
35 @ExtendWith(MockitoExtension.class)
37 public class NTimesRetryStrategyTest {
38 private static final int SUCCESSFUL_RETURN_VALUE = 42;
42 private Supplier<@Nullable Integer> operation;
46 private Consumer<Exception> onTransientException;
48 private Supplier<@Nullable Integer> getOperation() {
49 assertNotNull(operation);
50 return Objects.requireNonNull(operation);
53 private Consumer<Exception> getOnTransientException() {
54 assertNotNull(onTransientException);
55 return Objects.requireNonNull(onTransientException);
59 public void testConstructorThrowsIllegalArgumentExceptionIfNumberOfRetriesIsSmallerThanZero() {
61 assertThrows(IllegalArgumentException.class, () -> {
62 new NTimesRetryStrategy(-1);
67 public void testSuccessfulOperationReturnsCorrectValue() {
69 when(getOperation().get()).thenReturn(SUCCESSFUL_RETURN_VALUE);
71 NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
74 Integer result = retryStrategy.performRetryableOperation(getOperation(), getOnTransientException());
77 assertEquals(Integer.valueOf(SUCCESSFUL_RETURN_VALUE), result);
78 verifyNoMoreInteractions(onTransientException);
82 public void testFailingOperationReturnsCorrectValueOnRetry() {
84 when(getOperation().get()).thenThrow(MieleWebserviceTransientException.class)
85 .thenReturn(SUCCESSFUL_RETURN_VALUE);
87 NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
90 Integer result = retryStrategy.performRetryableOperation(getOperation(), getOnTransientException());
93 assertEquals(Integer.valueOf(SUCCESSFUL_RETURN_VALUE), result);
94 verify(getOnTransientException()).accept(any());
95 verifyNoMoreInteractions(onTransientException);
99 public void testFailingOperationReturnsCorrectValueOnSecondRetry() {
101 when(getOperation().get()).thenThrow(MieleWebserviceTransientException.class)
102 .thenThrow(MieleWebserviceTransientException.class).thenReturn(SUCCESSFUL_RETURN_VALUE);
104 NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(2);
107 Integer result = retryStrategy.performRetryableOperation(getOperation(), getOnTransientException());
110 assertEquals(Integer.valueOf(SUCCESSFUL_RETURN_VALUE), result);
111 verify(getOnTransientException(), times(2)).accept(any());
112 verifyNoMoreInteractions(onTransientException);
116 public void testAlwaysFailingOperationThrowsMieleWebserviceException() {
118 when(getOperation().get()).thenThrow(MieleWebserviceTransientException.class);
120 NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
124 retryStrategy.performRetryableOperation(getOperation(), getOnTransientException());
127 } catch (MieleWebserviceException e) {
131 verify(getOnTransientException()).accept(any());
132 verifyNoMoreInteractions(onTransientException);
136 public void testNullReturnValueDoesNotCauseMultipleRetries() {
138 when(getOperation().get()).thenReturn(null);
140 NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
143 retryStrategy.performRetryableOperation(getOperation(), getOnTransientException());
146 verifyNoInteractions(getOnTransientException());
150 public void testSuccessfulOperation() {
152 Runnable operation = mock(Runnable.class);
153 doNothing().when(operation).run();
155 NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
158 retryStrategy.performRetryableOperation(operation, getOnTransientException());
161 verify(operation).run();
162 verifyNoInteractions(getOnTransientException());
166 public void testFailingOperationCausesRetry() {
168 Runnable operation = mock(Runnable.class);
169 doThrow(MieleWebserviceTransientException.class).doNothing().when(operation).run();
171 NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
174 retryStrategy.performRetryableOperation(operation, getOnTransientException());
177 verify(getOnTransientException()).accept(any());
178 verify(operation, times(2)).run();
179 verifyNoMoreInteractions(getOnTransientException());
183 public void testTwoTimesFailingOperationCausesTwoRetries() {
185 Runnable operation = mock(Runnable.class);
186 doThrow(MieleWebserviceTransientException.class).doThrow(MieleWebserviceTransientException.class).doNothing()
187 .when(operation).run();
189 NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(2);
192 retryStrategy.performRetryableOperation(operation, getOnTransientException());
195 verify(getOnTransientException(), times(2)).accept(any());
196 verify(operation, times(3)).run();
197 verifyNoMoreInteractions(getOnTransientException());
201 public void testAlwaysFailingRunnableOperationThrowsMieleWebserviceException() {
203 Runnable operation = mock(Runnable.class);
204 doThrow(MieleWebserviceTransientException.class).when(operation).run();
206 NTimesRetryStrategy retryStrategy = new NTimesRetryStrategy(1);
210 retryStrategy.performRetryableOperation(operation, getOnTransientException());
213 } catch (MieleWebserviceException e) {
217 verify(getOnTransientException()).accept(any());
218 verifyNoMoreInteractions(getOnTransientException());