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