1 /*
2  * Copyright 2016, 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.managedprovisioning.provisioning;
18 
19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
20 
21 import static org.junit.Assert.assertTrue;
22 import static org.mockito.Matchers.any;
23 import static org.mockito.Matchers.anyLong;
24 import static org.mockito.Mockito.doAnswer;
25 import static org.mockito.Mockito.times;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.verifyNoMoreInteractions;
28 import static org.mockito.Mockito.verifyZeroInteractions;
29 import static org.mockito.Mockito.when;
30 
31 import android.content.ComponentName;
32 import android.content.Context;
33 import android.os.Handler;
34 import android.os.Looper;
35 import android.os.Message;
36 
37 import androidx.test.filters.FlakyTest;
38 import androidx.test.filters.SmallTest;
39 import androidx.test.runner.AndroidJUnit4;
40 
41 import com.android.managedprovisioning.R;
42 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
43 import com.android.managedprovisioning.analytics.TimeLogger;
44 import com.android.managedprovisioning.model.ProvisioningParams;
45 
46 import org.junit.Before;
47 import org.junit.Ignore;
48 import org.junit.Test;
49 import org.junit.runner.RunWith;
50 import org.mockito.ArgumentCaptor;
51 import org.mockito.Mock;
52 import org.mockito.MockitoAnnotations;
53 import org.mockito.invocation.InvocationOnMock;
54 
55 import java.util.concurrent.Semaphore;
56 import java.util.concurrent.TimeUnit;
57 
58 /**
59  * Unit tests for {@link ProvisioningManager}.
60  */
61 @RunWith(AndroidJUnit4.class)
62 @SmallTest
63 public class ProvisioningManagerTest {
64     private final int TEST_PROGRESS_ID = 123;
65     private final int TEST_ERROR_ID = 456;
66     private final boolean TEST_FACTORY_RESET_REQUIRED = true;
67     private final ComponentName TEST_ADMIN = new ComponentName("com.test.admin", ".AdminReceiver");
68     private final ProvisioningParams TEST_PARAMS = new ProvisioningParams.Builder()
69             .setProvisioningAction(ACTION_PROVISION_MANAGED_PROFILE)
70             .setDeviceAdminComponentName(TEST_ADMIN)
71             .build();
72 
73     @Mock private Context mContext;
74     @Mock private ProvisioningControllerFactory mFactory;
75     @Mock private ProvisioningAnalyticsTracker mAnalyticsTracker;
76     @Mock private TimeLogger mTimeLogger;
77     @Mock private Handler mUiHandler;
78     @Mock private ProvisioningManagerCallback mCallback;
79     @Mock private AbstractProvisioningController mController;
80 
81     private ProvisioningManager mManager;
82 
83     @Before
setUp()84     public void setUp() {
85         MockitoAnnotations.initMocks(this);
86 
87         // Immediately execute any message that is sent onto the handler
88         when(mUiHandler.sendMessageAtTime(any(Message.class), anyLong())).thenAnswer(
89                 (InvocationOnMock invocation) -> {
90                     Message msg = (Message) invocation.getArguments()[0];
91                     msg.getCallback().run();
92                     return null;
93                 });
94         mManager = new ProvisioningManager(
95                 mContext,
96                 mFactory,
97                 mAnalyticsTracker,
98                 mTimeLogger);
99         when(mFactory.createProvisioningController(mContext, TEST_PARAMS, mManager))
100                 .thenReturn(mController);
101     }
102 
103     @Test
testMaybeStartProvisioning()104     public void testMaybeStartProvisioning() {
105         // GIVEN that provisioning is not currently running
106         // WHEN calling maybeStartProvisioning
107         mManager.maybeStartProvisioning(TEST_PARAMS);
108 
109         // THEN the factory should be called
110         verify(mFactory).createProvisioningController(mContext, TEST_PARAMS, mManager);
111 
112         // THEN the controller should be started on a Looper that is not the main thread
113         ArgumentCaptor<Looper> looperCaptor = ArgumentCaptor.forClass(Looper.class);
114         verify(mController).start(looperCaptor.capture());
115         assertTrue(looperCaptor.getValue() != Looper.getMainLooper());
116 
117         // WHEN trying to start provisioning again
118         mManager.maybeStartProvisioning(TEST_PARAMS);
119 
120         // THEN nothing should happen
121         verifyNoMoreInteractions(mFactory);
122         verifyNoMoreInteractions(mController);
123     }
124 
125     @Test
testCancelProvisioning()126     public void testCancelProvisioning() {
127         // GIVEN provisioning has been started
128         mManager.maybeStartProvisioning(TEST_PARAMS);
129 
130         // WHEN cancelling provisioning
131         mManager.cancelProvisioning();
132 
133         // THEN the controller should be cancelled
134         verify(mController).cancel();
135     }
136 
137     @FlakyTest(bugId = 131866915)
138     @Ignore
139     @Test
testListener_error()140     public void testListener_error() {
141         // GIVEN a listener is registered
142         mManager.registerListener(mCallback);
143         // WHEN some progress has occurred previously
144         mManager.error(R.string.cant_set_up_device, TEST_ERROR_ID, TEST_FACTORY_RESET_REQUIRED);
145         // THEN the listener should receive a callback
146         verify(mCallback).error(R.string.cant_set_up_device, TEST_ERROR_ID, TEST_FACTORY_RESET_REQUIRED);
147 
148         // WHEN the listener is unregistered and registered again
149         mManager.unregisterListener(mCallback);
150         mManager.registerListener(mCallback);
151         // THEN the listener should receive a callback again
152         verify(mCallback, times(2)).error(R.string.cant_set_up_device, TEST_ERROR_ID, TEST_FACTORY_RESET_REQUIRED);
153         verifyNoMoreInteractions(mCallback);
154     }
155 
156     @Test
testListener_cleanupCompleted()157     public void testListener_cleanupCompleted() {
158         // GIVEN provisioning has been started
159         mManager.maybeStartProvisioning(TEST_PARAMS);
160 
161         // GIVEN a listener is registered
162         mManager.registerListener(mCallback);
163         // WHEN some progress has occurred previously
164         mManager.cleanUpCompleted();
165         // THEN no callback is sent
166         verifyZeroInteractions(mCallback);
167     }
168 
169     @FlakyTest(bugId = 131866915)
170     @Ignore
171     @Test
testListener_preFinalizationCompleted()172     public void testListener_preFinalizationCompleted() throws InterruptedException {
173         // GIVEN provisioning has been started
174         mManager.maybeStartProvisioning(TEST_PARAMS);
175         // GIVEN a listener is registered
176         mManager.registerListener(mCallback);
177 
178         // prepare a semaphore to handle AsyncTask usage
179         final Semaphore semaphore = new Semaphore(0);
180         doAnswer((InvocationOnMock invocation) -> {
181             semaphore.release(1);
182             return null;
183         }).when(mCallback).preFinalizationCompleted();
184 
185         // WHEN some progress has occurred previously
186         mManager.preFinalizationCompleted();
187 
188 
189         assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS));
190 
191 
192         // THEN the listener should receive a callback
193         verify(mCallback).preFinalizationCompleted();
194 
195         // WHEN the listener is unregistered and registered again
196         mManager.unregisterListener(mCallback);
197         mManager.registerListener(mCallback);
198         // THEN the listener should receive a callback again
199         verify(mCallback).preFinalizationCompleted();
200         verifyNoMoreInteractions(mCallback);
201     }
202 }
203