blob: 9c9d7771d58e83744cd59b63139e5b59be888fda [file] [log] [blame]
/*
* 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.IShellOutputReceiver;
import com.android.ddmlib.Log;
import com.android.ddmlib.MultiLineReceiver;
import com.android.ddmlib.SyncService;
import com.android.ddmlib.SyncService.ISyncProgressMonitor;
import com.android.ddmlib.SyncService.SyncResult;
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 install cases
*/
public class PackageManagerHostTests extends DeviceTestCase {
// testPushAppPrivate constants
// these constants must match values defined in test-apps/SimpleTestApp
private static final String SIMPLE_APK = "SimpleTestApp.apk";
private static final String SIMPLE_PKG = "com.android.framework.simpletestapp";
// TODO: get this value from Android Environment instead of hardcoding
private static final String APP_PRIVATE_PATH = "/data/app-private/";
private static final String LOG_TAG = "PackageManagerHostTests";
private static final int MAX_WAIT_FOR_DEVICE_TIME = 120 * 1000;
private static final int WAIT_FOR_DEVICE_POLL_TIME = 10 * 1000;
@Override
protected void setUp() throws Exception {
super.setUp();
// ensure apk path has been set before test is run
assertNotNull(getTestAppPath());
}
/**
* Regression test to verify that pushing an apk to the private app directory doesn't install
* the app, and otherwise cause the system to blow up.
* <p/>
* Assumes adb is running as root in device under test.
*/
public void testPushAppPrivate() throws IOException, InterruptedException {
Log.i(LOG_TAG, "testing pushing an apk to /data/app-private");
final String apkAppPrivatePath = APP_PRIVATE_PATH + SIMPLE_APK;
// cleanup test app just in case it was accidently installed
getDevice().uninstallPackage(SIMPLE_PKG);
executeShellCommand("stop");
pushFile(getTestAppFilePath(SIMPLE_APK), apkAppPrivatePath);
// sanity check to make sure file is there
assertTrue(doesRemoteFileExist(apkAppPrivatePath));
executeShellCommand("start");
waitForDevice();
// grep for package to make sure its not installed
assertFalse(doesPackageExist(SIMPLE_PKG));
// ensure it has been deleted from app-private
assertFalse(doesRemoteFileExist(apkAppPrivatePath));
}
/**
* Helper method to push a file to device
* @param apkAppPrivatePath
* @throws IOException
*/
private void pushFile(final String localFilePath, final String destFilePath)
throws IOException {
SyncResult result = getDevice().getSyncService().pushFile(
localFilePath, destFilePath,
new NullSyncProgressMonitor());
assertEquals(SyncService.RESULT_OK, result.getCode());
}
/**
* Helper method to determine if file on device exists.
*
* @param destPath the absolute path of file on device to check
* @return <code>true</code> if file exists, <code>false</code> otherwise.
* @throws IOException if adb shell command failed
*/
private boolean doesRemoteFileExist(String destPath) throws IOException {
String lsGrep = executeShellCommand(String.format("ls %s",
destPath));
return !lsGrep.contains("No such file or directory");
}
/**
* Helper method to determine if package on device exists.
*
* @param packageName the Android manifest package to check.
* @return <code>true</code> if package exists, <code>false</code> otherwise
* @throws IOException if adb shell command failed
*/
private boolean doesPackageExist(String packageName) throws IOException {
String pkgGrep = executeShellCommand(String.format("pm path %s",
packageName));
return pkgGrep.contains("package:");
}
/**
* Waits for device's package manager to respond.
*
* @throws InterruptedException
* @throws IOException
*/
private void waitForDevice() throws InterruptedException, IOException {
Log.i(LOG_TAG, "waiting for device");
int currentWaitTime = 0;
// poll the package manager until it returns something for android
while (!doesPackageExist("android")) {
Thread.sleep(WAIT_FOR_DEVICE_POLL_TIME);
currentWaitTime += WAIT_FOR_DEVICE_POLL_TIME;
if (currentWaitTime > MAX_WAIT_FOR_DEVICE_TIME) {
Log.e(LOG_TAG, "time out waiting for device");
throw new InterruptedException();
}
}
}
/**
* Helper method which executes a adb shell command and returns output as a {@link String}
* @return
* @throws IOException
*/
private String executeShellCommand(String command) throws IOException {
Log.d(LOG_TAG, String.format("adb shell %s", command));
CollectingOutputReceiver receiver = new CollectingOutputReceiver();
getDevice().executeShellCommand(command, receiver);
String output = receiver.getOutput();
Log.d(LOG_TAG, String.format("Result: %s", output));
return output;
}
/**
* 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
*/
private String getTestAppFilePath(String fileName) {
return String.format("%s%s%s", getTestAppPath(), File.separator, fileName);
}
public static Test suite() {
return new DeviceTestSuite(PackageManagerHostTests.class);
}
/**
* A {@link IShellOutputReceiver} which collects the whole shell output into one {@link String}
*/
private static class CollectingOutputReceiver extends MultiLineReceiver {
private StringBuffer mOutputBuffer = new StringBuffer();
public String getOutput() {
return mOutputBuffer.toString();
}
@Override
public void processNewLines(String[] lines) {
for (String line: lines) {
mOutputBuffer.append(line);
mOutputBuffer.append("\n");
}
}
public boolean isCancelled() {
return false;
}
}
private static class NullSyncProgressMonitor implements ISyncProgressMonitor {
public void advance(int work) {
// ignore
}
public boolean isCanceled() {
// ignore
return false;
}
public void start(int totalWork) {
// ignore
}
public void startSubTask(String name) {
// ignore
}
public void stop() {
// ignore
}
}
}