CTS implementation of ITestSuite
- basic CTS implementation of the new ITestSuite to start
scheduling some tests and get results.
- config using the implementation to be used to run.
- Fix CTS monkey module to ensure it does not run out of
memory in case of failures.
Test: unit tests, manual
Bug: 37211399
Change-Id: I78416b3475b2a5eeeb804054ad43273cd4dddca7
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
index df3cfbc..286f53f 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
@@ -56,6 +56,14 @@
@Option(name="branch", description="build branch name to supply.")
private String mBranch = null;
+ @Option(name = "build-id",
+ description =
+ "build version number to supply. Override the default cts version number.")
+ private String mBuildId = null;
+
+ @Option(name="build-flavor", description="build flavor name to supply.")
+ private String mBuildFlavor = null;
+
@Option(name="use-device-build-info", description="Bootstrap build info from device")
private boolean mUseDeviceBuildInfo = false;
@@ -78,14 +86,22 @@
@Override
public IBuildInfo getBuild() {
// Create a blank BuildInfo which will get populated later.
- String version = getSuiteInfoBuildNumber();
- if (version == null) {
- version = IBuildInfo.UNKNOWN_BUILD_ID;
+ String version = null;
+ if (mBuildId != null) {
+ version = mBuildId;
+ } else {
+ version = getSuiteInfoBuildNumber();
+ if (version == null) {
+ version = IBuildInfo.UNKNOWN_BUILD_ID;
+ }
}
- IBuildInfo ctsBuild = new BuildInfo(version, mTestTag, mTestTag);
+ IBuildInfo ctsBuild = new BuildInfo(version, mTestTag);
if (mBranch != null) {
ctsBuild.setBuildBranch(mBranch);
}
+ if (mBuildFlavor != null) {
+ ctsBuild.setBuildFlavor(mBuildFlavor);
+ }
addCompatibilitySuiteInfo(ctsBuild);
return ctsBuild;
}
@@ -103,7 +119,7 @@
} else {
String buildId = device.getBuildId();
String buildFlavor = device.getBuildFlavor();
- IBuildInfo info = new DeviceBuildInfo(buildId, mTestTag, buildFlavor);
+ IBuildInfo info = new DeviceBuildInfo(buildId, mTestTag);
if (mBranch == null) {
// if branch is not specified via param, make a pseudo branch name based on platform
// version and product info from device
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
index 70dc125..3eb93d4 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
@@ -61,6 +61,14 @@
* {@inheritDoc}
*/
@Override
+ public IAbi getAbi() {
+ return mAbi;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public File resolveRelativeFilePath(IBuildInfo buildInfo, String fileName) {
try {
File f = new File(getTestsDir(buildInfo),
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java
index d77d931..8e038fb 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java
@@ -37,7 +37,8 @@
public boolean postExecutionCheck(ITestDevice device) throws DeviceNotAvailableException {
if (!MonitoringUtils.checkDeviceConnectivity(device)) {
if (mIsFailed) {
- CLog.w("NetworkConnectivityChecker is still failing.");
+ CLog.w("NetworkConnectivityChecker is still failing on %s.",
+ device.getSerialNumber());
return true;
}
mIsFailed = true;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java
index 102d9c8..f1faee9 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java
@@ -20,6 +20,7 @@
import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.ITargetPreparer;
import com.android.tradefed.targetprep.TargetSetupError;
@@ -45,8 +46,7 @@
@Override
public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
BuildError, DeviceNotAvailableException {
- throw new TargetSetupError("TokenRequirement is not expected to run",
- device.getDeviceDescriptor());
+ CLog.e("TokenRequirement is not expected to run");
}
/**
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityHostTestBase.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityHostTestBase.java
index b2e2a33..bd4653b 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityHostTestBase.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityHostTestBase.java
@@ -77,6 +77,11 @@
}
@Override
+ public IAbi getAbi() {
+ return mAbi;
+ }
+
+ @Override
public void setBuild(IBuildInfo buildInfo) {
// Get the build, this is used to access the APK.
mBuild = buildInfo;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java
new file mode 100644
index 0000000..aecdd0e
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java
@@ -0,0 +1,274 @@
+/*
+ * 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.compatibility.common.tradefed.testtype.suite;
+
+import com.android.compatibility.SuiteInfo;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.testtype.ISubPlan;
+import com.android.compatibility.common.tradefed.testtype.ModuleRepo;
+import com.android.compatibility.common.tradefed.testtype.SubPlan;
+import com.android.compatibility.common.util.TestFilter;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.IConfiguration;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.Option.Importance;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.Abi;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.suite.ITestSuite;
+import com.android.tradefed.util.AbiFormatter;
+import com.android.tradefed.util.AbiUtils;
+import com.android.tradefed.util.ArrayUtil;
+import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A Test for running Compatibility Test Suite with new suite system.
+ */
+@OptionClass(alias = "compatibility")
+public class CompatibilityTestSuite extends ITestSuite {
+
+ private static final String INCLUDE_FILTER_OPTION = "include-filter";
+ private static final String EXCLUDE_FILTER_OPTION = "exclude-filter";
+ private static final String SUBPLAN_OPTION = "subplan";
+ private static final String MODULE_OPTION = "module";
+ private static final String TEST_OPTION = "test";
+ private static final String PRECONDITION_ARG_OPTION = "precondition-arg";
+ private static final String MODULE_ARG_OPTION = "module-arg";
+ private static final String TEST_ARG_OPTION = "test-arg";
+ private static final String ABI_OPTION = "abi";
+ private static final String SKIP_HOST_ARCH_CHECK = "skip-host-arch-check";
+ private static final String PRIMARY_ABI_RUN = "primary-abi-only";
+ private static final String PRODUCT_CPU_ABI_KEY = "ro.product.cpu.abi";
+
+ @Option(name = SUBPLAN_OPTION,
+ description = "the subplan to run",
+ importance = Importance.IF_UNSET)
+ private String mSubPlan;
+
+ @Option(name = INCLUDE_FILTER_OPTION,
+ description = "the include module filters to apply.",
+ importance = Importance.ALWAYS)
+ private Set<String> mIncludeFilters = new HashSet<>();
+
+ @Option(name = EXCLUDE_FILTER_OPTION,
+ description = "the exclude module filters to apply.",
+ importance = Importance.ALWAYS)
+ private Set<String> mExcludeFilters = new HashSet<>();
+
+ @Option(name = MODULE_OPTION,
+ shortName = 'm',
+ description = "the test module to run.",
+ importance = Importance.IF_UNSET)
+ private String mModuleName = null;
+
+ @Option(name = TEST_OPTION,
+ shortName = 't',
+ description = "the test to run.",
+ importance = Importance.IF_UNSET)
+ private String mTestName = null;
+
+ @Option(name = PRECONDITION_ARG_OPTION,
+ description = "the arguments to pass to a precondition. The expected format is "
+ + "\"<arg-name>:<arg-value>\"",
+ importance = Importance.ALWAYS)
+ private List<String> mPreconditionArgs = new ArrayList<>();
+
+ @Option(name = MODULE_ARG_OPTION,
+ description = "the arguments to pass to a module. The expected format is "
+ + "\"<module-name>:<arg-name>:<arg-value>\"",
+ importance = Importance.ALWAYS)
+ private List<String> mModuleArgs = new ArrayList<>();
+
+ @Option(name = TEST_ARG_OPTION,
+ description = "the arguments to pass to a test. The expected format is "
+ + "\"<test-class>:<arg-name>:<arg-value>\"",
+ importance = Importance.ALWAYS)
+ private List<String> mTestArgs = new ArrayList<>();
+
+ @Option(name = ABI_OPTION,
+ shortName = 'a',
+ description = "the abi to test.",
+ importance = Importance.IF_UNSET)
+ private String mAbiName = null;
+
+ @Option(name = SKIP_HOST_ARCH_CHECK,
+ description = "Whether host architecture check should be skipped")
+ private boolean mSkipHostArchCheck = false;
+
+ @Option(name = PRIMARY_ABI_RUN,
+ description = "Whether to run tests with only the device primary abi. "
+ + "This override the --abi option.")
+ private boolean mPrimaryAbiRun = false;
+
+ private ModuleRepoSuite mModuleRepo = new ModuleRepoSuite();
+ private CompatibilityBuildHelper mBuildHelper;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public LinkedHashMap<String, IConfiguration> loadTests() {
+ try {
+ setupFilters();
+ Set<IAbi> abis = getAbis(getDevice());
+ // Initialize the repository, {@link CompatibilityBuildHelper#getTestsDir} can
+ // throw a {@link FileNotFoundException}
+ return mModuleRepo.loadConfigs(mBuildHelper.getTestsDir(),
+ abis, mTestArgs, mModuleArgs, mIncludeFilters,
+ mExcludeFilters);
+ } catch (DeviceNotAvailableException | FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ super.setBuild(buildInfo);
+ mBuildHelper = new CompatibilityBuildHelper(buildInfo);
+ }
+
+ /**
+ * Gets the set of ABIs supported by both Compatibility and the device under test
+ *
+ * @return The set of ABIs to run the tests on
+ * @throws DeviceNotAvailableException
+ */
+ Set<IAbi> getAbis(ITestDevice device) throws DeviceNotAvailableException {
+ Set<IAbi> abis = new LinkedHashSet<>();
+ Set<String> archAbis = getAbisForBuildTargetArch();
+ if (mPrimaryAbiRun) {
+ if (mAbiName == null) {
+ // Get the primary from the device and make it the --abi to run.
+ mAbiName = device.getProperty(PRODUCT_CPU_ABI_KEY).trim();
+ } else {
+ CLog.d("Option --%s supersedes the option --%s, using abi: %s", ABI_OPTION,
+ PRIMARY_ABI_RUN, mAbiName);
+ }
+ }
+ if (mAbiName != null) {
+ // A particular abi was requested, it still needs to be supported by the build.
+ if ((!mSkipHostArchCheck && !archAbis.contains(mAbiName)) ||
+ !AbiUtils.isAbiSupportedByCompatibility(mAbiName)) {
+ throw new IllegalArgumentException(String.format("Your CTS hasn't been built with "
+ + "abi '%s' support, this CTS currently supports '%s'.",
+ mAbiName, archAbis));
+ } else {
+ abis.add(new Abi(mAbiName, AbiUtils.getBitness(mAbiName)));
+ return abis;
+ }
+ } else {
+ // Run on all abi in common between the device and CTS.
+ List<String> deviceAbis = Arrays.asList(AbiFormatter.getSupportedAbis(device, ""));
+ for (String abi : deviceAbis) {
+ if ((mSkipHostArchCheck || archAbis.contains(abi)) &&
+ AbiUtils.isAbiSupportedByCompatibility(abi)) {
+ abis.add(new Abi(abi, AbiUtils.getBitness(abi)));
+ } else {
+ CLog.d("abi '%s' is supported by device but not by this CTS build (%s), tests "
+ + "will not run against it.", abi, archAbis);
+ }
+ }
+ if (abis.isEmpty()) {
+ throw new IllegalArgumentException(String.format("None of the abi supported by this"
+ + " CTS build ('%s') are supported by the device ('%s').",
+ archAbis, deviceAbis));
+ }
+ return abis;
+ }
+ }
+
+ /**
+ * Return the abis supported by the Host build target architecture.
+ * Exposed for testing.
+ */
+ protected Set<String> getAbisForBuildTargetArch() {
+ return AbiUtils.getAbisForArch(SuiteInfo.TARGET_ARCH);
+ }
+
+ /**
+ * Sets the include/exclude filters up based on if a module name was given or whether this is a
+ * retry run.
+ */
+ void setupFilters() throws FileNotFoundException {
+ if (mSubPlan != null) {
+ try {
+ File subPlanFile = new File(mBuildHelper.getSubPlansDir(), mSubPlan + ".xml");
+ if (!subPlanFile.exists()) {
+ throw new IllegalArgumentException(
+ String.format("Could not retrieve subplan \"%s\"", mSubPlan));
+ }
+ InputStream subPlanInputStream = new FileInputStream(subPlanFile);
+ ISubPlan subPlan = new SubPlan();
+ subPlan.parse(subPlanInputStream);
+ mIncludeFilters.addAll(subPlan.getIncludeFilters());
+ mExcludeFilters.addAll(subPlan.getExcludeFilters());
+ } catch (ParseException e) {
+ throw new RuntimeException(
+ String.format("Unable to find or parse subplan %s", mSubPlan), e);
+ }
+ }
+ if (mModuleName != null) {
+ List<String> modules = ModuleRepo.getModuleNamesMatching(
+ mBuildHelper.getTestsDir(), mModuleName);
+ if (modules.size() == 0) {
+ throw new IllegalArgumentException(
+ String.format("No modules found matching %s", mModuleName));
+ } else if (modules.size() > 1) {
+ throw new IllegalArgumentException(String.format(
+ "Multiple modules found matching %s:\n%s\nWhich one did you mean?\n",
+ mModuleName, ArrayUtil.join("\n", modules)));
+ } else {
+ String moduleName = modules.get(0);
+ checkFilters(mIncludeFilters, moduleName);
+ checkFilters(mExcludeFilters, moduleName);
+ mIncludeFilters.add(new TestFilter(mAbiName, moduleName, mTestName).toString());
+ }
+ } else if (mTestName != null) {
+ throw new IllegalArgumentException(
+ "Test name given without module name. Add --module <module-name>");
+ }
+ }
+
+ /* Helper method designed to remove filters in a list not applicable to the given module */
+ private static void checkFilters(Set<String> filters, String moduleName) {
+ Set<String> cleanedFilters = new HashSet<String>();
+ for (String filter : filters) {
+ if (moduleName.equals(TestFilter.createFrom(filter).getName())) {
+ cleanedFilters.add(filter); // Module name matches, filter passes
+ }
+ }
+ filters.clear();
+ filters.addAll(cleanedFilters);
+ }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/ModuleRepoSuite.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/ModuleRepoSuite.java
new file mode 100644
index 0000000..acfb80b
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/ModuleRepoSuite.java
@@ -0,0 +1,300 @@
+/*
+ * 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.compatibility.common.tradefed.testtype.suite;
+
+import com.android.compatibility.common.util.TestFilter;
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.ConfigurationFactory;
+import com.android.tradefed.config.IConfiguration;
+import com.android.tradefed.config.IConfigurationFactory;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.ITestFileFilterReceiver;
+import com.android.tradefed.testtype.ITestFilterReceiver;
+import com.android.tradefed.util.AbiUtils;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.StreamUtil;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Retrieves Compatibility test module definitions from the repository.
+ */
+public class ModuleRepoSuite {
+
+ private static final String CONFIG_EXT = ".config";
+ private Map<String, Map<String, List<String>>> mTestArgs = new HashMap<>();
+ private Map<String, Map<String, List<String>>> mModuleArgs = new HashMap<>();
+ private boolean mIncludeAll;
+ private Map<String, List<TestFilter>> mIncludeFilters = new HashMap<>();
+ private Map<String, List<TestFilter>> mExcludeFilters = new HashMap<>();
+ private IConfigurationFactory mConfigFactory = ConfigurationFactory.getInstance();
+
+ /**
+ * Main loading of configurations, looking into testcases/ folder
+ */
+ public LinkedHashMap<String, IConfiguration> loadConfigs(File testsDir, Set<IAbi> abis,
+ List<String> testArgs, List<String> moduleArgs,
+ Set<String> includeFilters, Set<String> excludeFilters) {
+ CLog.d("Initializing ModuleRepo\nTests Dir:%s\nABIs:%s\n" +
+ "Test Args:%s\nModule Args:%s\nIncludes:%s\nExcludes:%s",
+ testsDir.getAbsolutePath(), abis, testArgs, moduleArgs,
+ includeFilters, excludeFilters);
+
+ LinkedHashMap<String, IConfiguration> toRun = new LinkedHashMap<>();
+
+ putArgs(testArgs, mTestArgs);
+ putArgs(moduleArgs, mModuleArgs);
+ mIncludeAll = includeFilters.isEmpty();
+ // Include all the inclusions
+ addFilters(includeFilters, mIncludeFilters, abis);
+ // Exclude all the exclusions
+ addFilters(excludeFilters, mExcludeFilters, abis);
+
+ File[] configFiles = testsDir.listFiles(new ConfigFilter());
+ if (configFiles.length == 0) {
+ throw new IllegalArgumentException(
+ String.format("No config files found in %s", testsDir.getAbsolutePath()));
+ }
+ for (File configFile : configFiles) {
+ final String name = configFile.getName().replace(CONFIG_EXT, "");
+ final String[] pathArg = new String[] { configFile.getAbsolutePath() };
+ try {
+ // Invokes parser to process the test module config file
+ // Need to generate a different config for each ABI as we cannot guarantee the
+ // configs are idempotent. This however means we parse the same file multiple times
+ for (IAbi abi : abis) {
+ IConfiguration config = mConfigFactory.createConfigurationFromArgs(pathArg);
+ String id = AbiUtils.createId(abi.getName(), name);
+ if (!shouldRunModule(id)) {
+ // If the module should not run tests based on the state of filters,
+ // skip this name/abi combination.
+ continue;
+ }
+
+ Map<String, List<String>> args = new HashMap<>();
+ if (mModuleArgs.containsKey(name)) {
+ args.putAll(mModuleArgs.get(name));
+ }
+ if (mModuleArgs.containsKey(id)) {
+ args.putAll(mModuleArgs.get(id));
+ }
+ for (Entry<String, List<String>> entry : args.entrySet()) {
+ for (String value : entry.getValue()) {
+ // Collection-type options can be injected with multiple values
+ config.injectOptionValue(entry.getKey(), value);
+ }
+ }
+
+ List<IRemoteTest> tests = config.getTests();
+ for (IRemoteTest test : tests) {
+ String className = test.getClass().getName();
+ Map<String, List<String>> testArgsMap = new HashMap<>();
+ if (mTestArgs.containsKey(className)) {
+ testArgsMap.putAll(mTestArgs.get(className));
+ }
+ for (Entry<String, List<String>> entry : testArgsMap.entrySet()) {
+ for (String value : entry.getValue()) {
+ config.injectOptionValue(entry.getKey(), value);
+ }
+ }
+ addFiltersToTest(test, abi, name);
+ if (test instanceof IAbiReceiver) {
+ ((IAbiReceiver)test).setAbi(abi);
+ }
+ }
+ List<ITargetPreparer> preparers = config.getTargetPreparers();
+ for (ITargetPreparer preparer : preparers) {
+ if (preparer instanceof IAbiReceiver) {
+ ((IAbiReceiver)preparer).setAbi(abi);
+ }
+ }
+ toRun.put(id, config);
+ }
+ } catch (ConfigurationException e) {
+ throw new RuntimeException(String.format("Error parsing config file: %s",
+ configFile.getName()), e);
+ }
+ }
+ return toRun;
+ }
+
+ private void addFilters(Set<String> stringFilters,
+ Map<String, List<TestFilter>> filters, Set<IAbi> abis) {
+ for (String filterString : stringFilters) {
+ TestFilter filter = TestFilter.createFrom(filterString);
+ String abi = filter.getAbi();
+ if (abi == null) {
+ for (IAbi a : abis) {
+ addFilter(a.getName(), filter, filters);
+ }
+ } else {
+ addFilter(abi, filter, filters);
+ }
+ }
+ }
+
+ private void addFilter(String abi, TestFilter filter,
+ Map<String, List<TestFilter>> filters) {
+ getFilterList(filters, AbiUtils.createId(abi, filter.getName())).add(filter);
+ }
+
+ private List<TestFilter> getFilterList(Map<String, List<TestFilter>> filters, String id) {
+ List<TestFilter> fs = filters.get(id);
+ if (fs == null) {
+ fs = new ArrayList<>();
+ filters.put(id, fs);
+ }
+ return fs;
+ }
+
+ private void addFiltersToTest(IRemoteTest test, IAbi abi, String name) {
+ String moduleId = AbiUtils.createId(abi.getName(), name);
+ if (!(test instanceof ITestFilterReceiver)) {
+ throw new IllegalArgumentException(String.format(
+ "Test in module %s must implement ITestFilterReceiver.", moduleId));
+ }
+ List<TestFilter> mdIncludes = getFilterList(mIncludeFilters, moduleId);
+ List<TestFilter> mdExcludes = getFilterList(mExcludeFilters, moduleId);
+ if (!mdIncludes.isEmpty()) {
+ addTestIncludes((ITestFilterReceiver) test, mdIncludes, name);
+ }
+ if (!mdExcludes.isEmpty()) {
+ addTestExcludes((ITestFilterReceiver) test, mdExcludes, name);
+ }
+ }
+
+ private boolean shouldRunModule(String moduleId) {
+ List<TestFilter> mdIncludes = getFilterList(mIncludeFilters, moduleId);
+ List<TestFilter> mdExcludes = getFilterList(mExcludeFilters, moduleId);
+ // if including all modules or includes exist for this module, and there are not excludes
+ // for the entire module, this module should be run.
+ return (mIncludeAll || !mdIncludes.isEmpty()) && !containsModuleExclude(mdExcludes);
+ }
+
+ private void addTestIncludes(ITestFilterReceiver test, List<TestFilter> includes,
+ String name) {
+ if (test instanceof ITestFileFilterReceiver) {
+ File includeFile = createFilterFile(name, ".include", includes);
+ ((ITestFileFilterReceiver)test).setIncludeTestFile(includeFile);
+ } else {
+ // add test includes one at a time
+ for (TestFilter include : includes) {
+ String filterTestName = include.getTest();
+ if (filterTestName != null) {
+ test.addIncludeFilter(filterTestName);
+ }
+ }
+ }
+ }
+
+ private void addTestExcludes(ITestFilterReceiver test, List<TestFilter> excludes,
+ String name) {
+ if (test instanceof ITestFileFilterReceiver) {
+ File excludeFile = createFilterFile(name, ".exclude", excludes);
+ ((ITestFileFilterReceiver)test).setExcludeTestFile(excludeFile);
+ } else {
+ // add test excludes one at a time
+ for (TestFilter exclude : excludes) {
+ test.addExcludeFilter(exclude.getTest());
+ }
+ }
+ }
+
+ private File createFilterFile(String prefix, String suffix, List<TestFilter> filters) {
+ File filterFile = null;
+ PrintWriter out = null;
+ try {
+ filterFile = FileUtil.createTempFile(prefix, suffix);
+ out = new PrintWriter(filterFile);
+ for (TestFilter filter : filters) {
+ String filterTest = filter.getTest();
+ if (filterTest != null) {
+ out.println(filterTest);
+ }
+ }
+ out.flush();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to create filter file");
+ } finally {
+ StreamUtil.close(out);
+ }
+ filterFile.deleteOnExit();
+ return filterFile;
+ }
+
+ /**
+ * Returns true iff one or more test filters in excludes apply to the entire module.
+ */
+ private boolean containsModuleExclude(Collection<TestFilter> excludes) {
+ for (TestFilter exclude : excludes) {
+ if (exclude.getTest() == null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A {@link FilenameFilter} to find all the config files in a directory.
+ */
+ public static class ConfigFilter implements FilenameFilter {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean accept(File dir, String name) {
+ CLog.d("%s/%s", dir.getAbsolutePath(), name);
+ return name.endsWith(CONFIG_EXT);
+ }
+ }
+
+ private static void putArgs(List<String> args,
+ Map<String, Map<String, List<String>>> argsMap) {
+ for (String arg : args) {
+ String[] parts = arg.split(":");
+ String target = parts[0];
+ String key = parts[1];
+ String value = parts[2];
+ Map<String, List<String>> map = argsMap.get(target);
+ if (map == null) {
+ map = new HashMap<>();
+ argsMap.put(target, map);
+ }
+ List<String> valueList = map.get(key);
+ if (valueList == null) {
+ valueList = new ArrayList<>();
+ map.put(key, valueList);
+ }
+ valueList.add(value);
+ }
+ }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
index c42c410..fc04085 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
@@ -36,6 +36,7 @@
import com.android.compatibility.common.tradefed.testtype.ModuleRepoTest;
import com.android.compatibility.common.tradefed.testtype.SubPlanTest;
import com.android.compatibility.common.tradefed.testtype.retry.RetryFactoryTestTest;
+import com.android.compatibility.common.tradefed.testtype.suite.CompatibilityTestSuiteTest;
import com.android.compatibility.common.tradefed.util.CollectorUtilTest;
import com.android.compatibility.common.tradefed.util.OptionHelperTest;
import com.android.compatibility.common.tradefed.util.RetryFilterHelperTest;
@@ -89,6 +90,9 @@
// testtype.retry
RetryFactoryTestTest.class,
+ // testype.suite
+ CompatibilityTestSuiteTest.class,
+
// util
CollectorUtilTest.class,
OptionHelperTest.class,
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
index 4aa67ac..356207e 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
@@ -104,6 +104,11 @@
}
@Override
+ public IAbi getAbi() {
+ return null;
+ }
+
+ @Override
public long getRuntimeHint() {
return 1L;
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
index 504d5e9..edee5eb 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
@@ -430,6 +430,8 @@
public void setCollectTestsOnly(boolean arg0) {}
@Override
public void setAbi(IAbi arg0) {}
+ @Override
+ public IAbi getAbi() {return null;}
}
/**
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
index 1a63b03..7b43972 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
@@ -90,6 +90,11 @@
}
@Override
+ public IAbi getAbi() {
+ return null;
+ }
+
+ @Override
public long getRuntimeHint() {
return 1L;
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java
index 6f199ae..a154f31 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java
@@ -132,6 +132,11 @@
}
@Override
+ public IAbi getAbi() {
+ return null;
+ }
+
+ @Override
public long getRuntimeHint() {
return 1L;
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuiteTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuiteTest.java
new file mode 100644
index 0000000..86569ef
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuiteTest.java
@@ -0,0 +1,179 @@
+/*
+ * 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.compatibility.common.tradefed.testtype.suite;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.util.AbiUtils;
+
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link CompatibilityTestSuite}.
+ */
+public class CompatibilityTestSuiteTest {
+
+ private static final String FAKE_HOST_ARCH = "arm";
+ private CompatibilityTestSuite mTest;
+ private ITestDevice mMockDevice;
+
+ @Before
+ public void setUp() throws Exception {
+ mTest = new CompatibilityTestSuite() {
+ @Override
+ protected Set<String> getAbisForBuildTargetArch() {
+ return AbiUtils.getAbisForArch(FAKE_HOST_ARCH);
+ }
+ };
+ mMockDevice = EasyMock.createMock(ITestDevice.class);
+ mTest.setDevice(mMockDevice);
+ }
+
+ /**
+ * Test that {@link CompatibilityTestSuite#getAbis(ITestDevice)} is returning a proper
+ * intersection of CTS supported architectures and Device supported architectures.
+ */
+ @Test
+ public void testGetAbis() throws DeviceNotAvailableException {
+ EasyMock.expect(mMockDevice.getProperty(EasyMock.eq("ro.product.cpu.abilist")))
+ .andReturn("arm64-v8a,armeabi-v7a,armeabi");
+ Set<String> expectedAbis = new HashSet<>();
+ expectedAbis.add("arm64-v8a");
+ expectedAbis.add("armeabi-v7a");
+ EasyMock.replay(mMockDevice);
+ Set<IAbi> res = mTest.getAbis(mMockDevice);
+ assertEquals(2, res.size());
+ for (IAbi abi : res) {
+ assertTrue(expectedAbis.contains(abi.getName()));
+ }
+ EasyMock.verify(mMockDevice);
+ }
+
+ /**
+ * Test that {@link CompatibilityTestSuite#getAbis(ITestDevice)} is throwing an exception when
+ * none of the CTS build supported abi match the device abi.
+ */
+ @Test
+ public void testGetAbis_notSupported() throws DeviceNotAvailableException {
+ EasyMock.expect(mMockDevice.getProperty(EasyMock.eq("ro.product.cpu.abilist")))
+ .andReturn("armeabi");
+ EasyMock.replay(mMockDevice);
+ try {
+ mTest.getAbis(mMockDevice);
+ fail("Should have thrown an exception");
+ } catch (IllegalArgumentException e) {
+ assertEquals("None of the abi supported by this CTS build ('[armeabi-v7a, arm64-v8a]')"
+ + " are supported by the device ('[armeabi]').", e.getMessage());
+ }
+ EasyMock.verify(mMockDevice);
+ }
+
+ /**
+ * Test that {@link CompatibilityTestSuite#getAbis(ITestDevice)} is returning only the device
+ * primary abi.
+ */
+ @Test
+ public void testGetAbis_primaryAbiOnly() throws Exception {
+ OptionSetter setter = new OptionSetter(mTest);
+ setter.setOptionValue(CompatibilityTest.PRIMARY_ABI_RUN, "true");
+ EasyMock.expect(mMockDevice.getProperty(EasyMock.eq("ro.product.cpu.abi")))
+ .andReturn("arm64-v8a");
+ Set<String> expectedAbis = new HashSet<>();
+ expectedAbis.add("arm64-v8a");
+ EasyMock.replay(mMockDevice);
+ Set<IAbi> res = mTest.getAbis(mMockDevice);
+ assertEquals(1, res.size());
+ for (IAbi abi : res) {
+ assertTrue(expectedAbis.contains(abi.getName()));
+ }
+ EasyMock.verify(mMockDevice);
+ }
+
+ /**
+ * Test that {@link CompatibilityTestSuite#getAbis(ITestDevice)} is throwing an exception if
+ * the primary abi is not supported.
+ */
+ @Test
+ public void testGetAbis_primaryAbiOnly_NotSupported() throws Exception {
+ OptionSetter setter = new OptionSetter(mTest);
+ setter.setOptionValue(CompatibilityTest.PRIMARY_ABI_RUN, "true");
+ EasyMock.expect(mMockDevice.getProperty(EasyMock.eq("ro.product.cpu.abi")))
+ .andReturn("armeabi");
+ EasyMock.replay(mMockDevice);
+ try {
+ mTest.getAbis(mMockDevice);
+ fail("Should have thrown an exception");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Your CTS hasn't been built with abi 'armeabi' support, "
+ + "this CTS currently supports '[armeabi-v7a, arm64-v8a]'.", e.getMessage());
+ }
+ EasyMock.verify(mMockDevice);
+ }
+
+ /**
+ * Test that {@link CompatibilityTestSuite#getAbis(ITestDevice)} is returning the list of abi
+ * supported by Compatibility and the device, and not the particular CTS build.
+ */
+ @Test
+ public void testGetAbis_skipCtsArchCheck() throws Exception {
+ OptionSetter setter = new OptionSetter(mTest);
+ setter.setOptionValue(CompatibilityTest.SKIP_HOST_ARCH_CHECK, "true");
+ EasyMock.expect(mMockDevice.getProperty(EasyMock.eq("ro.product.cpu.abilist")))
+ .andReturn("x86_64,x86,armeabi");
+ Set<String> expectedAbis = new HashSet<>();
+ expectedAbis.add("x86_64");
+ expectedAbis.add("x86");
+ EasyMock.replay(mMockDevice);
+ Set<IAbi> res = mTest.getAbis(mMockDevice);
+ assertEquals(2, res.size());
+ for (IAbi abi : res) {
+ assertTrue(expectedAbis.contains(abi.getName()));
+ }
+ EasyMock.verify(mMockDevice);
+ }
+
+ /**
+ * Test {@link CompatibilityTestSuite#getAbis(ITestDevice)} when we skip the Cts side
+ * architecture check and want to run x86 abi.
+ */
+ @Test
+ public void testGetAbis_skipCtsArchCheck_abiSpecified() throws Exception {
+ OptionSetter setter = new OptionSetter(mTest);
+ setter.setOptionValue(CompatibilityTest.SKIP_HOST_ARCH_CHECK, "true");
+ setter.setOptionValue(CompatibilityTest.ABI_OPTION, "x86");
+ Set<String> expectedAbis = new HashSet<>();
+ expectedAbis.add("x86");
+ EasyMock.replay(mMockDevice);
+ Set<IAbi> res = mTest.getAbis(mMockDevice);
+ assertEquals(1, res.size());
+ for (IAbi abi : res) {
+ assertTrue(expectedAbis.contains(abi.getName()));
+ }
+ EasyMock.verify(mMockDevice);
+ }
+}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/MonitoringUtils.java b/common/host-side/util/src/com/android/compatibility/common/util/MonitoringUtils.java
index e24ca40..148a9a5 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/MonitoringUtils.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/MonitoringUtils.java
@@ -42,7 +42,8 @@
return true;
} else {
CLog.logAndDisplay(LogLevel.INFO,
- "Connectivity check failed, retrying in %dms",
+ "Connectivity check failed on %s, retrying in %dms",
+ device.getSerialNumber(),
CONNECTIVITY_CHECK_INTERVAL_MS);
RunUtil.getDefault().sleep(CONNECTIVITY_CHECK_INTERVAL_MS);
}
diff --git a/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java b/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
index 6894a21..f042a89 100644
--- a/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
+++ b/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
@@ -31,6 +31,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import java.util.zip.ZipFile;
/**
@@ -80,6 +81,8 @@
RemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(mTestPackageName, RUNNER,
device.getIDevice());
+ // set a max deadline limit to avoid hanging forever
+ runner.setMaxTimeToOutputResponse(2, TimeUnit.MINUTES);
TestResults tr = new TestResults(new AttachAgent(device, mTestPackageName, mTestApk));
diff --git a/hostsidetests/monkey/src/com/android/cts/monkey/CategoryTest.java b/hostsidetests/monkey/src/com/android/cts/monkey/CategoryTest.java
index ff04f6c..f3bb5d9 100644
--- a/hostsidetests/monkey/src/com/android/cts/monkey/CategoryTest.java
+++ b/hostsidetests/monkey/src/com/android/cts/monkey/CategoryTest.java
@@ -16,31 +16,73 @@
package com.android.cts.monkey;
+import com.android.tradefed.device.CollectingOutputReceiver;
+
+import java.util.concurrent.TimeUnit;
+
public class CategoryTest extends AbstractMonkeyTest {
+ private static final long MAX_TIMEOUT = 5 * 60 * 1000; // 5 min
+
public void testDefaultCategories() throws Exception {
- String out = mDevice.executeShellCommand(MONKEY_CMD + " -v -p " + PKGS[0] + " 5000");
- assertTrue(out.contains("cmp=com.android.cts.monkey/.MonkeyActivity"));
- assertTrue(out.contains("cmp=com.android.cts.monkey/.BaboonActivity"));
+ String cmd = MONKEY_CMD + " -v -p " + PKGS[0] + " 5000";
+ CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+ try {
+ mDevice.executeShellCommand(cmd, receiver, MAX_TIMEOUT, TimeUnit.MILLISECONDS, 0);
+ String out = receiver.getOutput();
+ assertTrue(out.contains("cmp=com.android.cts.monkey/.MonkeyActivity"));
+ assertTrue(out.contains("cmp=com.android.cts.monkey/.BaboonActivity"));
+ } finally {
+ receiver.cancel();
+ receiver.clearBuffer();
+ receiver = null;
+ }
}
public void testSingleCategory() throws Exception {
- String out = mDevice.executeShellCommand(MONKEY_CMD + " -v -p " + PKGS[0]
- + " -c android.intent.category.LAUNCHER 5000");
- assertTrue(out.contains("cmp=com.android.cts.monkey/.MonkeyActivity"));
- assertFalse(out.contains("cmp=com.android.cts.monkey/.BaboonActivity"));
+ String cmd = MONKEY_CMD + " -v -p " + PKGS[0]
+ + " -c android.intent.category.LAUNCHER 5000";
+ CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+ try {
+ mDevice.executeShellCommand(cmd, receiver, MAX_TIMEOUT, TimeUnit.MILLISECONDS, 0);
+ String out = receiver.getOutput();
+ assertTrue(out.contains("cmp=com.android.cts.monkey/.MonkeyActivity"));
+ assertFalse(out.contains("cmp=com.android.cts.monkey/.BaboonActivity"));
+ } finally {
+ receiver.cancel();
+ receiver.clearBuffer();
+ receiver = null;
+ }
- out = mDevice.executeShellCommand(MONKEY_CMD + " -v -p " + PKGS[0]
- + " -c android.intent.category.MONKEY 5000");
- assertFalse(out.contains("cmp=com.android.cts.monkey/.MonkeyActivity"));
- assertTrue(out.contains("cmp=com.android.cts.monkey/.BaboonActivity"));
+ CollectingOutputReceiver receiver2 = new CollectingOutputReceiver();
+ try {
+ mDevice.executeShellCommand(MONKEY_CMD + " -v -p " + PKGS[0]
+ + " -c android.intent.category.MONKEY 5000", receiver2, MAX_TIMEOUT,
+ TimeUnit.MILLISECONDS, 0);
+ String out = receiver2.getOutput();
+ assertFalse(out.contains("cmp=com.android.cts.monkey/.MonkeyActivity"));
+ assertTrue(out.contains("cmp=com.android.cts.monkey/.BaboonActivity"));
+ } finally {
+ receiver2.cancel();
+ receiver2.clearBuffer();
+ receiver2 = null;
+ }
}
public void testMultipleCategories() throws Exception {
- String out = mDevice.executeShellCommand(MONKEY_CMD + " -v -p " + PKGS[0]
+ String cmd = MONKEY_CMD + " -v -p " + PKGS[0]
+ " -c android.intent.category.LAUNCHER"
- + " -c android.intent.category.MONKEY 5000");
- assertTrue(out.contains("cmp=com.android.cts.monkey/.MonkeyActivity"));
- assertTrue(out.contains("cmp=com.android.cts.monkey/.BaboonActivity"));
+ + " -c android.intent.category.MONKEY 5000";
+ CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+ try {
+ mDevice.executeShellCommand(cmd, receiver, MAX_TIMEOUT, TimeUnit.MILLISECONDS, 0);
+ String out = receiver.getOutput();
+ assertTrue(out.contains("cmp=com.android.cts.monkey/.MonkeyActivity"));
+ assertTrue(out.contains("cmp=com.android.cts.monkey/.BaboonActivity"));
+ } finally {
+ receiver.cancel();
+ receiver.clearBuffer();
+ receiver = null;
+ }
}
}
diff --git a/hostsidetests/monkey/src/com/android/cts/monkey/MonkeyTest.java b/hostsidetests/monkey/src/com/android/cts/monkey/MonkeyTest.java
index 997f7c6..0241879 100644
--- a/hostsidetests/monkey/src/com/android/cts/monkey/MonkeyTest.java
+++ b/hostsidetests/monkey/src/com/android/cts/monkey/MonkeyTest.java
@@ -16,6 +16,7 @@
package com.android.cts.monkey;
+import com.android.ddmlib.NullOutputReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
import java.util.Scanner;
@@ -32,7 +33,8 @@
public void testNotMonkey() throws Exception {
mDevice.executeShellCommand("am start -W -a android.intent.action.MAIN "
- + "-n com.android.cts.monkey/com.android.cts.monkey.MonkeyActivity");
+ + "-n com.android.cts.monkey/com.android.cts.monkey.MonkeyActivity",
+ new NullOutputReceiver());
assertIsUserAMonkey(false);
}
diff --git a/hostsidetests/monkey/src/com/android/cts/monkey/PackageTest.java b/hostsidetests/monkey/src/com/android/cts/monkey/PackageTest.java
index 986304c..b3a22d6 100644
--- a/hostsidetests/monkey/src/com/android/cts/monkey/PackageTest.java
+++ b/hostsidetests/monkey/src/com/android/cts/monkey/PackageTest.java
@@ -16,10 +16,14 @@
package com.android.cts.monkey;
+import com.android.tradefed.device.CollectingOutputReceiver;
+
+import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
public class PackageTest extends AbstractMonkeyTest {
+ private static final long MAX_TIMEOUT = 5 * 60 * 1000; // 5 min
private static final int MAX_ERROR_LENGTH = 256;
private static final Pattern ALLOW_MONKEY =
Pattern.compile("^.*Allowing.*cmp=com\\.android\\.cts\\.monkey/\\.MonkeyActivity.*$",
@@ -30,23 +34,49 @@
Pattern.MULTILINE);
public void testSinglePackage() throws Exception {
- String out = mDevice.executeShellCommand(MONKEY_CMD + " -v -p " + PKGS[0] + " 5000");
- String error = truncateError(out);
- assertTrue("Monkey not found in: " + error, ALLOW_MONKEY.matcher(out).find());
- assertFalse("Chimp found in: " + error, ALLOW_CHIMP.matcher(out).find());
+ String cmd = MONKEY_CMD + " -v -p " + PKGS[0] + " 5000";
+ CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+ try {
+ mDevice.executeShellCommand(cmd, receiver, MAX_TIMEOUT, TimeUnit.MILLISECONDS, 0);
+ String out = receiver.getOutput();
+ String error = truncateError(out);
+ assertTrue("Monkey not found in: " + error, ALLOW_MONKEY.matcher(out).find());
+ assertFalse("Chimp found in: " + error, ALLOW_CHIMP.matcher(out).find());
+ } finally {
+ receiver.cancel();
+ receiver.clearBuffer();
+ receiver = null;
+ }
- out = mDevice.executeShellCommand(MONKEY_CMD + " -v -p " + PKGS[1] + " 5000");
- error = truncateError(out);
- assertFalse("Monkey found in: " + error, ALLOW_MONKEY.matcher(out).find());
- assertTrue("Chimp not found in: " + error, ALLOW_CHIMP.matcher(out).find());
+ String cmd2 = MONKEY_CMD + " -v -p " + PKGS[1] + " 5000";
+ CollectingOutputReceiver receiver2 = new CollectingOutputReceiver();
+ try {
+ mDevice.executeShellCommand(cmd2, receiver2, MAX_TIMEOUT, TimeUnit.MILLISECONDS, 0);
+ String out = receiver2.getOutput();
+ String error = truncateError(out);
+ assertFalse("Monkey found in: " + error, ALLOW_MONKEY.matcher(out).find());
+ assertTrue("Chimp not found in: " + error, ALLOW_CHIMP.matcher(out).find());
+ } finally {
+ receiver2.cancel();
+ receiver2.clearBuffer();
+ receiver2 = null;
+ }
}
public void testMultiplePackages() throws Exception {
- String out = mDevice.executeShellCommand(MONKEY_CMD + " -v -p " + PKGS[0]
- + " -p " + PKGS[1] + " 5000");
- String error = truncateError(out);
- assertTrue("Monkey not found in: " + error, ALLOW_MONKEY.matcher(out).find());
- assertTrue("Chimp not found in: " + error, ALLOW_CHIMP.matcher(out).find());
+ String cmd = MONKEY_CMD + " -v -p " + PKGS[0] + " -p " + PKGS[1] + " 5000";
+ CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+ try {
+ mDevice.executeShellCommand(cmd, receiver, MAX_TIMEOUT, TimeUnit.MILLISECONDS, 0);
+ String out = receiver.getOutput();
+ String error = truncateError(out);
+ assertTrue("Monkey not found in: " + error, ALLOW_MONKEY.matcher(out).find());
+ assertTrue("Chimp not found in: " + error, ALLOW_CHIMP.matcher(out).find());
+ } finally {
+ receiver.cancel();
+ receiver.clearBuffer();
+ receiver = null;
+ }
}
private static final String truncateError(String input) {
diff --git a/hostsidetests/monkey/src/com/android/cts/monkey/SeedTest.java b/hostsidetests/monkey/src/com/android/cts/monkey/SeedTest.java
index a0016e2..973e986 100644
--- a/hostsidetests/monkey/src/com/android/cts/monkey/SeedTest.java
+++ b/hostsidetests/monkey/src/com/android/cts/monkey/SeedTest.java
@@ -25,7 +25,9 @@
String out1 = mDevice.executeShellCommand(cmd1);
String out2 = mDevice.executeShellCommand(cmd1);
assertOutputs(out1, out2);
+ }
+ public void testSeed2() throws Exception {
String cmd2 = MONKEY_CMD + " -s 3007 -v -p " + PKGS[0] + " 125";
String out3 = mDevice.executeShellCommand(cmd2);
String out4 = mDevice.executeShellCommand(cmd2);
diff --git a/tests/jdwp/runner/host-side/src/com/android/compatibility/testtype/DalvikTest.java b/tests/jdwp/runner/host-side/src/com/android/compatibility/testtype/DalvikTest.java
index fb86862..6abc6d7 100644
--- a/tests/jdwp/runner/host-side/src/com/android/compatibility/testtype/DalvikTest.java
+++ b/tests/jdwp/runner/host-side/src/com/android/compatibility/testtype/DalvikTest.java
@@ -182,6 +182,14 @@
* {@inheritDoc}
*/
@Override
+ public IAbi getAbi() {
+ return mAbi;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public void setBuild(IBuildInfo build) {
mBuildHelper = new CompatibilityBuildHelper(build);
}
@@ -464,6 +472,7 @@
// A DalvikTest to run any tests not contained in packages from TEST_PACKAGES, may be empty
DalvikTest catchAll = new DalvikTest();
OptionCopier.copyOptionsNoThrow(this, catchAll);
+ catchAll.mAbi = mAbi;
shards.add(catchAll);
// estimate catchAll's runtime to be that of a single package in TEST_PACKAGES
long runtimeHint = mRuntimeHint / TEST_PACKAGES.size();
@@ -474,7 +483,8 @@
DalvikTest test = new DalvikTest();
OptionCopier.copyOptionsNoThrow(this, test);
test.addIncludeFilter(packageName);
- test.mRuntimeHint = runtimeHint;
+ test.mRuntimeHint = runtimeHint / TEST_PACKAGES.size();
+ test.mAbi = mAbi;
shards.add(test);
}
// return a shard for each package in TEST_PACKAGE, plus a shard for any other tests
diff --git a/tests/libcore/javautilcollections/AndroidTest.xml b/tests/libcore/javautilcollections/AndroidTest.xml
index 016285f..40800cd 100644
--- a/tests/libcore/javautilcollections/AndroidTest.xml
+++ b/tests/libcore/javautilcollections/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,6 +14,7 @@
limitations under the License.
-->
<configuration description="Config for CTS Libcore java.util Collection test cases">
+ <option name="not-shardable" value="true" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsLibcoreJavaUtilCollectionsTestCases.apk" />
@@ -66,4 +68,4 @@
<option name="test-timeout" value="1200000" />
<option name="shell-timeout" value="1400000" />
</test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-suite.xml b/tools/cts-tradefed/res/config/cts-suite.xml
new file mode 100644
index 0000000..c75072c
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-suite.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs CTS as a suite">
+ <!-- running config -->
+ <build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
+ <test class="com.android.compatibility.common.tradefed.testtype.suite.CompatibilityTestSuite" />
+
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:rerun-from-file:true" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:fallback-to-serial-rerun:false" />
+
+ <logger class="com.android.tradefed.log.FileLogger">
+ <option name="log-level-display" value="WARN" />
+ </logger>
+ <!-- setup configs -->
+ <include name="cts-preconditions" />
+ <include name="cts-system-checkers" />
+ <include name="cts-known-failures" />
+
+ <option name="plan" value="cts-suite" />
+ <option name="test-tag" value="cts-suite" />
+
+ <option name="enable-root" value="false" />
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.PropertyCheck">
+ <option name="property-name" value="ro.build.type" />
+ <option name="expected-value" value="user"/> <!-- Device should have user build -->
+ <option name="throw-error" value="false"/> <!-- Only print warning if not user build -->
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.PropertyCheck">
+ <option name="property-name" value="ro.product.locale" />
+ <option name="expected-value" value="en-US"/> <!-- Device locale should be US English -->
+ <option name="throw-error" value="false"/> <!-- Only print warning if not en-US -->
+ </target_preparer>
+
+ <template-include name="reporters" default="basic-reporters" />
+
+ <result_reporter class="com.android.compatibility.common.tradefed.result.ResultReporter" />
+ <result_reporter class="com.android.tradefed.result.suite.SuiteResultReporter" />
+</configuration>