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.finalization; 18 19 import static android.app.admin.DeviceAdminReceiver.ACTION_PROFILE_PROVISIONING_COMPLETE; 20 import static android.app.admin.DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED; 21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE; 22 23 import static org.mockito.ArgumentMatchers.eq; 24 import static org.mockito.Matchers.any; 25 import static org.mockito.Mockito.doAnswer; 26 import static org.mockito.Mockito.never; 27 import static org.mockito.Mockito.verify; 28 29 import android.accounts.Account; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.os.UserHandle; 33 import android.test.AndroidTestCase; 34 import android.test.suitebuilder.annotation.SmallTest; 35 36 import com.android.managedprovisioning.common.RemoveAccountListener; 37 import com.android.managedprovisioning.common.Utils; 38 39 import org.mockito.ArgumentCaptor; 40 import org.mockito.Mock; 41 import org.mockito.MockitoAnnotations; 42 import org.mockito.invocation.InvocationOnMock; 43 44 import java.util.concurrent.Semaphore; 45 import java.util.concurrent.TimeUnit; 46 import java.util.function.Function; 47 48 /** 49 * Unit tests for {@link DpcReceivedSuccessReceiver}. 50 */ 51 public class DpcReceivedSuccessReceiverTest extends AndroidTestCase { 52 private static final int SEND_BROADCAST_TIMEOUT_SECONDS = 1; 53 private static final String TEST_MDM_PACKAGE_NAME = "mdm.package.name"; 54 private static final Account TEST_ACCOUNT = new Account("test@account.com", "account.type"); 55 private static final Intent TEST_INTENT = new Intent(ACTION_PROFILE_PROVISIONING_COMPLETE); 56 private static final UserHandle MANAGED_PROFILE_USER_HANDLE = UserHandle.of(123); 57 58 @Mock private Context mContext; 59 @Mock private Utils mUtils; 60 61 @Override setUp()62 public void setUp() { 63 // this is necessary for mockito to work 64 System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); 65 MockitoAnnotations.initMocks(this); 66 } 67 68 @SmallTest testNoAccountMigration()69 public void testNoAccountMigration() { 70 // GIVEN that no account migration occurred during provisioning 71 final DpcReceivedSuccessReceiver receiver = new DpcReceivedSuccessReceiver( 72 /* migratedAccount */ null, /* keepAccountMigrated */ false, 73 MANAGED_PROFILE_USER_HANDLE, TEST_MDM_PACKAGE_NAME, mUtils, /* callback */ null, 74 /* isAdminIntegratedFlow */ false); 75 76 // WHEN the profile provisioning complete intent was received by the DPC 77 receiver.onReceive(mContext, TEST_INTENT); 78 79 // THEN an intent should be sent to the primary user 80 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 81 verify(mContext).sendBroadcast(intentCaptor.capture()); 82 83 // THEN the broadcast action is ACTION_MANAGED_PROFILE_PROVISIONED 84 assertEquals(ACTION_MANAGED_PROFILE_PROVISIONED, intentCaptor.getValue().getAction()); 85 86 // THEN the receiver package is the DPC 87 assertEquals(TEST_MDM_PACKAGE_NAME, intentCaptor.getValue().getPackage()); 88 89 // THEN the extra user handle should be of managed profile 90 assertEquals(MANAGED_PROFILE_USER_HANDLE, 91 intentCaptor.getValue().getExtra(Intent.EXTRA_USER)); 92 } 93 94 @SmallTest testAccountMigration()95 public void testAccountMigration() throws Exception { 96 // GIVEN that account migration occurred during provisioning 97 final DpcReceivedSuccessReceiver receiver = new DpcReceivedSuccessReceiver(TEST_ACCOUNT, 98 /* keepAccountMigrated */ false, MANAGED_PROFILE_USER_HANDLE, TEST_MDM_PACKAGE_NAME, 99 mUtils, /* callback */ null, /* isAdminIntegratedFlow */ false); 100 101 // WHEN receiver.onReceive is called 102 invokeOnReceiveAndVerifyIntent(receiver, /* postOnReceive */ aVoid -> { 103 // THEN the account should have been removed from the primary user 104 ArgumentCaptor<RemoveAccountListener> captor = 105 ArgumentCaptor.forClass(RemoveAccountListener.class); 106 verify(mUtils).removeAccountAsync(eq(mContext), eq(TEST_ACCOUNT), captor.capture()); 107 captor.getValue().onAccountRemoved(); 108 return null; 109 }); 110 111 } 112 113 @SmallTest testAccountCopy()114 public void testAccountCopy() throws Exception { 115 // GIVEN that account copy occurred during provisioning 116 final DpcReceivedSuccessReceiver receiver = new DpcReceivedSuccessReceiver(TEST_ACCOUNT, 117 /* keepAccountMigrated */ true, MANAGED_PROFILE_USER_HANDLE, TEST_MDM_PACKAGE_NAME, 118 mUtils, /* callback */ null, /* isAdminIntegratedFlow */ false); 119 120 // WHEN receiver.onReceive is called 121 invokeOnReceiveAndVerifyIntent(receiver, /* postOnReceive */ aVoid -> { 122 // THEN the account is not removed from the primary user 123 verify(mUtils, never()).removeAccountAsync(eq(mContext), eq(TEST_ACCOUNT), any()); 124 return null; 125 }); 126 } 127 invokeOnReceiveAndVerifyIntent(final DpcReceivedSuccessReceiver receiver, Function<Void, Void> postOnReceive)128 private void invokeOnReceiveAndVerifyIntent(final DpcReceivedSuccessReceiver receiver, 129 Function<Void, Void> postOnReceive) throws InterruptedException { 130 // prepare a semaphore to handle AsyncTask usage 131 final Semaphore semaphore = new Semaphore(0); 132 doAnswer((InvocationOnMock invocation) -> { 133 semaphore.release(1); 134 return null; 135 }).when(mContext).sendBroadcast(any(Intent.class)); 136 137 // WHEN the profile provisioning complete intent was received by the DPC 138 receiver.onReceive(mContext, TEST_INTENT); 139 140 postOnReceive.apply(null); 141 142 assertTrue(semaphore.tryAcquire(SEND_BROADCAST_TIMEOUT_SECONDS, TimeUnit.SECONDS)); 143 144 // THEN an intent should be sent to the primary user 145 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 146 verify(mContext).sendBroadcast(intentCaptor.capture()); 147 148 // THEN the broadcast action is ACTION_MANAGED_PROFILE_PROVISIONED 149 assertEquals(ACTION_MANAGED_PROFILE_PROVISIONED, intentCaptor.getValue().getAction()); 150 151 // THEN the receiver package is the DPC 152 assertEquals(TEST_MDM_PACKAGE_NAME, intentCaptor.getValue().getPackage()); 153 154 // THEN the extra user handle should be of managed profile 155 assertEquals(MANAGED_PROFILE_USER_HANDLE, 156 intentCaptor.getValue().getExtra(Intent.EXTRA_USER)); 157 158 // THEN the account was added to the broadcast 159 assertEquals(TEST_ACCOUNT, intentCaptor.getValue().getParcelableExtra( 160 EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE)); 161 } 162 } 163