AppCollectorTest.java revision c7d9de59bfa083472a5c8fcfc02c2363b33e204f
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 17package com.android.server.storage; 18 19import android.content.pm.UserInfo; 20import android.content.Context; 21import android.content.pm.ApplicationInfo; 22import android.content.pm.IPackageStatsObserver; 23import android.content.pm.PackageManager; 24import android.content.pm.PackageStats; 25import android.os.UserManager; 26import android.os.storage.VolumeInfo; 27import android.test.AndroidTestCase; 28import org.junit.Before; 29import org.junit.Test; 30import org.junit.runner.RunWith; 31import org.junit.runners.JUnit4; 32import org.mockito.Mock; 33import org.mockito.Mockito; 34import org.mockito.MockitoAnnotations; 35import org.mockito.invocation.InvocationOnMock; 36import org.mockito.stubbing.Answer; 37 38import java.util.ArrayList; 39import java.util.List; 40import java.util.concurrent.CountDownLatch; 41import java.util.concurrent.TimeUnit; 42 43import static com.google.common.truth.Truth.assertThat; 44import static org.mockito.Matchers.any; 45import static org.mockito.Matchers.anyInt; 46import static org.mockito.Matchers.eq; 47import static org.mockito.Mockito.doAnswer; 48import static org.mockito.Mockito.when; 49 50@RunWith(JUnit4.class) 51public class AppCollectorTest extends AndroidTestCase { 52 private static final long TIMEOUT = TimeUnit.MINUTES.toMillis(1); 53 @Mock private Context mContext; 54 @Mock private PackageManager mPm; 55 @Mock private UserManager mUm; 56 private List<ApplicationInfo> mApps; 57 private List<UserInfo> mUsers; 58 59 @Before 60 public void setUp() throws Exception { 61 super.setUp(); 62 MockitoAnnotations.initMocks(this); 63 mApps = new ArrayList<>(); 64 when(mContext.getPackageManager()).thenReturn(mPm); 65 when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUm); 66 67 // Set up the app list. 68 when(mPm.getInstalledApplications(anyInt())).thenReturn(mApps); 69 70 // Set up the user list with a single user (0). 71 mUsers = new ArrayList<>(); 72 mUsers.add(new UserInfo(0, "", 0)); 73 when(mUm.getUsers()).thenReturn(mUsers); 74 } 75 76 @Test 77 public void testNoApps() throws Exception { 78 VolumeInfo volume = new VolumeInfo("testuuid", 0, null, null); 79 volume.fsUuid = "testuuid"; 80 AppCollector collector = new AppCollector(mContext, volume); 81 82 assertThat(collector.getPackageStats(TIMEOUT)).isEmpty(); 83 } 84 85 @Test 86 public void testAppOnExternalVolume() throws Exception { 87 addApplication("com.test.app", "differentuuid"); 88 VolumeInfo volume = new VolumeInfo("testuuid", 0, null, null); 89 volume.fsUuid = "testuuid"; 90 AppCollector collector = new AppCollector(mContext, volume); 91 92 assertThat(collector.getPackageStats(TIMEOUT)).isEmpty(); 93 } 94 95 @Test 96 public void testOneValidApp() throws Exception { 97 addApplication("com.test.app", "testuuid"); 98 VolumeInfo volume = new VolumeInfo("testuuid", 0, null, null); 99 volume.fsUuid = "testuuid"; 100 AppCollector collector = new AppCollector(mContext, volume); 101 PackageStats stats = new PackageStats("com.test.app"); 102 103 // Set up this to handle the asynchronous call to the PackageManager. This returns the 104 // package info for the specified package. 105 doAnswer(new Answer<Void>() { 106 @Override 107 public Void answer(InvocationOnMock invocation) { 108 try { 109 ((IPackageStatsObserver.Stub) invocation.getArguments()[2]) 110 .onGetStatsCompleted(stats, true); 111 } catch (Exception e) { 112 // We fail instead of just letting the exception fly because throwing 113 // out of the callback like this on the background thread causes the test 114 // runner to crash, rather than reporting the failure. 115 fail(); 116 } 117 return null; 118 } 119 }).when(mPm).getPackageSizeInfoAsUser(eq("com.test.app"), eq(0), any()); 120 121 122 // Because getPackageStats is a blocking call, we block execution of the test until the 123 // call finishes. In order to finish the call, we need the above answer to execute. 124 List<PackageStats> myStats = new ArrayList<>(); 125 CountDownLatch latch = new CountDownLatch(1); 126 new Thread(new Runnable() { 127 @Override 128 public void run() { 129 myStats.addAll(collector.getPackageStats(TIMEOUT)); 130 latch.countDown(); 131 } 132 }).start(); 133 latch.await(); 134 135 assertThat(myStats).containsExactly(stats); 136 } 137 138 @Test 139 public void testMultipleUsersOneApp() throws Exception { 140 addApplication("com.test.app", "testuuid"); 141 ApplicationInfo otherUsersApp = new ApplicationInfo(); 142 otherUsersApp.packageName = "com.test.app"; 143 otherUsersApp.volumeUuid = "testuuid"; 144 otherUsersApp.uid = 1; 145 mUsers.add(new UserInfo(1, "", 0)); 146 147 VolumeInfo volume = new VolumeInfo("testuuid", 0, null, null); 148 volume.fsUuid = "testuuid"; 149 AppCollector collector = new AppCollector(mContext, volume); 150 PackageStats stats = new PackageStats("com.test.app"); 151 PackageStats otherStats = new PackageStats("com.test.app"); 152 otherStats.userHandle = 1; 153 154 // Set up this to handle the asynchronous call to the PackageManager. This returns the 155 // package info for our packages. 156 doAnswer(new Answer<Void>() { 157 @Override 158 public Void answer(InvocationOnMock invocation) { 159 try { 160 ((IPackageStatsObserver.Stub) invocation.getArguments()[2]) 161 .onGetStatsCompleted(stats, true); 162 163 // Now callback for the other uid. 164 ((IPackageStatsObserver.Stub) invocation.getArguments()[2]) 165 .onGetStatsCompleted(otherStats, true); 166 } catch (Exception e) { 167 // We fail instead of just letting the exception fly because throwing 168 // out of the callback like this on the background thread causes the test 169 // runner to crash, rather than reporting the failure. 170 fail(); 171 } 172 return null; 173 } 174 }).when(mPm).getPackageSizeInfoAsUser(eq("com.test.app"), eq(0), any()); 175 176 177 // Because getPackageStats is a blocking call, we block execution of the test until the 178 // call finishes. In order to finish the call, we need the above answer to execute. 179 List<PackageStats> myStats = new ArrayList<>(); 180 CountDownLatch latch = new CountDownLatch(1); 181 new Thread(new Runnable() { 182 @Override 183 public void run() { 184 myStats.addAll(collector.getPackageStats(TIMEOUT)); 185 latch.countDown(); 186 } 187 }).start(); 188 latch.await(); 189 190 // This should 191 assertThat(myStats).containsAllOf(stats, otherStats); 192 } 193 194 private void addApplication(String packageName, String uuid) { 195 ApplicationInfo info = new ApplicationInfo(); 196 info.packageName = packageName; 197 info.volumeUuid = uuid; 198 mApps.add(info); 199 } 200 201} 202