Merge "Fix docs: replace </> with </> or (/)"
diff --git a/src/com/android/tradefed/device/WifiHelper.java b/src/com/android/tradefed/device/WifiHelper.java
index 06c0fdf..50c2f45 100644
--- a/src/com/android/tradefed/device/WifiHelper.java
+++ b/src/com/android/tradefed/device/WifiHelper.java
@@ -36,7 +36,7 @@
private static final String NULL_IP_ADDR = "0.0.0.0";
private static final String INSTRUMENTATION_CLASS = ".WifiUtil";
- static final String INSTRUMENTATION_PKG = "com.android.tradefed.utils.wifi";
+ public static final String INSTRUMENTATION_PKG = "com.android.tradefed.utils.wifi";
static final String FULL_INSTRUMENTATION_NAME =
String.format("%s/%s", INSTRUMENTATION_PKG, INSTRUMENTATION_CLASS);
@@ -95,7 +95,7 @@
/**
* Helper method to extract the wifi util apk from the classpath
*/
- static File extractWifiUtilApk() throws IOException {
+ public static File extractWifiUtilApk() throws IOException {
File apkTempFile;
apkTempFile = FileUtil.createTempFile(WIFIUTIL_APK_NAME, ".apk");
InputStream apkStream = WifiHelper.class.getResourceAsStream(
diff --git a/src/com/android/tradefed/targetprep/AppSetup.java b/src/com/android/tradefed/targetprep/AppSetup.java
index 8137dd4..176f0a6 100644
--- a/src/com/android/tradefed/targetprep/AppSetup.java
+++ b/src/com/android/tradefed/targetprep/AppSetup.java
@@ -23,12 +23,16 @@
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.util.AaptParser;
+import java.io.File;
import java.util.HashSet;
import java.util.Set;
/**
* A {@link ITargetPreparer} that installs an apk and its tests.
+ * <p/>
+ * Requires 'aapt' on PATH when --uninstall is set
*/
@OptionClass(alias="app-setup")
public class AppSetup implements ITargetPreparer, ITargetCleaner {
@@ -39,13 +43,21 @@
@Option(name = "install", description = "install all apks in build.")
private boolean mInstall = true;
- @Option(name = "uninstall", description = "uninstall all apks after test completes.")
+ @Option(name = "uninstall", description =
+ "uninstall only apks in build after test completes.")
private boolean mUninstall = true;
+ @Option(name = "uninstall-all", description =
+ "uninstall all unnstallable apks found on device after test completes.")
+ private boolean mUninstallAll = false;
+
@Option(name = "skip-uninstall-pkg", description =
- "force retention of this package when --uninstall is set.")
+ "force retention of this package when --uninstall-all is set.")
private Set<String> mSkipUninstallPkgs = new HashSet<String>();
+ /** contains package names of installed apps. Used for uninstall */
+ private Set<String> mInstalledPkgs = new HashSet<String>();
+
/**
* {@inheritDoc}
*/
@@ -59,7 +71,7 @@
CLog.i("Performing setup on %s", device.getSerialNumber());
// double check that device is clean, in case it has unexpected cruft on it
- if (mUninstall && !uninstallApps(device)) {
+ if (mUninstallAll && !uninstallAllApps(device)) {
// cannot cleanup device! Bad things may happen in future tests. Take device out
// of service
// TODO: in future, consider doing more sophisticated recovery operations
@@ -75,11 +87,27 @@
"Failed to install %s on %s. Reason: %s",
apkFile.getFile().getName(), device.getSerialNumber(), result));
}
+ if (mUninstall && !mUninstallAll) {
+ addPackageNameToUninstall(apkFile.getFile());
+ }
}
}
}
+ private void addPackageNameToUninstall(File apkFile) throws TargetSetupError {
+ AaptParser aaptParser = AaptParser.parse(apkFile);
+ if (aaptParser == null) {
+ throw new TargetSetupError(String.format("Failed to extract info from '%s' using aapt",
+ apkFile.getAbsolutePath()));
+ }
+ if (aaptParser.getPackageName() == null) {
+ throw new TargetSetupError(String.format(
+ "Failed to find package name for '%s' using aapt", apkFile.getAbsolutePath()));
+ }
+ mInstalledPkgs.add(aaptParser.getPackageName());
+ }
+
/**
* {@inheritDoc}
*/
@@ -90,7 +118,16 @@
if (mReboot) {
device.reboot();
}
- if (mUninstall && !uninstallApps(device)) {
+ if (mUninstall && !mUninstallAll) {
+ for (String pkgName : mInstalledPkgs) {
+ String result = device.uninstallPackage(pkgName);
+ if (result != null) {
+ CLog.e("Failed to uninstall %s: %s", pkgName, result);
+ // TODO: consider throwing here
+ }
+ }
+ }
+ if (mUninstallAll && !uninstallAllApps(device)) {
// cannot cleanup device! Bad things may happen in future tests. Take device out
// of service
// TODO: in future, consider doing more sophisticated recovery operations
@@ -99,12 +136,12 @@
}
}
- private boolean uninstallApps(ITestDevice device) throws DeviceNotAvailableException {
+ private boolean uninstallAllApps(ITestDevice device) throws DeviceNotAvailableException {
// make multiple attempts to uninstall apps, aborting if failed
// TODO: consider moving this to ITestDevice, so more sophisticated recovery attempts
// can be performed
for (int i = 0; i < 3; i++) {
- Set<String> pkgs = getAppsToUninstall(device);
+ Set<String> pkgs = getAllAppsToUninstall(device);
if (pkgs.isEmpty()) {
return true;
}
@@ -118,10 +155,10 @@
}
// check getAppsToUninstall one more time, cause last attempt through loop might have been
// successful
- return getAppsToUninstall(device).isEmpty();
+ return getAllAppsToUninstall(device).isEmpty();
}
- private Set<String> getAppsToUninstall(ITestDevice device) throws DeviceNotAvailableException {
+ private Set<String> getAllAppsToUninstall(ITestDevice device) throws DeviceNotAvailableException {
Set<String> pkgs = device.getUninstallablePackageNames();
pkgs.removeAll(mSkipUninstallPkgs);
return pkgs;
diff --git a/src/com/android/tradefed/testtype/InstalledInstrumentationsTest.java b/src/com/android/tradefed/testtype/InstalledInstrumentationsTest.java
index 0c91d8c..f0155be 100644
--- a/src/com/android/tradefed/testtype/InstalledInstrumentationsTest.java
+++ b/src/com/android/tradefed/testtype/InstalledInstrumentationsTest.java
@@ -85,6 +85,10 @@
"collector, so use the EACH setting with due caution.")
private BugreportCollector.Freq mBugreportFrequency = null;
+ @Option(name = "class",
+ description = "Only run tests in specified class")
+ private String mTestClass = null;
+
private List<InstrumentationTest> mTests = null;
/**
@@ -168,6 +172,7 @@
sendCoverage(test.getPackageName(), test.getCoverageTarget(), listener);
}
test.setDevice(getDevice());
+ test.setClassName(mTestClass);
test.run(listener);
// test completed, remove from list
mTests.remove(0);
diff --git a/src/com/android/tradefed/util/AaptParser.java b/src/com/android/tradefed/util/AaptParser.java
index 2477eab..9bef466 100644
--- a/src/com/android/tradefed/util/AaptParser.java
+++ b/src/com/android/tradefed/util/AaptParser.java
@@ -22,7 +22,7 @@
import java.util.regex.Pattern;
/**
- * class that extracts info from apk by parsing output of 'aapt dump badging'.
+ * Class that extracts info from apk by parsing output of 'aapt dump badging'.
* <p/>
* aapt must be on PATH
*/
@@ -44,13 +44,18 @@
}
}
+ /**
+ * Parse info from the apk.
+ *
+ * @param apkFile the apk file
+ * @return the {@link AaptParser} or <code>null</code> if failed to extract the information
+ */
public static AaptParser parse(File apkFile) {
CommandResult result = RunUtil.getDefault().runTimedCmd(5000, "aapt", "dump", "badging",
apkFile.getAbsolutePath());
if (result.getStatus() == CommandStatus.SUCCESS) {
AaptParser p = new AaptParser();
p.parse(result.getStdout());
-
return p;
}
CLog.e("Failed to run aapt on %s", apkFile.getAbsoluteFile());
@@ -60,4 +65,5 @@
public String getPackageName() {
return mPackageName;
}
+
}
diff --git a/tests/src/com/android/tradefed/targetprep/AppSetupFuncTest.java b/tests/src/com/android/tradefed/targetprep/AppSetupFuncTest.java
new file mode 100644
index 0000000..3bd02a7
--- /dev/null
+++ b/tests/src/com/android/tradefed/targetprep/AppSetupFuncTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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 com.android.tradefed.targetprep;
+
+import com.android.tradefed.build.AppBuildInfo;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.WifiHelper;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.util.FileUtil;
+
+import java.io.File;
+
+/**
+ * A functional test for {@link AppSetup}.
+ * <p/>
+ * Relies on WifiUtil.apk in tradefed.jar.
+ * <p/>
+ * 'aapt' must be in PATH.
+ */
+public class AppSetupFuncTest extends DeviceTestCase {
+
+ /**
+ * Test end to end normal case for {@link AppSetup}.
+ */
+ public void testSetupTeardown() throws Exception {
+ // use wifiutil as a test apk since it already exists
+ getDevice().uninstallPackage(WifiHelper.INSTRUMENTATION_PKG);
+ File wifiapk = WifiHelper.extractWifiUtilApk();
+ try {
+ AppBuildInfo appBuild = new AppBuildInfo("0", "stub", "stub");
+ appBuild.addAppPackageFile(wifiapk, "0");
+ AppSetup appSetup = new AppSetup();
+ // turn off reboot to reduce test execution time
+ OptionSetter optionSetter = new OptionSetter(appSetup);
+ optionSetter.setOptionValue("reboot", "false");
+ appSetup.setUp(getDevice(), appBuild);
+ assertTrue(getDevice().getUninstallablePackageNames().contains(
+ WifiHelper.INSTRUMENTATION_PKG));
+ appSetup.tearDown(getDevice(), appBuild, null);
+ assertFalse(getDevice().getUninstallablePackageNames().contains(
+ WifiHelper.INSTRUMENTATION_PKG));
+ } finally {
+ FileUtil.deleteFile(wifiapk);
+ }
+ }
+}