• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.devicelockcontroller.receivers;
18 
19 import static com.android.devicelockcontroller.WorkManagerExceptionHandler.ALARM_REASON;
20 
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.eq;
23 import static org.mockito.Mockito.verify;
24 import static org.mockito.Mockito.verifyNoInteractions;
25 import static org.mockito.Mockito.verifyNoMoreInteractions;
26 import static org.mockito.Mockito.when;
27 import static org.robolectric.Shadows.shadowOf;
28 
29 import android.content.BroadcastReceiver;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.os.Bundle;
33 import android.os.Handler;
34 import android.os.HandlerThread;
35 import android.os.Looper;
36 
37 import androidx.test.core.app.ApplicationProvider;
38 
39 import com.android.devicelockcontroller.TestDeviceLockControllerApplication;
40 import com.android.devicelockcontroller.WorkManagerExceptionHandler;
41 import com.android.devicelockcontroller.WorkManagerExceptionHandler.AlarmReason;
42 import com.android.devicelockcontroller.schedule.DeviceLockControllerScheduler;
43 import com.android.devicelockcontroller.storage.GlobalParametersClient;
44 
45 import com.google.common.util.concurrent.Futures;
46 import com.google.common.util.concurrent.ListenableFuture;
47 import com.google.common.util.concurrent.SettableFuture;
48 
49 import org.junit.Before;
50 import org.junit.Test;
51 import org.junit.runner.RunWith;
52 import org.robolectric.RobolectricTestRunner;
53 
54 import java.time.Duration;
55 import java.util.concurrent.TimeUnit;
56 
57 @RunWith(RobolectricTestRunner.class)
58 public final class WorkFailureAlarmReceiverTest {
59     private static final long TIMEOUT_MILLIS = 1000;
60 
61     private DeviceLockControllerScheduler mScheduler;
62     private TestDeviceLockControllerApplication mTestApp;
63     private Handler mHandler;
64 
65     @Before
setUp()66     public void setUp() {
67         final HandlerThread handlerThread = new HandlerThread("BroadcastHandlerThread");
68         handlerThread.start();
69         mHandler = handlerThread.getThreadHandler();
70 
71         mTestApp = ApplicationProvider.getApplicationContext();
72         mScheduler = mTestApp.getDeviceLockControllerScheduler();
73     }
74 
75     @Test
onReceive_reasonInitialization_shouldCallMaybeScheduleInitialCheckIn()76     public void onReceive_reasonInitialization_shouldCallMaybeScheduleInitialCheckIn()
77             throws Exception {
78         GlobalParametersClient.getInstance().setProvisionReady(false).get();
79 
80         when(mScheduler.maybeScheduleInitialCheckIn()).thenReturn(Futures.immediateVoidFuture());
81 
82         final ListenableFuture<Void> broadcastComplete =
83                 sendBroadcastToWorkFailureAlarmReceiver(AlarmReason.INITIALIZATION);
84 
85         shadowOf(Looper.getMainLooper()).idle();
86 
87         broadcastComplete.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
88 
89         verify(mScheduler).maybeScheduleInitialCheckIn();
90         verifyNoMoreInteractions(mScheduler);
91     }
92 
93     @Test
onReceive_reasonInitialCheckIn_shouldCallMaybeScheduleInitialCheckIn()94     public void onReceive_reasonInitialCheckIn_shouldCallMaybeScheduleInitialCheckIn()
95             throws Exception {
96         GlobalParametersClient.getInstance().setProvisionReady(false).get();
97 
98         when(mScheduler.maybeScheduleInitialCheckIn()).thenReturn(Futures.immediateVoidFuture());
99 
100         final ListenableFuture<Void> broadcastComplete =
101                 sendBroadcastToWorkFailureAlarmReceiver(AlarmReason.INITIAL_CHECK_IN);
102 
103         shadowOf(Looper.getMainLooper()).idle();
104 
105         broadcastComplete.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
106 
107         verify(mScheduler).maybeScheduleInitialCheckIn();
108         verifyNoMoreInteractions(mScheduler);
109     }
110 
111     @Test
onReceive_reasonRetryCheckIn_shouldCallScheduleRetryCheckInWork()112     public void onReceive_reasonRetryCheckIn_shouldCallScheduleRetryCheckInWork() throws Exception {
113         GlobalParametersClient.getInstance().setProvisionReady(false).get();
114 
115         when(mScheduler.scheduleRetryCheckInWork(any(Duration.class)))
116                 .thenReturn(Futures.immediateVoidFuture());
117 
118         final ListenableFuture<Void> broadcastComplete =
119                 sendBroadcastToWorkFailureAlarmReceiver(AlarmReason.RETRY_CHECK_IN);
120 
121         shadowOf(Looper.getMainLooper()).idle();
122 
123         broadcastComplete.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
124 
125         verify(mScheduler).scheduleRetryCheckInWork(eq(Duration.ZERO));
126         verifyNoMoreInteractions(mScheduler);
127     }
128 
129     @Test
onReceive_reasonRescheduleCheckIn_shouldCallNotifyNeedRescheduleCheckIn()130     public void onReceive_reasonRescheduleCheckIn_shouldCallNotifyNeedRescheduleCheckIn()
131             throws Exception {
132         GlobalParametersClient.getInstance().setProvisionReady(false).get();
133 
134         when(mScheduler.notifyNeedRescheduleCheckIn()).thenReturn(Futures.immediateVoidFuture());
135 
136         final ListenableFuture<Void> broadcastComplete =
137                 sendBroadcastToWorkFailureAlarmReceiver(AlarmReason.RESCHEDULE_CHECK_IN);
138 
139         shadowOf(Looper.getMainLooper()).idle();
140 
141         broadcastComplete.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
142 
143         verify(mScheduler).notifyNeedRescheduleCheckIn();
144         verifyNoMoreInteractions(mScheduler);
145     }
146 
147     @Test
onReceive_whenProvisionReady_doesNotSchedule()148     public void onReceive_whenProvisionReady_doesNotSchedule() throws Exception {
149         GlobalParametersClient.getInstance().setProvisionReady(true).get();
150 
151         when(mScheduler.maybeScheduleInitialCheckIn()).thenReturn(Futures.immediateVoidFuture());
152 
153         final ListenableFuture<Void> broadcastComplete =
154                 sendBroadcastToWorkFailureAlarmReceiver(AlarmReason.INITIALIZATION);
155 
156         shadowOf(Looper.getMainLooper()).idle();
157 
158         broadcastComplete.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
159 
160         verifyNoInteractions(mScheduler);
161     }
162 
getIntentForAlarmReason(@larmReason int alarmReason)163     private Intent getIntentForAlarmReason(@AlarmReason int alarmReason) {
164         final Intent intent = new Intent(mTestApp,
165                 WorkManagerExceptionHandler.WorkFailureAlarmReceiver.class);
166         final Bundle bundle = new Bundle();
167         bundle.putInt(ALARM_REASON, alarmReason);
168         intent.putExtras(bundle);
169         return intent;
170     }
171 
sendBroadcastToWorkFailureAlarmReceiver( @larmReason int alarmReason)172     private ListenableFuture<Void> sendBroadcastToWorkFailureAlarmReceiver(
173             @AlarmReason int alarmReason) {
174         final SettableFuture<Void> broadcastComplete = SettableFuture.create();
175 
176         mTestApp.sendOrderedBroadcast(
177                 getIntentForAlarmReason(alarmReason),
178                 null /* receiverPermission */,
179                 new BroadcastReceiver() {
180                     @Override
181                     public void onReceive(Context context, Intent intent) {
182                         broadcastComplete.set(null);
183                     }
184                 },
185                 mHandler /* scheduler */,
186                 0 /* initialCode */,
187                 null /* initialData */,
188                 null /* initialExtras */);
189 
190         return broadcastComplete;
191     }
192 }
193