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.auth;
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.mockito.ArgumentMatchers.any;
17 import static org.mockito.Mockito.*;
19 import java.io.IOException;
21 import java.util.Objects;
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.junit.jupiter.api.Test;
26 import org.mockito.invocation.InvocationOnMock;
27 import org.mockito.stubbing.Answer;
28 import org.openhab.binding.mielecloud.internal.MieleCloudBindingTestConstants;
29 import org.openhab.binding.mielecloud.internal.util.ReflectionUtil;
30 import org.openhab.core.auth.client.oauth2.AccessTokenRefreshListener;
31 import org.openhab.core.auth.client.oauth2.AccessTokenResponse;
32 import org.openhab.core.auth.client.oauth2.OAuthClientService;
33 import org.openhab.core.auth.client.oauth2.OAuthFactory;
34 import org.openhab.core.auth.client.oauth2.OAuthResponseException;
37 * @author Björn Lange - Initial contribution
40 public class OpenHabOAuthTokenRefresherTest {
41 private static final String ACCESS_TOKEN = "DE_0123456789abcdef0123456789abcdef";
43 private boolean hasAccessTokenRefreshListenerForServiceHandle(OpenHabOAuthTokenRefresher refresher,
45 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
47 .<Map<String, @Nullable AccessTokenRefreshListener>> getPrivate(refresher, "listenerByServiceHandle")
48 .get(MieleCloudBindingTestConstants.SERVICE_HANDLE) != null;
51 private AccessTokenRefreshListener getAccessTokenRefreshListenerByServiceHandle(
52 OpenHabOAuthTokenRefresher refresher, String serviceHandle)
53 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
54 AccessTokenRefreshListener listener = ReflectionUtil
55 .<Map<String, @Nullable AccessTokenRefreshListener>> getPrivate(refresher, "listenerByServiceHandle")
56 .get(MieleCloudBindingTestConstants.SERVICE_HANDLE);
57 assertNotNull(listener);
58 return Objects.requireNonNull(listener);
62 public void whenTheAccountWasNotConfiguredPriorToTheThingInitializingThenNoRefreshListenerCanBeRegistered() {
64 OAuthFactory oauthFactory = mock(OAuthFactory.class);
65 OpenHabOAuthTokenRefresher refresher = new OpenHabOAuthTokenRefresher(oauthFactory);
66 OAuthTokenRefreshListener listener = mock(OAuthTokenRefreshListener.class);
69 assertThrows(OAuthException.class, () -> {
70 refresher.setRefreshListener(listener, MieleCloudBindingTestConstants.SERVICE_HANDLE);
75 public void whenARefreshListenerIsRegisteredThenAListenerIsRegisteredAtTheClientService()
76 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
78 OAuthClientService oauthClientService = mock(OAuthClientService.class);
80 OAuthFactory oauthFactory = mock(OAuthFactory.class);
81 when(oauthFactory.getOAuthClientService(MieleCloudBindingTestConstants.SERVICE_HANDLE))
82 .thenReturn(oauthClientService);
84 OpenHabOAuthTokenRefresher refresher = new OpenHabOAuthTokenRefresher(oauthFactory);
86 OAuthTokenRefreshListener listener = mock(OAuthTokenRefreshListener.class);
89 refresher.setRefreshListener(listener, MieleCloudBindingTestConstants.SERVICE_HANDLE);
92 verify(oauthClientService).addAccessTokenRefreshListener(any());
94 getAccessTokenRefreshListenerByServiceHandle(refresher, MieleCloudBindingTestConstants.SERVICE_HANDLE));
98 public void whenTokenIsRefreshedThenTheListenerIsCalledWithTheNewAccessToken()
99 throws org.openhab.core.auth.client.oauth2.OAuthException, IOException, OAuthResponseException {
101 AccessTokenResponse accessTokenResponse = new AccessTokenResponse();
102 accessTokenResponse.setAccessToken(ACCESS_TOKEN);
104 OAuthClientService oauthClientService = mock(OAuthClientService.class);
106 OAuthFactory oauthFactory = mock(OAuthFactory.class);
107 when(oauthFactory.getOAuthClientService(MieleCloudBindingTestConstants.SERVICE_HANDLE))
108 .thenReturn(oauthClientService);
110 OpenHabOAuthTokenRefresher refresher = new OpenHabOAuthTokenRefresher(oauthFactory);
111 when(oauthClientService.refreshToken()).thenAnswer(new Answer<@Nullable AccessTokenResponse>() {
114 public AccessTokenResponse answer(@Nullable InvocationOnMock invocation) throws Throwable {
115 getAccessTokenRefreshListenerByServiceHandle(refresher, MieleCloudBindingTestConstants.SERVICE_HANDLE)
116 .onAccessTokenResponse(accessTokenResponse);
117 return accessTokenResponse;
121 OAuthTokenRefreshListener listener = mock(OAuthTokenRefreshListener.class);
122 refresher.setRefreshListener(listener, MieleCloudBindingTestConstants.SERVICE_HANDLE);
125 refresher.refreshToken(MieleCloudBindingTestConstants.SERVICE_HANDLE);
128 verify(listener).onNewAccessToken(ACCESS_TOKEN);
132 public void whenTokenIsRefreshedAndNoAccessTokenIsProvidedThenTheListenerIsNotNotified()
133 throws org.openhab.core.auth.client.oauth2.OAuthException, IOException, OAuthResponseException {
135 AccessTokenResponse accessTokenResponse = new AccessTokenResponse();
137 OAuthClientService oauthClientService = mock(OAuthClientService.class);
139 OAuthFactory oauthFactory = mock(OAuthFactory.class);
140 when(oauthFactory.getOAuthClientService(MieleCloudBindingTestConstants.SERVICE_HANDLE))
141 .thenReturn(oauthClientService);
143 OpenHabOAuthTokenRefresher refresher = new OpenHabOAuthTokenRefresher(oauthFactory);
144 when(oauthClientService.refreshToken()).thenAnswer(new Answer<@Nullable AccessTokenResponse>() {
147 public AccessTokenResponse answer(@Nullable InvocationOnMock invocation) throws Throwable {
148 getAccessTokenRefreshListenerByServiceHandle(refresher, MieleCloudBindingTestConstants.SERVICE_HANDLE)
149 .onAccessTokenResponse(accessTokenResponse);
150 return accessTokenResponse;
154 OAuthTokenRefreshListener listener = mock(OAuthTokenRefreshListener.class);
155 refresher.setRefreshListener(listener, MieleCloudBindingTestConstants.SERVICE_HANDLE);
158 assertThrows(OAuthException.class, () -> {
160 refresher.refreshToken(MieleCloudBindingTestConstants.SERVICE_HANDLE);
161 } catch (OAuthException e) {
162 verifyNoInteractions(listener);
169 public void whenTokenRefreshFailsWithOAuthExceptionThenTheListenerIsNotNotified()
170 throws org.openhab.core.auth.client.oauth2.OAuthException, IOException, OAuthResponseException {
172 OAuthClientService oauthClientService = mock(OAuthClientService.class);
173 when(oauthClientService.refreshToken()).thenThrow(new org.openhab.core.auth.client.oauth2.OAuthException());
175 OAuthFactory oauthFactory = mock(OAuthFactory.class);
176 when(oauthFactory.getOAuthClientService(MieleCloudBindingTestConstants.SERVICE_HANDLE))
177 .thenReturn(oauthClientService);
179 OpenHabOAuthTokenRefresher refresher = new OpenHabOAuthTokenRefresher(oauthFactory);
181 OAuthTokenRefreshListener listener = mock(OAuthTokenRefreshListener.class);
182 refresher.setRefreshListener(listener, MieleCloudBindingTestConstants.SERVICE_HANDLE);
185 assertThrows(OAuthException.class, () -> {
187 refresher.refreshToken(MieleCloudBindingTestConstants.SERVICE_HANDLE);
188 } catch (OAuthException e) {
189 verifyNoInteractions(listener);
196 public void whenTokenRefreshFailsDueToNetworkErrorThenTheListenerIsNotNotified()
197 throws org.openhab.core.auth.client.oauth2.OAuthException, IOException, OAuthResponseException {
199 OAuthClientService oauthClientService = mock(OAuthClientService.class);
200 when(oauthClientService.refreshToken()).thenThrow(new IOException());
202 OAuthFactory oauthFactory = mock(OAuthFactory.class);
203 when(oauthFactory.getOAuthClientService(MieleCloudBindingTestConstants.SERVICE_HANDLE))
204 .thenReturn(oauthClientService);
206 OpenHabOAuthTokenRefresher refresher = new OpenHabOAuthTokenRefresher(oauthFactory);
208 OAuthTokenRefreshListener listener = mock(OAuthTokenRefreshListener.class);
209 refresher.setRefreshListener(listener, MieleCloudBindingTestConstants.SERVICE_HANDLE);
212 assertThrows(OAuthException.class, () -> {
214 refresher.refreshToken(MieleCloudBindingTestConstants.SERVICE_HANDLE);
215 } catch (OAuthException e) {
216 verifyNoInteractions(listener);
223 public void whenTokenRefreshFailsDueToAnIllegalResponseThenTheListenerIsNotNotified()
224 throws org.openhab.core.auth.client.oauth2.OAuthException, IOException, OAuthResponseException {
226 OAuthClientService oauthClientService = mock(OAuthClientService.class);
227 when(oauthClientService.refreshToken()).thenThrow(new OAuthResponseException());
229 OAuthFactory oauthFactory = mock(OAuthFactory.class);
230 when(oauthFactory.getOAuthClientService(MieleCloudBindingTestConstants.SERVICE_HANDLE))
231 .thenReturn(oauthClientService);
233 OpenHabOAuthTokenRefresher refresher = new OpenHabOAuthTokenRefresher(oauthFactory);
235 OAuthTokenRefreshListener listener = mock(OAuthTokenRefreshListener.class);
236 refresher.setRefreshListener(listener, MieleCloudBindingTestConstants.SERVICE_HANDLE);
239 assertThrows(OAuthException.class, () -> {
241 refresher.refreshToken(MieleCloudBindingTestConstants.SERVICE_HANDLE);
242 } catch (OAuthException e) {
243 verifyNoInteractions(listener);
250 public void whenTheRefreshListenerIsUnsetAndWasNotRegisteredBeforeThenNothingHappens()
251 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
253 OAuthFactory oauthFactory = mock(OAuthFactory.class);
254 OpenHabOAuthTokenRefresher refresher = new OpenHabOAuthTokenRefresher(oauthFactory);
257 refresher.unsetRefreshListener(MieleCloudBindingTestConstants.SERVICE_HANDLE);
260 assertFalse(hasAccessTokenRefreshListenerForServiceHandle(refresher,
261 MieleCloudBindingTestConstants.SERVICE_HANDLE));
265 public void whenTheRefreshListenerIsUnsetAndTheClientServiceIsNotAvailableThenTheListenerIsCleared()
266 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
268 OAuthClientService oauthClientService = mock(OAuthClientService.class);
270 OAuthFactory oauthFactory = mock(OAuthFactory.class);
271 when(oauthFactory.getOAuthClientService(MieleCloudBindingTestConstants.SERVICE_HANDLE))
272 .thenReturn(oauthClientService);
274 OpenHabOAuthTokenRefresher refresher = new OpenHabOAuthTokenRefresher(oauthFactory);
276 OAuthTokenRefreshListener listener = mock(OAuthTokenRefreshListener.class);
278 refresher.setRefreshListener(listener, MieleCloudBindingTestConstants.SERVICE_HANDLE);
281 refresher.unsetRefreshListener(MieleCloudBindingTestConstants.SERVICE_HANDLE);
284 assertFalse(hasAccessTokenRefreshListenerForServiceHandle(refresher,
285 MieleCloudBindingTestConstants.SERVICE_HANDLE));
289 public void whenTheRefreshListenerIsUnsetThenTheListenerIsClearedAndRemovedFromTheClientService()
290 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
292 OAuthClientService oauthClientService = mock(OAuthClientService.class);
294 OAuthFactory oauthFactory = mock(OAuthFactory.class);
295 when(oauthFactory.getOAuthClientService(MieleCloudBindingTestConstants.SERVICE_HANDLE))
296 .thenReturn(oauthClientService);
298 OpenHabOAuthTokenRefresher refresher = new OpenHabOAuthTokenRefresher(oauthFactory);
300 OAuthTokenRefreshListener listener = mock(OAuthTokenRefreshListener.class);
302 refresher.setRefreshListener(listener, MieleCloudBindingTestConstants.SERVICE_HANDLE);
305 refresher.unsetRefreshListener(MieleCloudBindingTestConstants.SERVICE_HANDLE);
308 verify(oauthClientService).removeAccessTokenRefreshListener(any());
309 assertFalse(hasAccessTokenRefreshListenerForServiceHandle(refresher,
310 MieleCloudBindingTestConstants.SERVICE_HANDLE));
314 public void whenTokensAreRemovedThenTheRuntimeIsRequestedToDeleteServiceAndAccessToken()
315 throws org.openhab.core.auth.client.oauth2.OAuthException, IOException, OAuthResponseException {
317 OAuthClientService oauthClientService = mock(OAuthClientService.class);
319 OAuthFactory oauthFactory = mock(OAuthFactory.class);
320 when(oauthFactory.getOAuthClientService(MieleCloudBindingTestConstants.SERVICE_HANDLE))
321 .thenReturn(oauthClientService);
323 OpenHabOAuthTokenRefresher refresher = new OpenHabOAuthTokenRefresher(oauthFactory);
325 OAuthTokenRefreshListener listener = mock(OAuthTokenRefreshListener.class);
326 refresher.setRefreshListener(listener, MieleCloudBindingTestConstants.SERVICE_HANDLE);
329 refresher.removeTokensFromStorage(MieleCloudBindingTestConstants.SERVICE_HANDLE);
332 verify(oauthFactory).deleteServiceAndAccessToken(MieleCloudBindingTestConstants.SERVICE_HANDLE);