TestMappingSuiteRunner: Run tests in TestMapping base on option
test-mapping-path.
This CL is to run with multiple test options defined in TEST_MAPPING file
for presubmit tests. In the past, these test options were merged in the
Test Provider Service and might lose some test coverage. The design doc:
go/run-test-mapping-presubmit-tests
Bug: 117880789
Test: unittests.
Change-Id: I0451012a36485a61c0c552ed48276baa86304de9
Merged-In: I0451012a36485a61c0c552ed48276baa86304de9
diff --git a/src/com/android/tradefed/testtype/suite/TestMappingSuiteRunner.java b/src/com/android/tradefed/testtype/suite/TestMappingSuiteRunner.java
index 8eab13f..d32a1fc 100644
--- a/src/com/android/tradefed/testtype/suite/TestMappingSuiteRunner.java
+++ b/src/com/android/tradefed/testtype/suite/TestMappingSuiteRunner.java
@@ -126,8 +126,16 @@
"If options --test-mapping-test-group is set, option --include-filter should "
+ "not be set.");
}
+ if (!includeFilter.isEmpty() && !mTestMappingPaths.isEmpty()) {
+ throw new RuntimeException(
+ "If option --include-filter is set, option --test-mapping-path should "
+ + "not be set.");
+ }
if (mTestGroup != null) {
+ if (!mTestMappingPaths.isEmpty()) {
+ TestMapping.setTestMappingPaths(mTestMappingPaths);
+ }
testInfosToRun =
TestMapping.getTests(
getBuildInfo(), mTestGroup, getPrioritizeHostConfig(), mKeywords);
diff --git a/src/com/android/tradefed/util/testmapping/TestMapping.java b/src/com/android/tradefed/util/testmapping/TestMapping.java
index a550ec0..93419c0 100644
--- a/src/com/android/tradefed/util/testmapping/TestMapping.java
+++ b/src/com/android/tradefed/util/testmapping/TestMapping.java
@@ -34,6 +34,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
@@ -70,6 +71,20 @@
"(?m)[\\s\\t]*(//|#).*|(\".*?\")");
private static final Set<String> COMMENTS = new HashSet<>(Arrays.asList("#", "//"));
+ private static List<String> mTestMappingRelativePaths = new ArrayList<>();
+
+ /**
+ * Set the TEST_MAPPING paths inside of TEST_MAPPINGS_ZIP to limit loading the TEST_MAPPING.
+ *
+ * @param relativePaths A {@code List<String>} of TEST_MAPPING paths relative to
+ * TEST_MAPPINGS_ZIP.
+ */
+ public static void setTestMappingPaths(List<String> relativePaths) {
+ mTestMappingRelativePaths.clear();
+ mTestMappingRelativePaths.addAll(relativePaths);
+ }
+
+
/**
* Constructor to create a {@link TestMapping} object from a path to TEST_MAPPING file.
*
@@ -246,6 +261,39 @@
}
/**
+ * Helper to get all TEST_MAPPING paths relative to TEST_MAPPINGS_ZIP.
+ *
+ * @param testMappingsRootPath The {@link Path} to a test mappings zip path.
+ * @return A {@code Set<Path>} of all the TEST_MAPPING paths relative to TEST_MAPPINGS_ZIP.
+ */
+ @VisibleForTesting
+ static Set<Path> getAllTestMappingPaths(Path testMappingsRootPath) {
+ Set<Path> allTestMappingPaths = new HashSet<>();
+ for (String path : mTestMappingRelativePaths) {
+ boolean hasAdded = false;
+ Path testMappingPath = testMappingsRootPath.resolve(path);
+ // Recursively find the TEST_MAPPING file until reaching to testMappingsRootPath.
+ while (!testMappingPath.equals(testMappingsRootPath)) {
+ if (testMappingPath.resolve(TEST_MAPPING).toFile().exists()) {
+ hasAdded = true;
+ CLog.d("Adding TEST_MAPPING path: %s", testMappingPath);
+ allTestMappingPaths.add(testMappingPath.resolve(TEST_MAPPING));
+ }
+ testMappingPath = testMappingPath.getParent();
+ }
+ if (!hasAdded) {
+ CLog.w("Couldn't find TEST_MAPPING files from %s", path);
+ }
+ }
+ if (allTestMappingPaths.isEmpty()) {
+ throw new RuntimeException(
+ String.format(
+ "Couldn't find TEST_MAPPING files from %s", mTestMappingRelativePaths));
+ }
+ return allTestMappingPaths;
+ }
+
+ /**
* Helper to find all tests in all TEST_MAPPING files. This is needed when a suite run requires
* to run all tests in TEST_MAPPING files for a given group, e.g., presubmit.
*
@@ -263,7 +311,12 @@
try {
Path testMappingsRootPath = Paths.get(testMappingsDir.getAbsolutePath());
Set<String> disabledTests = getDisabledTests(testMappingsRootPath, testGroup);
- stream = Files.walk(testMappingsRootPath, FileVisitOption.FOLLOW_LINKS);
+ if (mTestMappingRelativePaths.isEmpty()) {
+ stream = Files.walk(testMappingsRootPath, FileVisitOption.FOLLOW_LINKS);
+ }
+ else {
+ stream = getAllTestMappingPaths(testMappingsRootPath).stream();
+ }
stream.filter(path -> path.getFileName().toString().equals(TEST_MAPPING))
.forEach(
path ->
diff --git a/tests/src/com/android/tradefed/testtype/suite/TestMappingSuiteRunnerTest.java b/tests/src/com/android/tradefed/testtype/suite/TestMappingSuiteRunnerTest.java
index 7ac65a4..342bd93 100644
--- a/tests/src/com/android/tradefed/testtype/suite/TestMappingSuiteRunnerTest.java
+++ b/tests/src/com/android/tradefed/testtype/suite/TestMappingSuiteRunnerTest.java
@@ -163,6 +163,17 @@
mRunner.loadTests();
}
+ /**
+ * Test for {@link TestMappingSuiteRunner#loadTests()} to fail when both options include-filter
+ * and test-mapping-path are set.
+ */
+ @Test(expected = RuntimeException.class)
+ public void testLoadTests_conflictOptions() throws Exception {
+ mOptionSetter.setOptionValue("include-filter", "test1");
+ mOptionSetter.setOptionValue("test-mapping-path", "path1");
+ mRunner.loadTests();
+ }
+
/** Test for {@link TestMappingSuiteRunner#loadTests()} to fail when no test option is set. */
@Test(expected = RuntimeException.class)
public void testLoadTests_noOption() throws Exception {
diff --git a/tests/src/com/android/tradefed/util/testmapping/TestMappingTest.java b/tests/src/com/android/tradefed/util/testmapping/TestMappingTest.java
index 0d69264..c1537ca 100644
--- a/tests/src/com/android/tradefed/util/testmapping/TestMappingTest.java
+++ b/tests/src/com/android/tradefed/util/testmapping/TestMappingTest.java
@@ -36,6 +36,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -228,6 +229,93 @@
}
/**
+ * Test for {@link TestMapping#getAllTestMappingPaths(Path)} to get TEST_MAPPING files from
+ * child directory.
+ */
+ @Test
+ public void testGetAllTestMappingPaths_FromChildDirectory() throws Exception {
+ File tempDir = null;
+ try {
+ tempDir = FileUtil.createTempDir("test_mapping");
+ Path testMappingsRootPath = Paths.get(tempDir.getAbsolutePath());
+ File srcDir = FileUtil.createTempDir("src", tempDir);
+ String srcFile = File.separator + TEST_DATA_DIR + File.separator + "test_mapping_1";
+ InputStream resourceStream = this.getClass().getResourceAsStream(srcFile);
+ FileUtil.saveResourceFile(resourceStream, srcDir, TEST_MAPPING);
+ File subDir = FileUtil.createTempDir("sub_dir", srcDir);
+ srcFile = File.separator + TEST_DATA_DIR + File.separator + "test_mapping_2";
+ resourceStream = this.getClass().getResourceAsStream(srcFile);
+ FileUtil.saveResourceFile(resourceStream, subDir, TEST_MAPPING);
+
+ List<String> testMappingRelativePaths = new ArrayList<>();
+ Path relPath = testMappingsRootPath.relativize(Paths.get(subDir.getAbsolutePath()));
+ testMappingRelativePaths.add(relPath.toString());
+ TestMapping.setTestMappingPaths(testMappingRelativePaths);
+ Set<Path> paths = TestMapping.getAllTestMappingPaths(testMappingsRootPath);
+ assertEquals(2, paths.size());
+ } finally {
+ TestMapping.setTestMappingPaths(new ArrayList<>());
+ FileUtil.recursiveDelete(tempDir);
+ }
+ }
+
+ /**
+ * Test for {@link TestMapping#getAllTestMappingPaths(Path)} to get TEST_MAPPING files from
+ * parent directory.
+ */
+ @Test
+ public void testGetAllTestMappingPaths_FromParentDirectory() throws Exception {
+ File tempDir = null;
+ try {
+ tempDir = FileUtil.createTempDir("test_mapping");
+ Path testMappingsRootPath = Paths.get(tempDir.getAbsolutePath());
+ File srcDir = FileUtil.createTempDir("src", tempDir);
+ String srcFile = File.separator + TEST_DATA_DIR + File.separator + "test_mapping_1";
+ InputStream resourceStream = this.getClass().getResourceAsStream(srcFile);
+ FileUtil.saveResourceFile(resourceStream, srcDir, TEST_MAPPING);
+ File subDir = FileUtil.createTempDir("sub_dir", srcDir);
+ srcFile = File.separator + TEST_DATA_DIR + File.separator + "test_mapping_2";
+ resourceStream = this.getClass().getResourceAsStream(srcFile);
+ FileUtil.saveResourceFile(resourceStream, subDir, TEST_MAPPING);
+
+ List<String> testMappingRelativePaths = new ArrayList<>();
+ Path relPath = testMappingsRootPath.relativize(Paths.get(srcDir.getAbsolutePath()));
+ testMappingRelativePaths.add(relPath.toString());
+ TestMapping.setTestMappingPaths(testMappingRelativePaths);
+ Set<Path> paths = TestMapping.getAllTestMappingPaths(testMappingsRootPath);
+ assertEquals(1, paths.size());
+ } finally {
+ TestMapping.setTestMappingPaths(new ArrayList<>());
+ FileUtil.recursiveDelete(tempDir);
+ }
+ }
+
+ /**
+ * Test for {@link TestMapping#getAllTestMappingPaths(Path)} to fail when no TEST_MAPPING files
+ * found.
+ */
+ @Test(expected = RuntimeException.class)
+ public void testGetAllTestMappingPaths_NoFilesFound() throws Exception {
+ File tempDir = null;
+ try {
+ tempDir = FileUtil.createTempDir("test_mapping");
+ Path testMappingsRootPath = Paths.get(tempDir.getAbsolutePath());
+ File srcDir = FileUtil.createTempDir("src", tempDir);
+
+ List<String> testMappingRelativePaths = new ArrayList<>();
+ Path relPath = testMappingsRootPath.relativize(Paths.get(srcDir.getAbsolutePath()));
+ testMappingRelativePaths.add(relPath.toString());
+ TestMapping.setTestMappingPaths(testMappingRelativePaths);
+ // No TEST_MAPPING files should be found according to the srcDir, getAllTestMappingPaths
+ // method shall raise RuntimeException.
+ TestMapping.getAllTestMappingPaths(testMappingsRootPath);
+ } finally {
+ TestMapping.setTestMappingPaths(new ArrayList<>());
+ FileUtil.recursiveDelete(tempDir);
+ }
+ }
+
+ /**
* Test for {@link TestInfo#merge()} for merging two TestInfo objects to fail when module names
* are different.
*/