1 /* 2 * Copyright (C) 2015 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_DEVICE; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assert.fail; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.verifyNoMoreInteractions; 27 import static org.mockito.Mockito.when; 28 29 import android.content.Context; 30 import android.content.pm.IPackageDeleteObserver; 31 import android.content.pm.PackageInfo; 32 import android.content.pm.PackageManager; 33 import android.os.RemoteException; 34 import android.test.mock.MockPackageManager; 35 36 import androidx.test.InstrumentationRegistry; 37 import androidx.test.filters.SmallTest; 38 39 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker; 40 import com.android.managedprovisioning.model.ProvisioningParams; 41 import com.android.managedprovisioning.task.nonrequiredapps.NonRequiredAppsLogic; 42 43 import org.junit.Before; 44 import org.junit.Test; 45 import org.mockito.Mock; 46 import org.mockito.MockitoAnnotations; 47 48 import java.util.Arrays; 49 import java.util.Collections; 50 import java.util.HashSet; 51 import java.util.Set; 52 53 @SmallTest 54 public class DeleteNonRequiredAppsTaskTest { 55 private static final String TEST_DPC_PACKAGE_NAME = "dpc.package.name"; 56 private static final int TEST_USER_ID = 123; 57 private static final ProvisioningParams TEST_PARAMS = new ProvisioningParams.Builder() 58 .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE) 59 .setDeviceAdminPackageName(TEST_DPC_PACKAGE_NAME) 60 .build(); 61 62 private @Mock AbstractProvisioningTask.Callback mCallback; 63 private @Mock Context mTestContext; 64 private @Mock NonRequiredAppsLogic mLogic; 65 66 private FakePackageManager mPackageManager; 67 private Set<String> mDeletedApps; 68 private DeleteNonRequiredAppsTask mTask; 69 70 @Before setUp()71 public void setUp() throws Exception { 72 MockitoAnnotations.initMocks(this); 73 74 mPackageManager = new FakePackageManager(); 75 76 when(mTestContext.getPackageManager()).thenReturn(mPackageManager); 77 when(mTestContext.getFilesDir()).thenReturn(InstrumentationRegistry.getTargetContext() 78 .getFilesDir()); 79 80 mDeletedApps = new HashSet<>(); 81 82 mTask = new DeleteNonRequiredAppsTask(mTestContext, TEST_PARAMS, mCallback, mLogic, 83 mock(ProvisioningAnalyticsTracker.class)); 84 } 85 86 @Test testNoAppsToDelete()87 public void testNoAppsToDelete() { 88 // GIVEN that no apps should be deleted 89 when(mLogic.getSystemAppsToRemove(TEST_USER_ID)).thenReturn(Collections.emptySet()); 90 mPackageManager.setInstalledApps(setFromArray("app.a")); 91 92 // WHEN running the task 93 mTask.run(TEST_USER_ID); 94 95 // THEN maybe take snapshot should have been called 96 verify(mLogic).maybeTakeSystemAppsSnapshot(TEST_USER_ID); 97 98 // THEN success should be called 99 verify(mCallback).onSuccess(mTask); 100 verifyNoMoreInteractions(mCallback); 101 102 // THEN no apps should have been deleted 103 assertDeletedApps(); 104 } 105 106 @Test testAppsToDelete()107 public void testAppsToDelete() { 108 // GIVEN that some apps should be deleted 109 when(mLogic.getSystemAppsToRemove(TEST_USER_ID)) 110 .thenReturn(setFromArray("app.a", "app.b")); 111 // GIVEN that only app a is currently installed 112 mPackageManager.setInstalledApps(setFromArray("app.a", "app.c")); 113 114 // WHEN running the task 115 mTask.run(TEST_USER_ID); 116 117 // THEN maybe take snapshot should have been called 118 verify(mLogic).maybeTakeSystemAppsSnapshot(TEST_USER_ID); 119 120 // THEN success should be called 121 verify(mCallback).onSuccess(mTask); 122 verifyNoMoreInteractions(mCallback); 123 124 // THEN those apps should have been deleted 125 assertDeletedApps("app.a"); 126 } 127 128 @Test testAllAppsAlreadyDeleted()129 public void testAllAppsAlreadyDeleted() { 130 // GIVEN that some apps should be deleted 131 when(mLogic.getSystemAppsToRemove(TEST_USER_ID)) 132 .thenReturn(setFromArray("app.a", "app.b")); 133 134 // WHEN running the task 135 mTask.run(TEST_USER_ID); 136 137 // THEN maybe take snapshot should have been called 138 verify(mLogic).maybeTakeSystemAppsSnapshot(TEST_USER_ID); 139 140 // THEN success should be called 141 verify(mCallback).onSuccess(mTask); 142 verifyNoMoreInteractions(mCallback); 143 144 // THEN those apps should have been deleted 145 assertDeletedApps(); 146 } 147 148 @Test testDeletionFailed()149 public void testDeletionFailed() { 150 // GIVEN that one app should be deleted 151 when(mLogic.getSystemAppsToRemove(TEST_USER_ID)) 152 .thenReturn(setFromArray("app.a")); 153 mPackageManager.setInstalledApps(setFromArray("app.a")); 154 155 // GIVEN that deletion fails 156 mPackageManager.setDeletionSucceeds(false); 157 158 // WHEN running the task 159 mTask.run(TEST_USER_ID); 160 161 // THEN maybe take snapshot should have been called 162 verify(mLogic).maybeTakeSystemAppsSnapshot(TEST_USER_ID); 163 164 // THEN error should be returned 165 verify(mCallback).onError(mTask, 0, /* errorMessage= */ null); 166 verifyNoMoreInteractions(mCallback); 167 } 168 setFromArray(T... array)169 private <T> Set<T> setFromArray(T... array) { 170 if (array == null) { 171 return null; 172 } 173 return new HashSet<>(Arrays.asList(array)); 174 } 175 assertDeletedApps(String... appArray)176 private void assertDeletedApps(String... appArray) { 177 assertEquals(setFromArray(appArray), mDeletedApps); 178 } 179 180 181 class FakePackageManager extends MockPackageManager { 182 private boolean mDeletionSucceeds = true; 183 private Set<String> mInstalledApps = new HashSet<>(); 184 setDeletionSucceeds(boolean deletionSucceeds)185 void setDeletionSucceeds(boolean deletionSucceeds) { 186 mDeletionSucceeds = deletionSucceeds; 187 } 188 setInstalledApps(Set<String> set)189 void setInstalledApps(Set<String> set) { 190 mInstalledApps = set; 191 } 192 193 @Override deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags, int userId)194 public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, 195 int flags, int userId) { 196 if (mDeletionSucceeds) { 197 mDeletedApps.add(packageName); 198 } 199 assertTrue((flags & PackageManager.DELETE_SYSTEM_APP) != 0); 200 assertEquals(TEST_USER_ID, userId); 201 202 int resultCode; 203 if (mDeletionSucceeds) { 204 resultCode = PackageManager.DELETE_SUCCEEDED; 205 } else { 206 resultCode = PackageManager.DELETE_FAILED_INTERNAL_ERROR; 207 } 208 assertTrue(mInstalledApps.remove(packageName)); 209 210 try { 211 observer.packageDeleted(packageName, resultCode); 212 } catch (RemoteException e) { 213 fail(e.toString()); 214 } 215 } 216 217 @Override getPackageInfoAsUser(String pkg, int flag, int userId)218 public PackageInfo getPackageInfoAsUser(String pkg, int flag, int userId) 219 throws NameNotFoundException { 220 if (mInstalledApps.contains(pkg) && userId == TEST_USER_ID) { 221 return new PackageInfo(); 222 } 223 throw new NameNotFoundException(); 224 } 225 } 226 } 227