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     private final static String testPackageName = "com.android.managedprovisioning";
73 
74     @Mock private Context mContext;
75     @Mock private ProvisioningControllerFactory mFactory;
76     @Mock private ProvisioningAnalyticsTracker mAnalyticsTracker;
77     @Mock private TimeLogger mTimeLogger;
78     @Mock private Handler mUiHandler;
79     @Mock private ProvisioningManagerCallback mCallback;
80     @Mock private AbstractProvisioningController mController;
81 
82     private ProvisioningManager mManager;
83 
84     @Before
setUp()85     public void setUp() {
86         MockitoAnnotations.initMocks(this);
87 
88         // Immediately execute any message that is sent onto the handler
89         when(mUiHandler.sendMessageAtTime(any(Message.class), anyLong())).thenAnswer(
90                 (InvocationOnMock invocation) -> {
91                     Message msg = (Message) invocation.getArguments()[0];
92                     msg.getCallback().run();
93                     return null;
94                 });
95         when(mContext.getPackageName()).thenReturn(testPackageName);
96         when(mContext.getApplicationContext()).thenReturn(mContext);
97         mManager = new ProvisioningManager(
98                 mContext,
99                 mFactory,
100                 mAnalyticsTracker,
101                 mTimeLogger);
102         when(mFactory.createProvisioningController(mContext, TEST_PARAMS, mManager))
103                 .thenReturn(mController);
104     }
105 
106     @Test
testMaybeStartProvisioning()107     public void testMaybeStartProvisioning() {
108         // GIVEN that provisioning is not currently running
109         // WHEN calling maybeStartProvisioning
110         mManager.maybeStartProvisioning(TEST_PARAMS);
111 
112         // THEN the factory should be called
113         verify(mFactory).createProvisioningController(mContext, TEST_PARAMS, mManager);
114 
115         // THEN the controller should be started on a Looper that is not the main thread
116         ArgumentCaptor<Looper> looperCaptor = ArgumentCaptor.forClass(Looper.class);
117         verify(mController).start(looperCaptor.capture());
118         assertTrue(looperCaptor.getValue() != Looper.getMainLooper());
119 
120         // WHEN trying to start provisioning again
121         mManager.maybeStartProvisioning(TEST_PARAMS);
122 
123         // THEN nothing should happen
124         verifyNoMoreInteractions(mFactory);
125         verifyNoMoreInteractions(mController);
126     }
127 
128     @Test
testCancelProvisioning()129     public void testCancelProvisioning() {
130         // GIVEN provisioning has been started
131         mManager.maybeStartProvisioning(TEST_PARAMS);
132 
133         // WHEN cancelling provisioning
134         mManager.cancelProvisioning();
135 
136         // THEN the controller should be cancelled
137         verify(mController).cancel();
138     }
139 
140     @FlakyTest(bugId = 131866915)
141     @Ignore
142     @Test
testListener_error()143     public void testListener_error() {
144         // GIVEN a listener is registered
145         mManager.registerListener(mCallback);
146         // WHEN some progress has occurred previously
147         mManager.error(R.string.cant_set_up_device, TEST_ERROR_ID, TEST_FACTORY_RESET_REQUIRED);
148         // THEN the listener should receive a callback
149         verify(mCallback).error(R.string.cant_set_up_device, TEST_ERROR_ID, TEST_FACTORY_RESET_REQUIRED);
150 
151         // WHEN the listener is unregistered and registered again
152         mManager.unregisterListener(mCallback);
153         mManager.registerListener(mCallback);
154         // THEN the listener should receive a callback again
155         verify(mCallback, times(2)).error(R.string.cant_set_up_device, TEST_ERROR_ID, TEST_FACTORY_RESET_REQUIRED);
156         verifyNoMoreInteractions(mCallback);
157     }
158 
159     @Test
testListener_cleanupCompleted()160     public void testListener_cleanupCompleted() {
161         // GIVEN provisioning has been started
162         mManager.maybeStartProvisioning(TEST_PARAMS);
163 
164         // GIVEN a listener is registered
165         mManager.registerListener(mCallback);
166         // WHEN some progress has occurred previously
167         mManager.cleanUpCompleted();
168         // THEN no callback is sent
169         verifyZeroInteractions(mCallback);
170     }
171 
172     @FlakyTest(bugId = 131866915)
173     @Ignore
174     @Test
testListener_preFinalizationCompleted()175     public void testListener_preFinalizationCompleted() throws InterruptedException {
176         // GIVEN provisioning has been started
177         mManager.maybeStartProvisioning(TEST_PARAMS);
178         // GIVEN a listener is registered
179         mManager.registerListener(mCallback);
180 
181         // prepare a semaphore to handle AsyncTask usage
182         final Semaphore semaphore = new Semaphore(0);
183         doAnswer((InvocationOnMock invocation) -> {
184             semaphore.release(1);
185             return null;
186         }).when(mCallback).preFinalizationCompleted();
187 
188         // WHEN some progress has occurred previously
189         mManager.preFinalizationCompleted();
190 
191 
192         assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS));
193 
194 
195         // THEN the listener should receive a callback
196         verify(mCallback).preFinalizationCompleted();
197 
198         // WHEN the listener is unregistered and registered again
199         mManager.unregisterListener(mCallback);
200         mManager.registerListener(mCallback);
201         // THEN the listener should receive a callback again
202         verify(mCallback).preFinalizationCompleted();
203         verifyNoMoreInteractions(mCallback);
204     }
205 }
206