/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.pm; import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.InstallException; import com.android.ddmlib.Log; import com.android.ddmlib.ShellCommandUnresponsiveException; import com.android.ddmlib.TimeoutException; import com.android.hosttest.DeviceTestCase; import com.android.hosttest.DeviceTestSuite; import java.io.File; import java.io.IOException; import junit.framework.Test; /** * Set of tests that verify host side stress scenarios (large apps, multiple upgrades, etc.) */ public class PackageManagerStressHostTests extends DeviceTestCase { private static final String LOG_TAG = "PackageManagerStressHostTests"; private PackageManagerHostTestUtils mPMHostUtils = null; // Path to the app repository and various subdirectories of it // Note: These stress tests require large apks that cannot be checked into the tree. // These variables define static locations that point to existing APKs (not built from // the tree) which can be used by the the stress tests in this file. private static final String LARGE_APPS_DIRECTORY_NAME = "largeApps"; private static final String MISC_APPS_DIRECTORY_NAME = "miscApps"; private static final String VERSIONED_APPS_DIRECTORY_NAME = "versionedApps"; private static final String MANY_APPS_DIRECTORY_NAME = "manyApps"; // Note: An external environment variable "ANDROID_TEST_APP_REPOSITORY" must be set // which points to the root location of the app respository. private static String AppRepositoryPath = null; // Large apps (>1mb) - filenames and their corresponding package names: private static enum APK { FILENAME, PACKAGENAME; } private static final String[][] LARGE_APPS = { {"External1mb.apk", "com.appsonsd.mytests.External1mb"}, {"External2mb.apk", "com.appsonsd.mytests.External2mb"}, {"External3mb.apk", "com.appsonsd.mytests.External3mb"}, {"External4mb.apk", "com.appsonsd.mytests.External4mb"}, {"External5mb.apk", "com.appsonsd.mytests.External5mb"}, {"External6mb.apk", "com.appsonsd.mytests.External6mb"}, {"External7mb.apk", "com.appsonsd.mytests.External7mb"}, {"External8mb.apk", "com.appsonsd.mytests.External8mb"}, {"External9mb.apk", "com.appsonsd.mytests.External9mb"}, {"External10mb.apk", "com.appsonsd.mytests.External10mb"}, {"External16mb.apk", "com.appsonsd.mytests.External16mb"}, {"External28mb.apk", "com.appsonsd.mytests.External28mb"}, {"External34mb.apk", "com.appsonsd.mytests.External34mb"}, {"External46mb.apk", "com.appsonsd.mytests.External46mb"}, {"External58mb.apk", "com.appsonsd.mytests.External58mb"}, {"External65mb.apk", "com.appsonsd.mytests.External65mb"}, {"External72mb.apk", "com.appsonsd.mytests.External72mb"}, {"External79mb.apk", "com.appsonsd.mytests.External79mb"}, {"External86mb.apk", "com.appsonsd.mytests.External86mb"}, {"External93mb.apk", "com.appsonsd.mytests.External93mb"}}; // Various test files and their corresponding package names private static final String AUTO_LOC_APK = "Auto241kb.apk"; private static final String AUTO_LOC_PKG = "com.appsonsd.mytests.Auto241kb"; private static final String INTERNAL_LOC_APK = "Internal781kb.apk"; private static final String INTERNAL_LOC_PKG = "com.appsonsd.mytests.Internal781kb"; private static final String EXTERNAL_LOC_APK = "External931kb.apk"; private static final String EXTERNAL_LOC_PKG = "com.appsonsd.mytests.External931kb"; private static final String NO_LOC_APK = "Internal751kb_EclairSDK.apk"; private static final String NO_LOC_PKG = "com.appsonsd.mytests.Internal751kb_EclairSDK"; // Versioned test apps private static final String VERSIONED_APPS_FILENAME_PREFIX = "External455kb_v"; private static final String VERSIONED_APPS_PKG = "com.appsonsd.mytests.External455kb"; private static final int VERSIONED_APPS_START_VERSION = 1; // inclusive private static final int VERSIONED_APPS_END_VERSION = 250; // inclusive // Large number of app installs // @TODO: increase the max when we can install more apps private static final int MANY_APPS_START = 1; private static final int MANY_APPS_END = 100; private static final String MANY_APPS_PKG_PREFIX = "com.appsonsd.mytests.External49kb_"; private static final String MANY_APPS_APK_PREFIX = "External49kb_"; public static Test suite() { return new DeviceTestSuite(PackageManagerStressHostTests.class); } @Override protected void setUp() throws Exception { super.setUp(); // setup the PackageManager host tests utilities class, and get various paths we'll need... mPMHostUtils = new PackageManagerHostTestUtils(getDevice()); AppRepositoryPath = System.getenv("ANDROID_TEST_APP_REPOSITORY"); assertNotNull(AppRepositoryPath); // Make sure path ends with a separator if (!AppRepositoryPath.endsWith(File.separator)) { AppRepositoryPath += File.separator; } } /** * Get the absolute file system location of repository test app with given filename * @param fileName the file name of the test app apk * @return {@link String} of absolute file path */ private String getRepositoryTestAppFilePath(String fileDirectory, String fileName) { return String.format("%s%s%s%s", AppRepositoryPath, fileDirectory, File.separator, fileName); } /** * Get the absolute file system location of test app with given filename * @param fileName the file name of the test app apk * @return {@link String} of absolute file path */ public String getTestAppFilePath(String fileName) { return String.format("%s%s%s", getTestAppPath(), File.separator, fileName); } /** * Stress test to verify that we can update an app multiple times on the SD card. * <p/> * Assumes adb is running as root in device under test. */ public void testUpdateAppManyTimesOnSD() throws IOException, InterruptedException, InstallException, TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException { Log.i(LOG_TAG, "Test updating an app on SD numerous times"); // cleanup test app just in case it already exists mPMHostUtils.uninstallApp(VERSIONED_APPS_PKG); // grep for package to make sure its not installed assertFalse(mPMHostUtils.doesPackageExist(VERSIONED_APPS_PKG)); try { for (int i = VERSIONED_APPS_START_VERSION; i <= VERSIONED_APPS_END_VERSION; ++i) { String currentApkName = String.format("%s%d.apk", VERSIONED_APPS_FILENAME_PREFIX, i); Log.i(LOG_TAG, "Installing app " + currentApkName); mPMHostUtils.installFile(getRepositoryTestAppFilePath(VERSIONED_APPS_DIRECTORY_NAME, currentApkName), true); mPMHostUtils.waitForPackageManager(); assertTrue(mPMHostUtils.doesAppExistOnSDCard(VERSIONED_APPS_PKG)); assertTrue(mPMHostUtils.doesPackageExist(VERSIONED_APPS_PKG)); } } finally { // cleanup test app mPMHostUtils.uninstallApp(VERSIONED_APPS_PKG); // grep for package to make sure its not installed assertFalse(mPMHostUtils.doesPackageExist(VERSIONED_APPS_PKG)); } } /** * Stress test to verify that an app can be installed, uninstalled, and * reinstalled on SD many times. * <p/> * Assumes adb is running as root in device under test. */ public void testUninstallReinstallAppOnSDManyTimes() throws IOException, InterruptedException, InstallException, TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException { Log.i(LOG_TAG, "Test updating an app on the SD card stays on the SD card"); // cleanup test app just in case it was already exists mPMHostUtils.uninstallApp(EXTERNAL_LOC_PKG); // grep for package to make sure its not installed assertFalse(mPMHostUtils.doesPackageExist(EXTERNAL_LOC_PKG)); for (int i = 0; i <= 500; ++i) { Log.i(LOG_TAG, "Installing app"); try { // install the app mPMHostUtils.installFile(getRepositoryTestAppFilePath(MISC_APPS_DIRECTORY_NAME, EXTERNAL_LOC_APK), false); mPMHostUtils.waitForPackageManager(); assertTrue(mPMHostUtils.doesAppExistOnSDCard(EXTERNAL_LOC_PKG)); assertTrue(mPMHostUtils.doesPackageExist(EXTERNAL_LOC_PKG)); } finally { // now uninstall the app Log.i(LOG_TAG, "Uninstalling app"); mPMHostUtils.uninstallApp(EXTERNAL_LOC_PKG); mPMHostUtils.waitForPackageManager(); assertFalse(mPMHostUtils.doesPackageExist(EXTERNAL_LOC_PKG)); } } } /** * Stress test to verify that we can install, 20 large apps (>1mb each) * <p/> * Assumes adb is running as root in device under test. */ public void testInstallManyLargeAppsOnSD() throws IOException, InterruptedException, InstallException, TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException { Log.i(LOG_TAG, "Test installing 20 large apps onto the sd card"); try { // Install all the large apps for (int i=0; i < LARGE_APPS.length; ++i) { String apkName = LARGE_APPS[i][APK.FILENAME.ordinal()]; String pkgName = LARGE_APPS[i][APK.PACKAGENAME.ordinal()]; // cleanup test app just in case it already exists mPMHostUtils.uninstallApp(pkgName); // grep for package to make sure its not installed assertFalse(mPMHostUtils.doesPackageExist(pkgName)); Log.i(LOG_TAG, "Installing app " + apkName); // install the app mPMHostUtils.installFile(getRepositoryTestAppFilePath(LARGE_APPS_DIRECTORY_NAME, apkName), false); mPMHostUtils.waitForPackageManager(); assertTrue(mPMHostUtils.doesAppExistOnSDCard(pkgName)); assertTrue(mPMHostUtils.doesPackageExist(pkgName)); } } finally { // Cleanup - ensure we uninstall all large apps if they were installed for (int i=0; i < LARGE_APPS.length; ++i) { String apkName = LARGE_APPS[i][APK.FILENAME.ordinal()]; String pkgName = LARGE_APPS[i][APK.PACKAGENAME.ordinal()]; Log.i(LOG_TAG, "Uninstalling app " + apkName); // cleanup test app just in case it was accidently installed mPMHostUtils.uninstallApp(pkgName); // grep for package to make sure its not installed anymore assertFalse(mPMHostUtils.doesPackageExist(pkgName)); assertFalse(mPMHostUtils.doesAppExistOnSDCard(pkgName)); } } } /** * Stress test to verify that we can install many small apps onto SD. * <p/> * Assumes adb is running as root in device under test. */ public void testInstallManyAppsOnSD() throws IOException, InterruptedException, InstallException, TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException { Log.i(LOG_TAG, "Test installing 500 small apps onto SD"); try { for (int i = MANY_APPS_START; i <= MANY_APPS_END; ++i) { String currentPkgName = String.format("%s%d", MANY_APPS_PKG_PREFIX, i); // cleanup test app just in case it already exists mPMHostUtils.uninstallApp(currentPkgName); // grep for package to make sure its not installed assertFalse(mPMHostUtils.doesPackageExist(currentPkgName)); String currentApkName = String.format("%s%d.apk", MANY_APPS_APK_PREFIX, i); Log.i(LOG_TAG, "Installing app " + currentApkName); mPMHostUtils.installFile(getRepositoryTestAppFilePath(MANY_APPS_DIRECTORY_NAME, currentApkName), true); mPMHostUtils.waitForPackageManager(); assertTrue(mPMHostUtils.doesAppExistOnSDCard(currentPkgName)); assertTrue(mPMHostUtils.doesPackageExist(currentPkgName)); } } finally { for (int i = MANY_APPS_START; i <= MANY_APPS_END; ++i) { String currentPkgName = String.format("%s%d", MANY_APPS_PKG_PREFIX, i); // cleanup test app mPMHostUtils.uninstallApp(currentPkgName); // grep for package to make sure its not installed assertFalse(mPMHostUtils.doesPackageExist(currentPkgName)); } } } }