1 /*
2  * Copyright (C) 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.task;
18 
19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
20 import static org.mockito.Matchers.eq;
21 import static org.mockito.Mockito.doAnswer;
22 import static org.mockito.Mockito.verify;
23 import static org.mockito.Mockito.verifyNoMoreInteractions;
24 import static org.mockito.Mockito.verifyZeroInteractions;
25 import static org.mockito.Mockito.when;
26 
27 import android.app.IActivityManager;
28 import android.content.BroadcastReceiver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.os.Handler;
32 import android.os.HandlerThread;
33 import android.os.RemoteException;
34 import android.os.UserHandle;
35 import android.test.AndroidTestCase;
36 import android.test.suitebuilder.annotation.SmallTest;
37 
38 import com.android.managedprovisioning.model.ProvisioningParams;
39 
40 import org.mockito.ArgumentCaptor;
41 import org.mockito.Mock;
42 import org.mockito.MockitoAnnotations;
43 import org.mockito.invocation.InvocationOnMock;
44 
45 import java.util.concurrent.CountDownLatch;
46 import java.util.concurrent.TimeUnit;
47 
48 /**
49  * Unit tests for {@link StartManagedProfileTask}.
50  */
51 public class StartManagedProfileTaskTest extends AndroidTestCase {
52     private static final int TEST_USER_ID = 123;
53     private static final String TEST_MDM_PACKAGE_NAME = "com.test.mdm";
54     private static final ProvisioningParams TEST_PARAMS = new ProvisioningParams.Builder()
55             .setDeviceAdminPackageName(TEST_MDM_PACKAGE_NAME)
56             .setProvisioningAction(ACTION_PROVISION_MANAGED_PROFILE)
57             .build();
58     private static final Intent UNLOCK_INTENT = new Intent(Intent.ACTION_USER_UNLOCKED)
59             .putExtra(Intent.EXTRA_USER_HANDLE, TEST_USER_ID);
60 
61     @Mock private IActivityManager mIActivityManager;
62     @Mock private Context mContext;
63     @Mock private AbstractProvisioningTask.Callback mCallback;
64     private ArgumentCaptor<BroadcastReceiver> mReceiverCaptor =
65             ArgumentCaptor.forClass(BroadcastReceiver.class);
66 
67     private StartManagedProfileTask mTask;
68     private HandlerThread mHandlerThread;
69     private final CountDownLatch mStartInBackgroundLatch = new CountDownLatch(1);
70     private final CountDownLatch mSuccessLatch = new CountDownLatch(1);
71 
setUp()72     public void setUp() {
73         // this is necessary for mockito to work
74         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
75         MockitoAnnotations.initMocks(this);
76 
77         mHandlerThread = new HandlerThread("Test thread");
78         mHandlerThread.start();
79 
80         mTask = new StartManagedProfileTask(mIActivityManager, mContext, TEST_PARAMS, mCallback);
81 
82         // register a countdown latch for the success callback
83         doAnswer((InvocationOnMock invocationOnMock) -> {
84                 mSuccessLatch.countDown();
85                 return null;
86             }).when(mCallback).onSuccess(mTask);
87     }
88 
tearDown()89     public void tearDown() {
90         mHandlerThread.quitSafely();
91     }
92 
93     @SmallTest
testSuccess()94     public void testSuccess() throws Exception {
95         // GIVEN that starting the user succeeds
96         doAnswer((InvocationOnMock invocationOnMock) -> {
97                 mStartInBackgroundLatch.countDown();
98                 return true;
99             }).when(mIActivityManager).startUserInBackground(TEST_USER_ID);
100 
101         // WHEN the task is run (on a handler thread to avoid deadlocks)
102         new Handler(mHandlerThread.getLooper()).post(() -> mTask.run(TEST_USER_ID));
103 
104         // THEN user unlock should have been called
105         assertTrue(mStartInBackgroundLatch.await(1, TimeUnit.SECONDS));
106 
107         // THEN an unlock receiver should be registered
108         verify(mContext).registerReceiverAsUser(
109                 mReceiverCaptor.capture(),
110                 eq(UserHandle.of(TEST_USER_ID)),
111                 eq(StartManagedProfileTask.UNLOCK_FILTER),
112                 eq(null), eq(null));
113 
114         // THEN the success callback should not have been called
115         verifyZeroInteractions(mCallback);
116 
117         // WHEN the unlock broadcast is sent
118         mReceiverCaptor.getValue().onReceive(mContext, UNLOCK_INTENT);
119 
120         // THEN the success callback should be called
121         assertTrue(mSuccessLatch.await(1, TimeUnit.SECONDS));
122         verify(mCallback).onSuccess(mTask);
123         verifyNoMoreInteractions(mCallback);
124 
125         verify(mContext).unregisterReceiver(mReceiverCaptor.getValue());
126     }
127 
128     @SmallTest
testError()129     public void testError() throws Exception {
130         // GIVEN that starting the user in background fails
131         when(mIActivityManager.startUserInBackground(TEST_USER_ID)).thenReturn(false);
132 
133         // WHEN the task is run
134         mTask.run(TEST_USER_ID);
135 
136         // THEN an unlock receiver should be registered
137         verify(mContext).registerReceiverAsUser(
138                 mReceiverCaptor.capture(),
139                 eq(UserHandle.of(TEST_USER_ID)),
140                 eq(StartManagedProfileTask.UNLOCK_FILTER),
141                 eq(null), eq(null));
142 
143         // THEN the error callback should have been called
144         verify(mCallback).onError(mTask, 0);
145         verifyNoMoreInteractions(mCallback);
146 
147         verify(mContext).unregisterReceiver(mReceiverCaptor.getValue());
148     }
149 
150     @SmallTest
testRemoteException()151     public void testRemoteException() throws Exception {
152         // GIVEN that starting the user in background throws a remote exception
153         when(mIActivityManager.startUserInBackground(TEST_USER_ID))
154                 .thenThrow(new RemoteException());
155 
156         // WHEN the task is run
157         mTask.run(TEST_USER_ID);
158 
159         // THEN an unlock receiver should be registered
160         verify(mContext).registerReceiverAsUser(
161                 mReceiverCaptor.capture(),
162                 eq(UserHandle.of(TEST_USER_ID)),
163                 eq(StartManagedProfileTask.UNLOCK_FILTER),
164                 eq(null), eq(null));
165 
166         // THEN the error callback should have been called
167         verify(mCallback).onError(mTask, 0);
168         verifyNoMoreInteractions(mCallback);
169 
170         verify(mContext).unregisterReceiver(mReceiverCaptor.getValue());
171     }
172 }
173