blob: 5933c998533c30d43c2894f614c9d928a925289a [file] [log] [blame]
/*
* Copyright (C) 2017 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.testtype.junit4;
import static org.junit.Assert.assertTrue;
import com.android.annotations.VisibleForTesting;
import com.android.ddmlib.Log.LogLevel;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.invoker.IInvocationContext;
import com.android.tradefed.invoker.TestInformation;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.CollectingTestListener;
import com.android.tradefed.result.ITestLifeCycleReceiver;
import com.android.tradefed.result.TestDescription;
import com.android.tradefed.result.TestResult;
import com.android.tradefed.result.TestRunResult;
import com.android.tradefed.result.TestStatus;
import com.android.tradefed.result.ddmlib.DefaultRemoteAndroidTestRunner;
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.TargetSetupError;
import com.android.tradefed.targetprep.suite.SuiteApkInstaller;
import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.testtype.IAbiReceiver;
import com.android.tradefed.testtype.ITestInformationReceiver;
import com.android.tradefed.util.ListInstrumentationParser;
import com.android.tradefed.util.ListInstrumentationParser.InstrumentationTarget;
import org.junit.After;
import org.junit.Assume;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* Base test class for running host JUnit4 style tests. This class provides support to install, run
* and clean up instrumentation tests from the host side. This class is multi-devices compatible.
* Should be the single source of truth to run instrumentation tests from host side in order to
* avoid duplicated utility and base class.
*/
public abstract class BaseHostJUnit4Test implements IAbiReceiver, ITestInformationReceiver {
static final long DEFAULT_TEST_TIMEOUT_MS = 10 * 60 * 1000L;
static final long DEFAULT_MAX_TIMEOUT_TO_OUTPUT_MS = 10 * 60 * 1000L; // 10 min
private static final Map<String, String> DEFAULT_INSTRUMENTATION_ARGS = new HashMap<>();
private IAbi mAbi;
private TestInformation mTestInfo;
private Map<SuiteApkInstaller, ITestDevice> mInstallers = new LinkedHashMap<>();
private TestRunResult mLatestInstruRes;
public final ITestDevice getDevice() {
return mTestInfo.getDevice();
}
public final IBuildInfo getBuild() {
return mTestInfo.getBuildInfo();
}
@Override
public final void setTestInformation(TestInformation testInformation) {
mTestInfo = testInformation;
}
@Override
public TestInformation getTestInformation() {
return mTestInfo;
}
@Override
public final void setAbi(IAbi abi) {
mAbi = abi;
}
@Override
public final IAbi getAbi() {
return mAbi;
}
public final IInvocationContext getInvocationContext() {
return mTestInfo.getContext();
}
public final List<ITestDevice> getListDevices() {
return mTestInfo.getContext().getDevices();
}
/**
* Automatic tear down for all the apk installed. This will uninstall all the apk from the
* device they where installed on.
*/
@After
public final void autoTearDown() throws DeviceNotAvailableException {
mLatestInstruRes = null;
for (SuiteApkInstaller installer : mInstallers.keySet()) {
installer.tearDown(mTestInfo, null);
}
mInstallers.clear();
}
// ------------------------- Utility APIs provided for tests -------------------------
/**
* Install an apk given its name on the device. Apk will be auto-cleaned.
*
* @param apkFileName The name of the apk file.
* @param options extra options given to the install command
*/
public final void installPackage(String apkFileName, String... options)
throws DeviceNotAvailableException, TargetSetupError {
final DeviceTestRunOptions installOptions = new DeviceTestRunOptions(null /*unused*/);
installOptions.setApkFileName(apkFileName);
installOptions.setInstallArgs(options);
installPackage(installOptions);
}
/**
* Install an apk given its name on a given device. Apk will be auto-cleaned.
*
* @param device the {@link ITestDevice} on which to install the apk.
* @param apkFileName The name of the apk file.
* @param options extra options given to the install command
*/
public final void installPackage(ITestDevice device, String apkFileName, String... options)
throws DeviceNotAvailableException, TargetSetupError {
final DeviceTestRunOptions installOptions = new DeviceTestRunOptions(null /*unused*/);
installOptions.setApkFileName(apkFileName);
installOptions.setDevice(device);
installOptions.setInstallArgs(options);
installPackage(installOptions);
}
/**
* Install an apk based on the {@link DeviceTestRunOptions} on the device. Apk will be
* auto-cleaned.
*
* @param options The options of the package installation.
*/
public final void installPackage(DeviceTestRunOptions options)
throws DeviceNotAvailableException, TargetSetupError {
final SuiteApkInstaller installer = createSuiteApkInstaller();
final ITestDevice device = options.getDevice() == null
? getDevice() : options.getDevice();
// Force the apk clean up
installer.setCleanApk(true);
// Store the preparer for cleanup
mInstallers.put(installer, device);
installer.addTestFileName(options.getApkFileName());
// If a userId is provided, grantPermission can be set for the apk installation.
if (options.getUserId() != null) {
installer.setUserId(options.getUserId());
installer.setShouldGrantPermission(options.isGrantPermission());
}
installer.setForceQueryable(options.isForceQueryable());
installer.setAbi(getAbi());
for (String option : options.getInstallArgs()) {
installer.addInstallArg(option);
}
try {
installer.setUp(mTestInfo);
} catch (BuildError e) {
// For some reason we forgot the BuildError part of the interface so it's hard to add
// it now
throw new TargetSetupError(
e.getMessage(), e, device.getDeviceDescriptor(), e.getErrorId());
}
}
/**
* Install an apk given its name for a specific user.
*
* @param apkFileName The name of the apk file.
* @param grantPermission whether to pass the grant permission flag when installing the apk.
* @param userId the user id of the user where to install the apk.
* @param options extra options given to the install command
*/
public final void installPackageAsUser(
String apkFileName, boolean grantPermission, int userId, String... options)
throws DeviceNotAvailableException, TargetSetupError {
final DeviceTestRunOptions installOptions = new DeviceTestRunOptions(null /*unused*/);
installOptions.setApkFileName(apkFileName);
installOptions.setGrantPermission(grantPermission);
installOptions.setUserId(userId);
installOptions.setInstallArgs(options);
installPackage(installOptions);
}
/**
* Install an apk given its name for a specific user on a given device.
*
* @param device the {@link ITestDevice} on which to install the apk.
* @param apkFileName The name of the apk file.
* @param grantPermission whether to pass the grant permission flag when installing the apk.
* @param userId the user id of the user where to install the apk.
* @param options extra options given to the install command
*/
public final void installPackageAsUser(
ITestDevice device,
String apkFileName,
boolean grantPermission,
int userId,
String... options)
throws DeviceNotAvailableException, TargetSetupError {
final DeviceTestRunOptions installOptions = new DeviceTestRunOptions(null /*unused*/);
installOptions.setApkFileName(apkFileName);
installOptions.setDevice(device);
installOptions.setGrantPermission(grantPermission);
installOptions.setUserId(userId);
installOptions.setInstallArgs(options);
installPackage(installOptions);
}
/**
* Method to run an installed instrumentation package. Use {@link #getLastDeviceRunResults()}
* right after to get the details of results.
*
* @param pkgName the name of the package to run.
* @param testClassName the name of the test class to run.
* @return True if it succeed without failure. False otherwise.
*/
public final boolean runDeviceTests(String pkgName, String testClassName)
throws DeviceNotAvailableException {
return runDeviceTests(getDevice(), pkgName, testClassName, null);
}
/**
* Method to run an installed instrumentation package. Use {@link #getLastDeviceRunResults()}
* right after to get the details of results.
*
* @param pkgName the name of the package to run.
* @param testClassName the name of the test class to run.
* @param testTimeoutMs the timeout in millisecond to be applied to each test case.
* @return True if it succeed without failure. False otherwise.
*/
public final boolean runDeviceTests(String pkgName, String testClassName, Long testTimeoutMs)
throws DeviceNotAvailableException {
return runDeviceTests(
getDevice(),
null,
pkgName,
testClassName,
null,
null,
testTimeoutMs,
DEFAULT_MAX_TIMEOUT_TO_OUTPUT_MS,
0L,
true,
false,
DEFAULT_INSTRUMENTATION_ARGS);
}
/**
* Method to run an installed instrumentation package. Use {@link #getLastDeviceRunResults()}
* right after to get the details of results.
*
* @param pkgName the name of the package to run.
* @param testClassName the name of the test class to run.
* @param userId the id of the user to run the test against. can be null.
* @param testTimeoutMs the timeout in millisecond to be applied to each test case.
* @return True if it succeed without failure. False otherwise.
*/
public final boolean runDeviceTests(
String pkgName, String testClassName, Integer userId, Long testTimeoutMs)
throws DeviceNotAvailableException {
return runDeviceTests(
getDevice(),
null,
pkgName,
testClassName,
null,
userId,
testTimeoutMs,
DEFAULT_MAX_TIMEOUT_TO_OUTPUT_MS,
0L,
true,
false,
DEFAULT_INSTRUMENTATION_ARGS);
}
/**
* Method to run an installed instrumentation package. Use {@link #getLastDeviceRunResults()}
* right after to get the details of results.
*
* @param pkgName the name of the package to run.
* @param testClassName the name of the test class to run.
* @param testMethodName the name of the test method in the class to be run.
* @return True if it succeed without failure. False otherwise.
*/
public final boolean runDeviceTests(String pkgName, String testClassName, String testMethodName)
throws DeviceNotAvailableException {
return runDeviceTests(getDevice(), pkgName, testClassName, testMethodName);
}
/**
* Method to run an installed instrumentation package. Use {@link #getLastDeviceRunResults()}
* right after to get the details of results.
*
* @param runner the instrumentation runner to be used.
* @param pkgName the name of the package to run.
* @param testClassName the name of the test class to run.
* @param testMethodName the name of the test method in the class to be run.
* @return True if it succeed without failure. False otherwise.
*/
public final boolean runDeviceTests(
String runner, String pkgName, String testClassName, String testMethodName)
throws DeviceNotAvailableException {
return runDeviceTests(
getDevice(),
runner,
pkgName,
testClassName,
testMethodName,
null,
DEFAULT_TEST_TIMEOUT_MS,
DEFAULT_MAX_TIMEOUT_TO_OUTPUT_MS,
0L,
true,
false,
DEFAULT_INSTRUMENTATION_ARGS);
}
/**
* Method to run an installed instrumentation package. Use {@link #getLastDeviceRunResults()}
* right after to get the details of results.
*
* @param device the device agaisnt which to run the instrumentation.
* @param pkgName the name of the package to run.
* @param testClassName the name of the test class to run.
* @param testMethodName the name of the test method in the class to be run.
* @return True if it succeed without failure. False otherwise.
*/
public final boolean runDeviceTests(
ITestDevice device, String pkgName, String testClassName, String testMethodName)
throws DeviceNotAvailableException {
return runDeviceTests(
device,
null,
pkgName,
testClassName,
testMethodName,
null,
DEFAULT_TEST_TIMEOUT_MS,
DEFAULT_MAX_TIMEOUT_TO_OUTPUT_MS,
0L,
true,
false,
DEFAULT_INSTRUMENTATION_ARGS);
}
/**
* Method to run an installed instrumentation package. Use {@link #getLastDeviceRunResults()}
* right after to get the details of results.
*
* @param device the device agaisnt which to run the instrumentation.
* @param pkgName the name of the package to run.
* @param testClassName the name of the test class to run.
* @param testMethodName the name of the test method in the class to be run.
* @param testTimeoutMs the timeout in millisecond to be applied to each test case.
* @return True if it succeed without failure. False otherwise.
*/
public final boolean runDeviceTests(
ITestDevice device,
String pkgName,
String testClassName,
String testMethodName,
Long testTimeoutMs)
throws DeviceNotAvailableException {
return runDeviceTests(
device,
null,
pkgName,
testClassName,
testMethodName,
null,
testTimeoutMs,
DEFAULT_MAX_TIMEOUT_TO_OUTPUT_MS,
0L,
true,
false,
DEFAULT_INSTRUMENTATION_ARGS);
}
/**
* Method to run an installed instrumentation package. Use {@link #getLastDeviceRunResults()}
* right after to get the details of results.
*
* @param device the device agaisnt which to run the instrumentation.
* @param pkgName the name of the package to run.
* @param testClassName the name of the test class to run.
* @param testMethodName the name of the test method in the class to be run.
* @param userId the id of the user to run the test against. can be null.
* @param testTimeoutMs the timeout in millisecond to be applied to each test case.
* @return True if it succeed without failure. False otherwise.
*/
public final boolean runDeviceTests(
ITestDevice device,
String pkgName,
String testClassName,
String testMethodName,
Integer userId,
Long testTimeoutMs)
throws DeviceNotAvailableException {
return runDeviceTests(
device,
null,
pkgName,
testClassName,
testMethodName,
userId,
testTimeoutMs,
DEFAULT_MAX_TIMEOUT_TO_OUTPUT_MS,
0L,
true,
false,
DEFAULT_INSTRUMENTATION_ARGS);
}
/**
* Method to run an installed instrumentation package. Use {@link #getLastDeviceRunResults()}
* right after to get the details of results.
*
* @param device the device agaisnt which to run the instrumentation.
* @param pkgName the name of the package to run.
* @param testClassName the name of the test class to run.
* @param testMethodName the name of the test method in the class to be run.
* @param testTimeoutMs the timeout in millisecond to be applied to each test case.
* @param maxTimeToOutputMs the max timeout the test has to start outputting something.
* @param maxInstrumentationTimeoutMs the max timeout the full instrumentation has to complete.
* @return True if it succeed without failure. False otherwise.
*/
public final boolean runDeviceTests(
ITestDevice device,
String pkgName,
String testClassName,
String testMethodName,
Long testTimeoutMs,
Long maxTimeToOutputMs,
Long maxInstrumentationTimeoutMs)
throws DeviceNotAvailableException {
return runDeviceTests(
device,
null,
pkgName,
testClassName,
testMethodName,
null,
testTimeoutMs,
maxTimeToOutputMs,
maxInstrumentationTimeoutMs,
true,
false,
DEFAULT_INSTRUMENTATION_ARGS);
}
/**
* Runs the instrumentation base on the information in {@link DeviceTestRunOptions}.
*
* @param options the {@link DeviceTestRunOptions} driving the instrumentation setup.
* @return True if it succeeded without failure. False otherwise.
* @throws DeviceNotAvailableException
*/
public final boolean runDeviceTests(DeviceTestRunOptions options)
throws DeviceNotAvailableException {
return runDeviceTests(
options.getDevice() == null ? getDevice() : options.getDevice(),
options.getRunner(),
options.getPackageName(),
options.getTestClassName(),
options.getTestMethodName(),
options.getUserId(),
options.getTestTimeoutMs(),
options.getMaxTimeToOutputMs(),
options.getMaxInstrumentationTimeoutMs(),
options.shouldCheckResults(),
options.isHiddenApiCheckDisabled(),
options.isTestApiCheckDisabled(),
options.isIsolatedStorageDisabled(),
options.isWindowAnimationDisabled(),
options.isRestartDisabled(),
options.getInstrumentationArgs(),
options.getExtraListeners());
}
/**
* Method to run an installed instrumentation package. Use {@link #getLastDeviceRunResults()}
* right after to get the details of results.
*
* @param device the device agaisnt which to run the instrumentation.
* @param pkgName the name of the package to run.
* @param testClassName the name of the test class to run.
* @param testMethodName the name of the test method in the class to be run.
* @param userId the id of the user to run the test against. can be null.
* @param testTimeoutMs the timeout in millisecond to be applied to each test case.
* @param maxTimeToOutputMs the max timeout the test has to start outputting something.
* @param maxInstrumentationTimeoutMs the max timeout the full instrumentation has to complete.
* @param checkResults whether or not the results are checked for crashes.
* @param isHiddenApiCheckDisabled whether or not we should disable the hidden api check.
* @param instrumentationArgs arguments to pass to the instrumentation.
* @return True if it succeeded without failure. False otherwise.
*/
public final boolean runDeviceTests(
ITestDevice device,
String runner,
String pkgName,
String testClassName,
String testMethodName,
Integer userId,
Long testTimeoutMs,
Long maxTimeToOutputMs,
Long maxInstrumentationTimeoutMs,
boolean checkResults,
boolean isHiddenApiCheckDisabled,
Map<String, String> instrumentationArgs)
throws DeviceNotAvailableException {
return runDeviceTests(
device,
runner,
pkgName,
testClassName,
testMethodName,
userId,
testTimeoutMs,
maxTimeToOutputMs,
maxInstrumentationTimeoutMs,
checkResults,
isHiddenApiCheckDisabled,
true,
false,
instrumentationArgs,
new ArrayList<>());
}
/**
* Method to run an installed instrumentation package. Use {@link #getLastDeviceRunResults()}
* right after to get the details of results.
*
* @param device the device agaisnt which to run the instrumentation.
* @param pkgName the name of the package to run.
* @param testClassName the name of the test class to run.
* @param testMethodName the name of the test method in the class to be run.
* @param userId the id of the user to run the test against. can be null.
* @param testTimeoutMs the timeout in millisecond to be applied to each test case.
* @param maxTimeToOutputMs the max timeout the test has to start outputting something.
* @param maxInstrumentationTimeoutMs the max timeout the full instrumentation has to complete.
* @param checkResults whether or not the results are checked for crashes.
* @param isHiddenApiCheckDisabled whether or not we should disable the hidden api check.
* @param isTestApiCheckDisabled whether or not we should disable the test api check.
* @param isIsolatedStorageDisabled whether or not we should disable isolated storage.
* @param instrumentationArgs arguments to pass to the instrumentation.
* @return True if it succeeded without failure. False otherwise.
*/
public final boolean runDeviceTests(
ITestDevice device,
String runner,
String pkgName,
String testClassName,
String testMethodName,
Integer userId,
Long testTimeoutMs,
Long maxTimeToOutputMs,
Long maxInstrumentationTimeoutMs,
boolean checkResults,
boolean isHiddenApiCheckDisabled,
boolean isTestApiCheckDisabled,
boolean isIsolatedStorageDisabled,
Map<String, String> instrumentationArgs,
List<ITestLifeCycleReceiver> extraListeners)
throws DeviceNotAvailableException {
return runDeviceTests(
device,
runner,
pkgName,
testClassName,
testMethodName,
userId,
testTimeoutMs,
maxTimeToOutputMs,
maxInstrumentationTimeoutMs,
checkResults,
isHiddenApiCheckDisabled,
isTestApiCheckDisabled,
isIsolatedStorageDisabled,
false, // leave window animations enabled for existing invocations
instrumentationArgs,
extraListeners);
}
/**
* Method to run an installed instrumentation package. Use {@link #getLastDeviceRunResults()}
* right after to get the details of results.
*
* @param device the device agaisnt which to run the instrumentation.
* @param pkgName the name of the package to run.
* @param testClassName the name of the test class to run.
* @param testMethodName the name of the test method in the class to be run.
* @param userId the id of the user to run the test against. can be null.
* @param testTimeoutMs the timeout in millisecond to be applied to each test case.
* @param maxTimeToOutputMs the max timeout the test has to start outputting something.
* @param maxInstrumentationTimeoutMs the max timeout the full instrumentation has to complete.
* @param checkResults whether or not the results are checked for crashes.
* @param isHiddenApiCheckDisabled whether or not we should disable the hidden api check.
* @param isTestApiCheckDisabled whether or not we should disable the test api check.
* @param isIsolatedStorageDisabled whether or not we should disable isolated storage.
* @param isWindowAnimationDisabled whether or not we should disable window animation.
* @param instrumentationArgs arguments to pass to the instrumentation.
* @return True if it succeeded without failure. False otherwise.
*/
public final boolean runDeviceTests(
ITestDevice device,
String runner,
String pkgName,
String testClassName,
String testMethodName,
Integer userId,
Long testTimeoutMs,
Long maxTimeToOutputMs,
Long maxInstrumentationTimeoutMs,
boolean checkResults,
boolean isHiddenApiCheckDisabled,
boolean isTestApiCheckDisabled,
boolean isIsolatedStorageDisabled,
boolean isWindowAnimationDisabled,
Map<String, String> instrumentationArgs,
List<ITestLifeCycleReceiver> extraListeners)
throws DeviceNotAvailableException {
return runDeviceTests(
device,
runner,
pkgName,
testClassName,
testMethodName,
userId,
testTimeoutMs,
maxTimeToOutputMs,
maxInstrumentationTimeoutMs,
checkResults,
isHiddenApiCheckDisabled,
isTestApiCheckDisabled,
isIsolatedStorageDisabled,
isWindowAnimationDisabled,
false, // leave restart enabled
instrumentationArgs,
extraListeners);
}
/**
* Method to run an installed instrumentation package. Use {@link #getLastDeviceRunResults()}
* right after to get the details of results.
*
* @param device the device agaisnt which to run the instrumentation.
* @param pkgName the name of the package to run.
* @param testClassName the name of the test class to run.
* @param testMethodName the name of the test method in the class to be run.
* @param userId the id of the user to run the test against. can be null.
* @param testTimeoutMs the timeout in millisecond to be applied to each test case.
* @param maxTimeToOutputMs the max timeout the test has to start outputting something.
* @param maxInstrumentationTimeoutMs the max timeout the full instrumentation has to complete.
* @param checkResults whether or not the results are checked for crashes.
* @param isHiddenApiCheckDisabled whether or not we should disable the hidden api check.
* @param isTestApiCheckDisabled whether or not we should disable the test api check.
* @param isIsolatedStorageDisabled whether or not we should disable isolated storage.
* @param isWindowAnimationDisabled whether or not we should disable window animation.
* @param instrumentationArgs arguments to pass to the instrumentation.
* @return True if it succeeded without failure. False otherwise.
*/
public final boolean runDeviceTests(
ITestDevice device,
String runner,
String pkgName,
String testClassName,
String testMethodName,
Integer userId,
Long testTimeoutMs,
Long maxTimeToOutputMs,
Long maxInstrumentationTimeoutMs,
boolean checkResults,
boolean isHiddenApiCheckDisabled,
boolean isTestApiCheckDisabled,
boolean isIsolatedStorageDisabled,
boolean isWindowAnimationDisabled,
boolean isRestartDisabled,
Map<String, String> instrumentationArgs,
List<ITestLifeCycleReceiver> extraListeners)
throws DeviceNotAvailableException {
TestRunResult runResult =
doRunTests(
device,
runner,
pkgName,
testClassName,
testMethodName,
userId,
testTimeoutMs,
maxTimeToOutputMs,
maxInstrumentationTimeoutMs,
isHiddenApiCheckDisabled,
isTestApiCheckDisabled,
isIsolatedStorageDisabled,
isWindowAnimationDisabled,
isRestartDisabled,
instrumentationArgs,
extraListeners);
mLatestInstruRes = runResult;
printTestResult(runResult);
if (checkResults) {
if (runResult.isRunFailure()) {
throw new AssertionError(
"Failed to successfully run device tests for "
+ runResult.getName()
+ ": "
+ runResult.getRunFailureMessage());
}
if (runResult.getNumTests() == 0) {
throw new AssertionError("No tests were run on the device");
}
if (runResult.hasFailedTests()) {
// build a meaningful error message
StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n");
for (Map.Entry<TestDescription, TestResult> resultEntry :
runResult.getTestResults().entrySet()) {
if (!TestStatus.PASSED.equals(resultEntry.getValue().getResultStatus())) {
errorBuilder.append(resultEntry.getKey().toString());
errorBuilder.append(":\n");
errorBuilder.append(resultEntry.getValue().getStackTrace());
}
}
throw new AssertionError(errorBuilder.toString());
}
// Assume not all tests have skipped (and rethrow AssumptionViolatedException if so)
List<TestResult> assumpFail =
runResult.getTestsResultsInState(TestStatus.ASSUMPTION_FAILURE);
List<String> messages =
assumpFail.stream().map(r -> r.getStackTrace()).collect(Collectors.toList());
String errors = String.join("\n\n", messages);
Assume.assumeTrue(
errors,
runResult.getNumTests()
!= runResult.getNumTestsInState(TestStatus.ASSUMPTION_FAILURE));
}
return !runResult.hasFailedTests() && runResult.getNumTests() > 0;
}
/**
* Returns the {@link TestRunResult} resulting from the latest runDeviceTests that ran. Or null
* if no results available.
*/
public final TestRunResult getLastDeviceRunResults() {
return mLatestInstruRes;
}
/** Helper method to run tests and return the listener that collected the results. */
private TestRunResult doRunTests(
ITestDevice device,
String runner,
String pkgName,
String testClassName,
String testMethodName,
Integer userId,
Long testTimeoutMs,
Long maxTimeToOutputMs,
Long maxInstrumentationTimeoutMs,
boolean isHiddenApiCheckDisabled,
boolean isTestApiCheckDisabled,
boolean isIsolatedStorageDisabled,
boolean isWindowAnimationDisabled,
boolean isRestartDisabled,
Map<String, String> instrumentationArgs,
List<ITestLifeCycleReceiver> extraListeners)
throws DeviceNotAvailableException {
RemoteAndroidTestRunner testRunner = createTestRunner(pkgName, runner, device);
String runOptions = "";
// hidden-api-checks flag only exists in P and after.
// Using a temp variable to consolidate the dynamic checks
int apiLevel = isHiddenApiCheckDisabled || isWindowAnimationDisabled
? device.getApiLevel() : 0;
if (isHiddenApiCheckDisabled && (apiLevel >= 28)) {
runOptions += "--no-hidden-api-checks ";
}
if (!isHiddenApiCheckDisabled
&& !isTestApiCheckDisabled
&& device.checkApiLevelAgainstNextRelease(30)) {
runOptions += "--no-test-api-access ";
}
// isolated-storage flag only exists in Q and after.
if (isIsolatedStorageDisabled && device.checkApiLevelAgainstNextRelease(29)) {
runOptions += "--no-isolated-storage ";
}
// window-animation flag only exists in ICS and after
if (isWindowAnimationDisabled && apiLevel >= 14) {
runOptions += "--no-window-animation ";
}
// restart flag only exists in S and after.
if (isRestartDisabled && device.checkApiLevelAgainstNextRelease(31)) {
runOptions += "--no-restart ";
}
if (getAbi() != null) {
runOptions += String.format("--abi %s", getAbi().getName());
}
// Set the run options if any.
if (!runOptions.isEmpty()) {
testRunner.setRunOptions(runOptions);
}
if (testClassName != null && testMethodName != null) {
testRunner.setMethodName(testClassName, testMethodName);
} else if (testClassName != null) {
testRunner.setClassName(testClassName);
}
if (testTimeoutMs != null) {
testRunner.addInstrumentationArg("timeout_msec", Long.toString(testTimeoutMs));
} else {
testTimeoutMs = DEFAULT_TEST_TIMEOUT_MS;
testRunner.addInstrumentationArg(
"timeout_msec", Long.toString(DEFAULT_TEST_TIMEOUT_MS));
}
if (maxTimeToOutputMs != null && maxTimeToOutputMs < testTimeoutMs) {
// Similar logic as InstrumentationTest
maxTimeToOutputMs = testTimeoutMs + testTimeoutMs / 10;
CLog.w(
String.format(
"maxTimeToOutputMs should be larger than testtimeout %d; NOTE:"
+ " extending maxTimeToOutputMs to %d, please consider fixing"
+ " this!",
testTimeoutMs, maxTimeToOutputMs));
}
if (maxTimeToOutputMs != null) {
testRunner.setMaxTimeToOutputResponse(maxTimeToOutputMs, TimeUnit.MILLISECONDS);
}
if (maxInstrumentationTimeoutMs != null) {
testRunner.setMaxTimeout(maxInstrumentationTimeoutMs, TimeUnit.MILLISECONDS);
}
// Pass all the instrumentation arguments
for (String key : instrumentationArgs.keySet()) {
testRunner.addInstrumentationArg(key, instrumentationArgs.get(key));
}
CollectingTestListener listener = createListener();
List<ITestLifeCycleReceiver> allReceiver = new ArrayList<>();
allReceiver.add(listener);
allReceiver.addAll(extraListeners);
if (userId == null) {
assertTrue(device.runInstrumentationTests(testRunner, allReceiver));
} else {
// Ensure userId is correct before starting instrumentation
assertTrue(userId >= 0);
assertTrue(device.runInstrumentationTestsAsUser(testRunner, userId, allReceiver));
}
return listener.getCurrentRunResults();
}
@VisibleForTesting
RemoteAndroidTestRunner createTestRunner(
String packageName, String runnerName, ITestDevice device)
throws DeviceNotAvailableException {
if (runnerName == null) {
ListInstrumentationParser parser = getListInstrumentationParser();
device.executeShellCommand("pm list instrumentation", parser);
for (InstrumentationTarget target : parser.getInstrumentationTargets()) {
if (packageName.equals(target.packageName)) {
runnerName = target.runnerName;
}
}
}
// If the runner name is still null
if (runnerName == null) {
throw new RuntimeException("No runner was defined and couldn't dynamically find one.");
}
return new DefaultRemoteAndroidTestRunner(packageName, runnerName, device.getIDevice());
}
@VisibleForTesting
ListInstrumentationParser getListInstrumentationParser() {
return new ListInstrumentationParser();
}
@VisibleForTesting
CollectingTestListener createListener() {
return new CollectingTestListener();
}
private void printTestResult(TestRunResult runResult) {
for (Map.Entry<TestDescription, TestResult> testEntry :
runResult.getTestResults().entrySet()) {
TestResult testResult = testEntry.getValue();
TestStatus testStatus = testResult.getResultStatus();
CLog.logAndDisplay(LogLevel.INFO, "Test " + testEntry.getKey() + ": " + testStatus);
if (!TestStatus.PASSED.equals(testStatus)
&& !TestStatus.ASSUMPTION_FAILURE.equals(testStatus)) {
CLog.logAndDisplay(LogLevel.WARN, testResult.getStackTrace());
}
}
}
/**
* Uninstalls a package on the device.
*
* @param pkgName the Android package to uninstall
* @return a {@link String} with an error code, or <code>null</code> if success
*/
public final String uninstallPackage(String pkgName) throws DeviceNotAvailableException {
return getDevice().uninstallPackage(pkgName);
}
/**
* Uninstalls a package on the device
*
* @param device the device that should uninstall the package.
* @param pkgName the Android package to uninstall
* @return a {@link String} with an error code, or <code>null</code> if success
*/
public final String uninstallPackage(ITestDevice device, String pkgName)
throws DeviceNotAvailableException {
return device.uninstallPackage(pkgName);
}
/**
* Checks if a package of a given name is installed on the device
*
* @param pkg the name of the package
* @return true if the package is found on the device
*/
public final boolean isPackageInstalled(String pkg) throws DeviceNotAvailableException {
return isPackageInstalled(getDevice(), pkg);
}
/**
* Checks if a package of a given name is installed on the device
*
* @param device the device that should uninstall the package.
* @param pkg the name of the package
* @return true if the package is found on the device
*/
public final boolean isPackageInstalled(ITestDevice device, String pkg)
throws DeviceNotAvailableException {
for (String installedPackage : device.getInstalledPackageNames()) {
if (pkg.equals(installedPackage)) {
return true;
}
}
return false;
}
public boolean hasDeviceFeature(String feature) throws DeviceNotAvailableException {
return getDevice().hasFeature("feature:" + feature);
}
@VisibleForTesting
SuiteApkInstaller createSuiteApkInstaller() {
return new SuiteApkInstaller();
}
}