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.task.nonrequiredapps;
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.mockito.ArgumentMatchers.eq;
24 import static org.mockito.ArgumentMatchers.nullable;
25 import static org.mockito.Matchers.anyInt;
26 import static org.mockito.Mockito.never;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.app.admin.DevicePolicyManager;
31 import android.content.ComponentName;
32 import android.content.Context;
33 import android.content.pm.IPackageManager;
34 
35 import androidx.test.filters.SmallTest;
36 
37 import com.android.managedprovisioning.common.Utils;
38 import com.android.managedprovisioning.model.ProvisioningParams;
39 
40 import org.junit.Before;
41 import org.junit.Test;
42 import org.mockito.Mock;
43 import org.mockito.MockitoAnnotations;
44 
45 import java.util.Arrays;
46 import java.util.Collections;
47 import java.util.List;
48 import java.util.Set;
49 import java.util.stream.Collectors;
50 
51 /**
52  * Unit tests for {@link NonRequiredAppsLogic}.
53  */
54 @SmallTest
55 public class NonRequiredAppsLogicTest {
56     private static final String TEST_DPC_PACKAGE_NAME = "dpc.package.name";
57     private static final ComponentName TEST_MDM_COMPONENT_NAME = new ComponentName(
58             TEST_DPC_PACKAGE_NAME, "pc.package.name.DeviceAdmin");
59 
60     private static final int TEST_USER_ID = 123;
61     private static final List<String> APPS = Arrays.asList("app.a", "app.b", "app.c", "app.d",
62             "app.e", "app.f", "app.g", "app.h");
63     private static final List<Integer> SNAPSHOT_APPS = Arrays.asList(0, 1, 2, 3);
64     private static final List<Integer> SYSTEM_APPS = Arrays.asList(0, 1, 4, 5);
65     private static final List<Integer> BLACKLIST_APPS = Arrays.asList(0, 2, 4, 6);
66 
67     @Mock
68     private DevicePolicyManager mDevicePolicyManager;
69     @Mock
70     private IPackageManager mIPackageManager;
71     @Mock
72     private SystemAppsSnapshot mSnapshot;
73     @Mock
74     private Utils mUtils;
75     @Mock
76     private Context mContext;
77 
78     private ProvisioningParams.Builder mParamsBuilder;
79 
80     @Before
setUp()81     public void setUp() throws Exception {
82         MockitoAnnotations.initMocks(this);
83         mParamsBuilder = createParamsBuilder();
84         when(mUtils.findDeviceAdmin(nullable(String.class), nullable(ComponentName.class),
85                 eq(mContext), eq(TEST_USER_ID))).thenReturn(TEST_MDM_COMPONENT_NAME);
86     }
87 
88     @Test
testGetSystemAppsToRemove_NewLeave()89     public void testGetSystemAppsToRemove_NewLeave() throws Exception {
90         // GIVEN that a new profile is being created and that system apps should not be deleted
91         mParamsBuilder.setLeaveAllSystemAppsEnabled(true);
92         final NonRequiredAppsLogic logic = createLogic(true);
93         // GIVEN that a combination of apps is present
94         initializeApps();
95 
96         // THEN getSystemAppsToRemove should be empty
97         assertTrue(logic.getSystemAppsToRemove(TEST_USER_ID).isEmpty());
98     }
99 
100     @Test
testGetSystemAppsToRemove_NewDelete()101     public void testGetSystemAppsToRemove_NewDelete() throws Exception {
102         // GIVEN that a new profile is being created and that system apps should be deleted
103         mParamsBuilder.setLeaveAllSystemAppsEnabled(false);
104         final NonRequiredAppsLogic logic = createLogic(true);
105         // GIVEN that a combination of apps is present
106         initializeApps();
107 
108         // THEN getSystemAppsToRemove should return a non-empty list with the only app to removed
109         // being the one that is a current system app and non required
110         assertEquals(getAppsSet(Arrays.asList(0, 4)),
111                 logic.getSystemAppsToRemove(TEST_USER_ID));
112     }
113 
114     @Test
testGetSystemAppsToRemove_deviceAdminComponentIsNotGiven()115     public void testGetSystemAppsToRemove_deviceAdminComponentIsNotGiven() throws Exception {
116         // GIVEN that only device admin package name is given.
117         mParamsBuilder.setDeviceAdminComponentName(null);
118         mParamsBuilder.setDeviceAdminPackageName(TEST_DPC_PACKAGE_NAME);
119         // GIVEN that a new profile is being created and that system apps should be deleted
120         mParamsBuilder.setLeaveAllSystemAppsEnabled(false);
121         final NonRequiredAppsLogic logic = createLogic(true);
122         // GIVEN that a combination of apps is present
123         initializeApps();
124 
125         // THEN getSystemAppsToRemove should return a non-empty list with the only app to removed
126         // being the one that is a current system app and non required
127         assertEquals(getAppsSet(Arrays.asList(0, 4)),
128                 logic.getSystemAppsToRemove(TEST_USER_ID));
129     }
130 
131     @Test
testGetSystemAppsToRemove_OtaLeave()132     public void testGetSystemAppsToRemove_OtaLeave() throws Exception {
133         // GIVEN that an OTA occurs and that system apps should not be deleted (indicated by the
134         // fact that no snapshot currently exists)
135         mParamsBuilder.setLeaveAllSystemAppsEnabled(false);
136         final NonRequiredAppsLogic logic = createLogic(false);
137         // GIVEN that a combination of apps is present
138         initializeApps();
139         // GIVEN that no snapshot currently exists
140         when(mSnapshot.hasSnapshot(TEST_USER_ID)).thenReturn(false);
141 
142         // THEN getSystemAppsToRemove should be empty
143         assertTrue(logic.getSystemAppsToRemove(TEST_USER_ID).isEmpty());
144     }
145 
146     @Test
testGetSystemAppsToRemove_OtaDelete()147     public void testGetSystemAppsToRemove_OtaDelete() throws Exception {
148         // GIVEN that an OTA occurs and that system apps should be deleted (indicated by the fact
149         // that a snapshot currently exists)
150         mParamsBuilder.setLeaveAllSystemAppsEnabled(false);
151         final NonRequiredAppsLogic logic = createLogic(false);
152         // GIVEN that a combination of apps is present
153         initializeApps();
154 
155         // THEN getSystemAppsToRemove should return a non-empty list with the only app to removed
156         // being the one that is a current system app, non required and not in the last
157         // snapshot.
158         assertEquals(Collections.singleton(APPS.get(4)), logic.getSystemAppsToRemove(TEST_USER_ID));
159     }
160 
161     @Test
testMaybeTakeSnapshot_NewLeave()162     public void testMaybeTakeSnapshot_NewLeave() {
163         // GIVEN that a new profile is being created and that system apps should not be deleted
164         mParamsBuilder.setLeaveAllSystemAppsEnabled(true);
165         final NonRequiredAppsLogic logic = createLogic(true);
166 
167         // WHEN calling maybeTakeSystemAppsSnapshot
168         logic.maybeTakeSystemAppsSnapshot(TEST_USER_ID);
169 
170         // THEN no snapshot should be taken
171         verify(mSnapshot, never()).takeNewSnapshot(anyInt());
172     }
173 
174     @Test
testMaybeTakeSnapshot_NewDelete()175     public void testMaybeTakeSnapshot_NewDelete() {
176         // GIVEN that a new profile is being created and that system apps should be deleted
177         mParamsBuilder.setLeaveAllSystemAppsEnabled(false);
178         final NonRequiredAppsLogic logic = createLogic(true);
179 
180         // WHEN calling maybeTakeSystemAppsSnapshot
181         logic.maybeTakeSystemAppsSnapshot(TEST_USER_ID);
182 
183         // THEN a snapshot should be taken
184         verify(mSnapshot).takeNewSnapshot(TEST_USER_ID);
185     }
186 
187     @Test
testMaybeTakeSnapshot_OtaLeave()188     public void testMaybeTakeSnapshot_OtaLeave() {
189         // GIVEN that an OTA occurs and that system apps should not be deleted (indicated by the
190         // fact that no snapshot currently exists)
191         mParamsBuilder.setLeaveAllSystemAppsEnabled(false);
192         final NonRequiredAppsLogic logic = createLogic(false);
193         when(mSnapshot.hasSnapshot(TEST_USER_ID)).thenReturn(false);
194 
195         // WHEN calling maybeTakeSystemAppsSnapshot
196         logic.maybeTakeSystemAppsSnapshot(TEST_USER_ID);
197 
198         // THEN no snapshot should be taken
199         verify(mSnapshot, never()).takeNewSnapshot(anyInt());
200     }
201 
202     @Test
testMaybeTakeSnapshot_OtaDelete()203     public void testMaybeTakeSnapshot_OtaDelete() {
204         // GIVEN that an OTA occurs and that system apps should be deleted (indicated by the fact
205         // that a snapshot currently exists)
206         mParamsBuilder.setLeaveAllSystemAppsEnabled(false);
207         final NonRequiredAppsLogic logic = createLogic(false);
208         when(mSnapshot.hasSnapshot(TEST_USER_ID)).thenReturn(true);
209 
210         // WHEN calling maybeTakeSystemAppsSnapshot
211         logic.maybeTakeSystemAppsSnapshot(TEST_USER_ID);
212 
213         // THEN a snapshot should be taken
214         verify(mSnapshot).takeNewSnapshot(TEST_USER_ID);
215     }
216 
initializeApps()217     private void initializeApps() throws Exception {
218         setCurrentSystemApps(getAppsSet(SYSTEM_APPS));
219         setLastSnapshot(getAppsSet(SNAPSHOT_APPS));
220         setNonRequiredApps(getAppsSet(BLACKLIST_APPS));
221     }
222 
setCurrentSystemApps(Set<String> set)223     private void setCurrentSystemApps(Set<String> set) {
224         when(mUtils.getCurrentSystemApps(mIPackageManager, TEST_USER_ID)).thenReturn(set);
225     }
226 
setLastSnapshot(Set<String> set)227     private void setLastSnapshot(Set<String> set) {
228         when(mSnapshot.getSnapshot(TEST_USER_ID)).thenReturn(set);
229         when(mSnapshot.hasSnapshot(TEST_USER_ID)).thenReturn(true);
230     }
231 
setNonRequiredApps(Set<String> set)232     private void setNonRequiredApps(Set<String> set) {
233         when(mDevicePolicyManager.getDisallowedSystemApps(TEST_MDM_COMPONENT_NAME, TEST_USER_ID,
234                 ACTION_PROVISION_MANAGED_DEVICE)).thenReturn(set);
235     }
236 
getAppsSet(List<Integer> ids)237     private Set<String> getAppsSet(List<Integer> ids) {
238         return ids.stream().map(APPS::get).collect(Collectors.toSet());
239     }
240 
createLogic(boolean newProfile)241     private NonRequiredAppsLogic createLogic(boolean newProfile) {
242         return new NonRequiredAppsLogic(
243                 mContext,
244                 mIPackageManager,
245                 mDevicePolicyManager,
246                 newProfile,
247                 mParamsBuilder.build(),
248                 mSnapshot,
249                 mUtils);
250     }
251 
createParamsBuilder()252     private ProvisioningParams.Builder createParamsBuilder() {
253         return new ProvisioningParams.Builder()
254                 .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE)
255                 .setDeviceAdminComponentName(TEST_MDM_COMPONENT_NAME);
256     }
257 }
258