diff --git a/src/devtools/mobileharness/infra/controller/test/util/xtsdownloader/configs/mcts_list.txt b/src/devtools/mobileharness/infra/controller/test/util/xtsdownloader/configs/mcts_list.txt index f08c8e9c6..6ba1d71b5 100644 --- a/src/devtools/mobileharness/infra/controller/test/util/xtsdownloader/configs/mcts_list.txt +++ b/src/devtools/mobileharness/infra/controller/test/util/xtsdownloader/configs/mcts_list.txt @@ -255,7 +255,6 @@ CtsTestAppWithQueryAllPackagesPermission CtsTetheringTest CtsTfliteNnapiDelegateTestCases CtsThreadNetworkTestCases -CtsUsbTests CtsUwbMultiDeviceTestCase_FiraRangingTests CtsUwbMultiDeviceTestCase_UwbManagerTests CtsUwbTestCases diff --git a/src/java/com/google/devtools/mobileharness/infra/ats/common/SessionRequestHandlerUtil.java b/src/java/com/google/devtools/mobileharness/infra/ats/common/SessionRequestHandlerUtil.java index d3ece2175..582dc4868 100644 --- a/src/java/com/google/devtools/mobileharness/infra/ats/common/SessionRequestHandlerUtil.java +++ b/src/java/com/google/devtools/mobileharness/infra/ats/common/SessionRequestHandlerUtil.java @@ -378,7 +378,12 @@ public ImmutableSet getStaticMctsModules() throws MobileHarnessException /** * Gets a list of filtered tradefed modules. * - *

The list of modules is filtered by include/exclude filters and the given module names. + *

The list of modules is filtered by include/exclude filters and the given module names. This + * method only return the modules passing along with the run cts -m command; In CTS tool, + * the run cts -m command only support passing one module so currently this method will + * most likely return only one module. This method also made an assumption that the + * --include-filter and run cts -m can be used together which is not supported in + * CTS tool actually. If the given module names are empty, it will return all the modules. * * @return a list of filtered tradefed modules if the given modules are not empty. Or an empty * list if the given modules are empty. diff --git a/src/java/com/google/devtools/mobileharness/infra/ats/common/SessionRequestInfo.java b/src/java/com/google/devtools/mobileharness/infra/ats/common/SessionRequestInfo.java index 460afbbdc..22f572fb0 100644 --- a/src/java/com/google/devtools/mobileharness/infra/ats/common/SessionRequestInfo.java +++ b/src/java/com/google/devtools/mobileharness/infra/ats/common/SessionRequestInfo.java @@ -132,6 +132,8 @@ public abstract class SessionRequestInfo { public abstract Optional skipDeviceInfo(); + public abstract Optional isEnableXtsDynamicDownload(); + public static Builder builder() { return new AutoValue_SessionRequestInfo.Builder() .setModuleNames(ImmutableList.of()) @@ -249,6 +251,8 @@ public abstract Builder setGivenMatchedNonTfModules( public abstract Builder setSkipDeviceInfo(boolean skipDeviceInfo); + public abstract Builder setIsEnableXtsDynamicDownload(boolean isEnableXtsDynamicDownload); + protected abstract SessionRequestInfo autoBuild(); public SessionRequestInfo build() { diff --git a/src/java/com/google/devtools/mobileharness/infra/ats/common/jobcreator/BUILD b/src/java/com/google/devtools/mobileharness/infra/ats/common/jobcreator/BUILD index 7ddd43b75..c67e071b5 100644 --- a/src/java/com/google/devtools/mobileharness/infra/ats/common/jobcreator/BUILD +++ b/src/java/com/google/devtools/mobileharness/infra/ats/common/jobcreator/BUILD @@ -44,8 +44,10 @@ java_library( "//src/java/com/google/devtools/mobileharness/infra/ats/common:session_request_info", "//src/java/com/google/devtools/mobileharness/infra/ats/common:xts_property_name", "//src/java/com/google/devtools/mobileharness/infra/ats/common/plan:test_plan_parser", + "//src/java/com/google/devtools/mobileharness/platform/android/xts/common/util:xts_constants", "//src/java/com/google/devtools/mobileharness/platform/android/xts/common/util:xts_dir_util", "//src/java/com/google/devtools/mobileharness/platform/android/xts/suite:suite_common", + "//src/java/com/google/devtools/mobileharness/platform/android/xts/suite:suite_test_filter", "//src/java/com/google/devtools/mobileharness/platform/android/xts/suite/retry:retry_args", "//src/java/com/google/devtools/mobileharness/platform/android/xts/suite/retry:retry_generator", "//src/java/com/google/devtools/mobileharness/platform/android/xts/suite/subplan:sub_plan", diff --git a/src/java/com/google/devtools/mobileharness/infra/ats/common/jobcreator/XtsJobCreator.java b/src/java/com/google/devtools/mobileharness/infra/ats/common/jobcreator/XtsJobCreator.java index 1d20b0f05..fee1b1045 100644 --- a/src/java/com/google/devtools/mobileharness/infra/ats/common/jobcreator/XtsJobCreator.java +++ b/src/java/com/google/devtools/mobileharness/infra/ats/common/jobcreator/XtsJobCreator.java @@ -36,9 +36,12 @@ import com.google.devtools.mobileharness.infra.ats.common.XtsPropertyName; import com.google.devtools.mobileharness.infra.ats.common.XtsPropertyName.Job; import com.google.devtools.mobileharness.infra.ats.common.plan.TestPlanParser; +import com.google.devtools.mobileharness.platform.android.xts.common.util.XtsConstants; +import com.google.devtools.mobileharness.platform.android.xts.common.util.XtsConstants.XtsDynamicDownloadModuleMatchResult; import com.google.devtools.mobileharness.platform.android.xts.common.util.XtsDirUtil; import com.google.devtools.mobileharness.platform.android.xts.config.proto.ConfigurationProto.Configuration; import com.google.devtools.mobileharness.platform.android.xts.suite.SuiteCommon; +import com.google.devtools.mobileharness.platform.android.xts.suite.SuiteTestFilter; import com.google.devtools.mobileharness.platform.android.xts.suite.retry.RetryArgs; import com.google.devtools.mobileharness.platform.android.xts.suite.retry.RetryGenerator; import com.google.devtools.mobileharness.platform.android.xts.suite.subplan.SubPlan; @@ -101,17 +104,45 @@ public static boolean isSkippableException(MobileHarnessException e) { */ public ImmutableList createXtsTradefedTestJob(SessionRequestInfo sessionRequestInfo) throws MobileHarnessException, InterruptedException { + ImmutableSet staticMctsModules = sessionRequestHandlerUtil.getStaticMctsModules(); ImmutableList tfModules = sessionRequestHandlerUtil.getFilteredTradefedModules(sessionRequestInfo); + ImmutableList includeFilters = + sessionRequestInfo.includeFilters().stream() + .map(SuiteTestFilter::create) + .collect(toImmutableList()); ImmutableList tradefedJobInfoList = createXtsTradefedTestJobInfo(sessionRequestInfo, tfModules); ImmutableList.Builder jobInfos = ImmutableList.builder(); + XtsDynamicDownloadModuleMatchResult dynamicDownloadModuleMatchResult = + addEnableXtsDynamicDownloadToJob( + sessionRequestInfo, tfModules, staticMctsModules, includeFilters); for (TradefedJobInfo tradefedJobInfo : tradefedJobInfoList) { - JobInfo jobInfo = - sessionRequestHandlerUtil.createXtsTradefedTestJob(sessionRequestInfo, tradefedJobInfo); - jobInfos.add(jobInfo); + // Create two jobs if we enable dynamic download. + switch (dynamicDownloadModuleMatchResult) { + case SOME_MATCH: + // Create a job for non dynamic download test cases. + jobInfos.add( + createDynamicJobInfo( + sessionRequestInfo, tradefedJobInfo, XtsConstants.STATIC_XTS_JOB)); + // Create a job for dynamic download test cases. + jobInfos.add( + createDynamicJobInfo( + sessionRequestInfo, tradefedJobInfo, XtsConstants.DYNAMIC_XTS_JOB)); + break; + case ALL_MATCH: + // Create only one job for dynamic download test cases. + jobInfos.add( + createDynamicJobInfo( + sessionRequestInfo, tradefedJobInfo, XtsConstants.DYNAMIC_XTS_JOB)); + break; + default: + jobInfos.add( + sessionRequestHandlerUtil.createXtsTradefedTestJob( + sessionRequestInfo, tradefedJobInfo)); + } } return jobInfos.build(); @@ -412,6 +443,53 @@ private void injectBuildFingerprint( Job.PREV_SESSION_DEVICE_VENDOR_BUILD_FINGERPRINT, prevSessionDeviceVendorBuildFingerprint); } + private static XtsDynamicDownloadModuleMatchResult addEnableXtsDynamicDownloadToJob( + SessionRequestInfo sessionRequestInfo, + ImmutableList tfModules, + ImmutableSet staticMctsModules, + ImmutableList includeFilters) { + if (sessionRequestInfo.isEnableXtsDynamicDownload().orElse(false)) { + // Consider independent two cases: + // 1. No -m and no --include-filter MCTS modules specified, dynamic download is disabled. + // 2. Some of the MCTS modules are specified, create a dynamic download job and a static job. + // 3. All of the MCTS modules are specified, create only one dynamic download job. + // 4. tfModules and includeFilters cannot be both non-empty. + if (!tfModules.isEmpty()) { + if (tfModules.stream().noneMatch(staticMctsModules::contains)) { + return XtsDynamicDownloadModuleMatchResult.NONE_MATCH; + } else if (tfModules.stream().allMatch(staticMctsModules::contains)) { + return XtsDynamicDownloadModuleMatchResult.ALL_MATCH; + } else { + return XtsDynamicDownloadModuleMatchResult.SOME_MATCH; + } + } + if (!includeFilters.isEmpty()) { + if (includeFilters.stream() + .noneMatch(filter -> staticMctsModules.stream().anyMatch(filter::matchModuleName))) { + return XtsDynamicDownloadModuleMatchResult.NONE_MATCH; + } else if (includeFilters.stream() + .allMatch(filter -> staticMctsModules.stream().anyMatch(filter::matchModuleName))) { + return XtsDynamicDownloadModuleMatchResult.ALL_MATCH; + } else { + return XtsDynamicDownloadModuleMatchResult.SOME_MATCH; + } + } + return XtsDynamicDownloadModuleMatchResult.SOME_MATCH; + } else { + return XtsDynamicDownloadModuleMatchResult.NONE_MATCH; + } + } + + private JobInfo createDynamicJobInfo( + SessionRequestInfo sessionRequestInfo, TradefedJobInfo tradefedJobInfo, String jobType) + throws MobileHarnessException, InterruptedException { + JobInfo dynamicDownloadJobInfo = + sessionRequestHandlerUtil.createXtsTradefedTestJob(sessionRequestInfo, tradefedJobInfo); + dynamicDownloadJobInfo.properties().add(XtsConstants.IS_XTS_DYNAMIC_DOWNLOAD_ENABLED, "true"); + dynamicDownloadJobInfo.properties().add(XtsConstants.XTS_DYNAMIC_DOWNLOAD_JOB_TYPE, jobType); + return dynamicDownloadJobInfo; + } + protected static Properties loadTestReportProperties(Path testReportPropertiesFile) throws MobileHarnessException { Properties properties = new Properties(); diff --git a/src/java/com/google/devtools/mobileharness/infra/ats/console/controller/sessionplugin/BUILD b/src/java/com/google/devtools/mobileharness/infra/ats/console/controller/sessionplugin/BUILD index 4ff711f57..90e820fbd 100644 --- a/src/java/com/google/devtools/mobileharness/infra/ats/console/controller/sessionplugin/BUILD +++ b/src/java/com/google/devtools/mobileharness/infra/ats/console/controller/sessionplugin/BUILD @@ -181,7 +181,6 @@ java_library( "//src/java/com/google/devtools/mobileharness/platform/android/xts/common/util:xts_constants", "//src/java/com/google/devtools/mobileharness/platform/android/xts/common/util:xts_dir_util", "//src/java/com/google/devtools/mobileharness/platform/android/xts/suite:suite_result_reporter", - "//src/java/com/google/devtools/mobileharness/platform/android/xts/suite:suite_test_filter", "//src/java/com/google/devtools/mobileharness/platform/android/xts/suite/retry:previous_result_loader", "//src/java/com/google/devtools/mobileharness/platform/android/xts/suite/retry:retry_type", "//src/java/com/google/devtools/mobileharness/shared/constant:log_record_importance", diff --git a/src/java/com/google/devtools/mobileharness/infra/ats/console/controller/sessionplugin/RunCommandHandler.java b/src/java/com/google/devtools/mobileharness/infra/ats/console/controller/sessionplugin/RunCommandHandler.java index 66fbe6d6e..538d158ce 100644 --- a/src/java/com/google/devtools/mobileharness/infra/ats/console/controller/sessionplugin/RunCommandHandler.java +++ b/src/java/com/google/devtools/mobileharness/infra/ats/console/controller/sessionplugin/RunCommandHandler.java @@ -17,7 +17,6 @@ package com.google.devtools.mobileharness.infra.ats.console.controller.sessionplugin; import static com.google.common.base.Ascii.toUpperCase; -import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.devtools.mobileharness.shared.constant.LogRecordImportance.IMPORTANCE; import static com.google.devtools.mobileharness.shared.constant.LogRecordImportance.Importance.IMPORTANT; import static com.google.devtools.mobileharness.shared.util.base.ProtoTextFormat.shortDebugString; @@ -25,7 +24,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import com.google.common.flogger.FluentLogger; import com.google.devtools.mobileharness.api.model.error.MobileHarnessException; import com.google.devtools.mobileharness.infra.ats.common.SessionRequestHandlerUtil; @@ -45,7 +43,6 @@ import com.google.devtools.mobileharness.platform.android.xts.common.util.XtsConstants; import com.google.devtools.mobileharness.platform.android.xts.common.util.XtsDirUtil; import com.google.devtools.mobileharness.platform.android.xts.suite.SuiteResultReporter; -import com.google.devtools.mobileharness.platform.android.xts.suite.SuiteTestFilter; import com.google.devtools.mobileharness.platform.android.xts.suite.retry.PreviousResultLoader; import com.google.devtools.mobileharness.platform.android.xts.suite.retry.RetryType; import com.google.devtools.mobileharness.shared.util.file.local.LocalFileUtil; @@ -135,14 +132,6 @@ ImmutableList createTradefedJobs(RunCommand command) return ImmutableList.of(); } - ImmutableSet staticMctsModules = sessionRequestHandlerUtil.getStaticMctsModules(); - ImmutableList tfModules = - sessionRequestHandlerUtil.getFilteredTradefedModules(sessionRequestInfo); - ImmutableList includeFilters = - sessionRequestInfo.includeFilters().stream() - .map(SuiteTestFilter::create) - .collect(toImmutableList()); - jobInfoList.forEach( jobInfo -> { jobInfo @@ -155,8 +144,6 @@ ImmutableList createTradefedJobs(RunCommand command) .getSessionProperty(SESSION_PROPERTY_NAME_TIMESTAMP_DIR_NAME) .orElseThrow()) .toString()); - addEnableXtsDynamicDownloadToJob( - jobInfo, command, tfModules, staticMctsModules, includeFilters); }); return jobInfoList; } @@ -361,6 +348,9 @@ SessionRequestInfo generateSessionRequestInfo(RunCommand runCommand) if (runCommand.hasMaxSdkLevel()) { builder.setMaxSdkLevel(runCommand.getMaxSdkLevel()); } + if (runCommand.getEnableXtsDynamicDownload()) { + builder.setIsEnableXtsDynamicDownload(runCommand.getEnableXtsDynamicDownload()); + } sessionInfo .getSessionProperty(SessionProperties.PROPERTY_KEY_SESSION_CLIENT_ID) @@ -384,29 +374,4 @@ private String createXtsTestResultSummary( : "") + "=================== End ====================\n"; } - - private static void addEnableXtsDynamicDownloadToJob( - JobInfo jobInfo, - RunCommand runCommand, - ImmutableList tfModules, - ImmutableSet staticMctsModules, - ImmutableList includeFilters) { - if (runCommand.getEnableXtsDynamicDownload()) { - jobInfo.properties().add(XtsConstants.IS_XTS_DYNAMIC_DOWNLOAD_ENABLED, "true"); - } - // Consider independent two cases: - // 1. No -m MCTS modules specified, dynamic download is disabled. - // 2. No include filtered MCTS modules, dynamic download is disabled. - if (!tfModules.isEmpty()) { - if (tfModules.stream().noneMatch(staticMctsModules::contains)) { - jobInfo.properties().add(XtsConstants.IS_XTS_DYNAMIC_DOWNLOAD_ENABLED, "false"); - } - } - if (!includeFilters.isEmpty()) { - if (includeFilters.stream() - .noneMatch(filter -> staticMctsModules.stream().anyMatch(filter::matchModuleName))) { - jobInfo.properties().add(XtsConstants.IS_XTS_DYNAMIC_DOWNLOAD_ENABLED, "false"); - } - } - } } diff --git a/src/java/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader/MctsDynamicDownloadPlugin.java b/src/java/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader/MctsDynamicDownloadPlugin.java index 583e79b0a..02600e20f 100644 --- a/src/java/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader/MctsDynamicDownloadPlugin.java +++ b/src/java/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader/MctsDynamicDownloadPlugin.java @@ -181,6 +181,11 @@ public XtsDynamicDownloadInfo parse(TestInfo test, String deviceId) String.format( "https://dl.google.com/dl/android/xts/mcts/tool/mcts_exclude/%s/%s/mcts-exclude.txt", aospVersion, preloadedMainlineVersion)); + // Add the full MCTS list file link url to the second position of the list. + downloadLinkUrls.add( + String.format( + "https://dl.google.com/dl/android/xts/mcts/%s/%s/mcts_test_list.txt", + preloadedMainlineVersion, deviceAbi)); for (String mctsNameAndVersioncode : mctsNamesOfPreloadedMainlineModules.get(PRELOADED_KEY)) { String moduleVersioncode = mctsNameAndVersioncode.substring(mctsNameAndVersioncode.indexOf(":") + 1); @@ -214,8 +219,36 @@ public XtsDynamicDownloadInfo parse(TestInfo test, String deviceId) @Override public void downloadXtsFiles(XtsDynamicDownloadInfo xtsDynamicDownloadInfo, TestInfo testInfo) throws MobileHarnessException, InterruptedException { - Set allTestModules = new HashSet<>(); List downloadUrlList = new ArrayList<>(xtsDynamicDownloadInfo.getDownloadUrlList()); + // Download the MCTS full test list. + if (downloadUrlList.get(1).contains("mcts_test_list")) { + logger.atInfo().log("Start to download MCTS full test list."); + String mctsFullTestListUrl = downloadUrlList.get(1); + String mctsFullTestListFilePath = + downloadPublicUrlFiles( + mctsFullTestListUrl, mctsFullTestListUrl.replace("https://dl.google.com/dl", "")); + if (mctsFullTestListFilePath != null) { + testInfo + .properties() + .add( + XtsConstants.XTS_DYNAMIC_DOWNLOAD_PATH_TEST_LIST_PROPERTY_KEY, + mctsFullTestListFilePath); + } + downloadUrlList.remove(1); + } + + // If the job type is static, skip downloading the MCTS files. + if (testInfo + .jobInfo() + .properties() + .get(XtsConstants.XTS_DYNAMIC_DOWNLOAD_JOB_TYPE) + .equals(XtsConstants.STATIC_XTS_JOB)) { + return; + } + + // Download the MCTS files for dynamic download mcts job. + logger.atInfo().log("Start to download files for dynamic download MCTS job..."); + Set allTestModules = new HashSet<>(); Set excludeTestModules = new HashSet<>(); // Get the exclude test modules. if (downloadUrlList.get(0).contains("mcts_exclude")) { diff --git a/src/java/com/google/devtools/mobileharness/platform/android/xts/common/util/BUILD b/src/java/com/google/devtools/mobileharness/platform/android/xts/common/util/BUILD index 6db53af7e..610f21e09 100644 --- a/src/java/com/google/devtools/mobileharness/platform/android/xts/common/util/BUILD +++ b/src/java/com/google/devtools/mobileharness/platform/android/xts/common/util/BUILD @@ -53,6 +53,7 @@ java_library( "//src/java/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader:__subpackages__", "//src/java/com/google/wireless/qa/mobileharness/shared/api/driver:__subpackages__", "//src/javatests/com/google/devtools/mobileharness/infra/ats:__subpackages__", + "//src/javatests/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader:__subpackages__", ], ) diff --git a/src/java/com/google/devtools/mobileharness/platform/android/xts/common/util/XtsConstants.java b/src/java/com/google/devtools/mobileharness/platform/android/xts/common/util/XtsConstants.java index f5f06d938..2ca9e30f3 100644 --- a/src/java/com/google/devtools/mobileharness/platform/android/xts/common/util/XtsConstants.java +++ b/src/java/com/google/devtools/mobileharness/platform/android/xts/common/util/XtsConstants.java @@ -48,15 +48,35 @@ public class XtsConstants { /** A MH job property key to indicate whether xTS dynamic download is enabled. */ public static final String IS_XTS_DYNAMIC_DOWNLOAD_ENABLED = "is_xts_dynamic_download_enabled"; + /** The job type of dynamic download xTS jobs. */ + public static final String XTS_DYNAMIC_DOWNLOAD_JOB_TYPE = "xts_dynamic_download_job_type"; + + public static final String STATIC_XTS_JOB = "static"; + public static final String DYNAMIC_XTS_JOB = "dynamic"; + /** MH test property keys of path relative to the test temp dir. */ public static final String XTS_DYNAMIC_DOWNLOAD_PATH_TEST_PROPERTY_KEY = "xts_dynamic_download_path"; + /** MH test property keys of path relative to the test temp dir. */ + public static final String XTS_DYNAMIC_DOWNLOAD_PATH_TEST_LIST_PROPERTY_KEY = + "xts_dynamic_download_test_list_path"; + public static final String XTS_DYNAMIC_DOWNLOAD_PATH_JDK_PROPERTY_KEY = "xts_dynamic_download_jdk_path"; public static final Pattern RESULT_ZIP_FILENAME_PATTERN = Pattern.compile("^\\d{4}\\.\\d{2}\\.\\d{2}_\\d{2}\\.\\d{2}\\.\\d{2}\\.\\d{3}_\\d{4}\\.zip$"); + /** The match result of filtered TF modules to define if dynamic download is enabled. */ + public enum XtsDynamicDownloadModuleMatchResult { + /** All the filtered TF modules match the dynamic download modules. */ + ALL_MATCH, + /** Some of the filtered TF modules match the dynamic download modules. */ + SOME_MATCH, + /** None of the filtered TF modules match the dynamic download modules. */ + NONE_MATCH, + } + private XtsConstants() {} } diff --git a/src/java/com/google/wireless/qa/mobileharness/shared/api/driver/XtsTradefedTest.java b/src/java/com/google/wireless/qa/mobileharness/shared/api/driver/XtsTradefedTest.java index ae9d8e70e..351576d44 100644 --- a/src/java/com/google/wireless/qa/mobileharness/shared/api/driver/XtsTradefedTest.java +++ b/src/java/com/google/wireless/qa/mobileharness/shared/api/driver/XtsTradefedTest.java @@ -18,6 +18,7 @@ import static com.google.common.base.StandardSystemProperty.JAVA_IO_TMPDIR; import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.devtools.mobileharness.shared.util.base.ProtoTextFormat.shortDebugString; import static com.google.devtools.mobileharness.shared.util.concurrent.Callables.threadRenaming; import static com.google.devtools.mobileharness.shared.util.concurrent.MoreFutures.logFailure; @@ -93,6 +94,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -132,6 +134,14 @@ public class XtsTradefedTest extends BaseDriver "--compatibility:include-filter", "--compatibility:exclude-filter"); + private static final ImmutableSet DYNAMIC_JOB_TEST_DEPENDENCIES = + ImmutableSet.of("CtsPreconditions"); + + // Will remove these cases from MCTS. + private static final ImmutableSet STATIC_JOB_TEST_DEPENDENCIES = + ImmutableSet.of( + "cts-dalvik-host-test-runner", "net-tests-utils-host-common", "CtsBackupHostTestCases"); + private static final String TF_PATH_KEY = "TF_PATH"; private static final Duration KILL_TF_AFTER_FINISH_TIME = Duration.ofMinutes(5L); @@ -139,6 +149,9 @@ public class XtsTradefedTest extends BaseDriver private static final String TF_AGENT_RESOURCE_PATH = "/com/google/devtools/mobileharness/platform/android/xts/agent/tradefed_invocation_agent_deploy.jar"; + private static final String STATIC_MCTS_LIST_FILE_PATH = + "/devtools/mobileharness/infra/controller/test/util/xtsdownloader/configs/mcts_list.txt"; + private final CommandExecutor cmdExecutor; private final LocalFileUtil localFileUtil; private final SystemUtil systemUtil; @@ -931,22 +944,53 @@ private void setUpXtsWorkDir( createSymlink(linkJdkDir, sourceXtsBundledJdkDir); } - createSymlinksForTestCases(linkTestcasesDir, sourceXtsBundledTestcasesDir); + if (isXtsDynamicDownloaderEnabled(testInfo)) { + Set xtsDynamicDownloadTestList = new HashSet<>(); + String testListProperty = + testInfo.properties().get(XtsConstants.XTS_DYNAMIC_DOWNLOAD_PATH_TEST_LIST_PROPERTY_KEY); + if (testListProperty != null) { + xtsDynamicDownloadTestList.addAll(getStringSetFromResourceFile(testListProperty)); + } else { + xtsDynamicDownloadTestList.addAll( + getStringSetFromResourceFile(getStaticMctsListFilePath())); + } + if (testInfo + .jobInfo() + .properties() + .get(XtsConstants.XTS_DYNAMIC_DOWNLOAD_JOB_TYPE) + .equals(XtsConstants.DYNAMIC_XTS_JOB)) { + if (testInfo.properties().has(XtsConstants.XTS_DYNAMIC_DOWNLOAD_PATH_TEST_PROPERTY_KEY)) { + // Integrates the dynamic downloaded test cases with the temp XTS workspace. + createSymlinksForDynamicDownloadTestCases( + linkTestcasesDir, + Path.of( + testInfo.getTmpFileDir() + + testInfo + .properties() + .get(XtsConstants.XTS_DYNAMIC_DOWNLOAD_PATH_TEST_PROPERTY_KEY)), + true, + xtsDynamicDownloadTestList); + // Also include the test dependencies for dynamic download test cases. + createSymlinksForDynamicDownloadTestCases( + linkTestcasesDir, sourceXtsBundledTestcasesDir, true, DYNAMIC_JOB_TEST_DEPENDENCIES); + } + } + if (testInfo + .jobInfo() + .properties() + .get(XtsConstants.XTS_DYNAMIC_DOWNLOAD_JOB_TYPE) + .equals(XtsConstants.STATIC_XTS_JOB)) { + // Integrates the static test cases with the temp XTS workspace. + createSymlinksForDynamicDownloadTestCases( + linkTestcasesDir, sourceXtsBundledTestcasesDir, false, xtsDynamicDownloadTestList); + } + } else { + createSymlinksForTestCases(linkTestcasesDir, sourceXtsBundledTestcasesDir); + } createSymlink(linkToolsDir, sourceXtsBundledToolsDir); createSymlink(linkLibDir, sourceXtsBundledLibDir); createSymlink(linkLib64Dir, sourceXtsBundledLib64Dir); - if (testInfo.properties().has(XtsConstants.XTS_DYNAMIC_DOWNLOAD_PATH_TEST_PROPERTY_KEY)) { - // Integrates the dynamic downloaded test cases with the temp XTS workspace. - createSymlinksForTestCases( - linkTestcasesDir, - Path.of( - testInfo.getTmpFileDir() - + testInfo - .properties() - .get(XtsConstants.XTS_DYNAMIC_DOWNLOAD_PATH_TEST_PROPERTY_KEY))); - } - if (useTfRunRetry(spec)) { // When using TF "run retry", TF looks for the corresponding previous result dir per given // session index. So it needs to link the previous session's result dir to the work dir so TF @@ -1022,6 +1066,58 @@ private void createSymlinksForTestCases(Path link, Path target) throws MobileHar "Finished integrating the test cases [%s] with the temp XTS workspace [%s].", target, link); } + private void createSymlinksForDynamicDownloadTestCases( + Path link, Path target, boolean isDynamicDownload, Set dynamicDownloadTestList) + throws MobileHarnessException { + try { + localFileUtil.checkFileOrDir(target); + } catch (MobileHarnessException e) { + // File does not exist, no need to integrate. + logger.atWarning().log("%s does not exist.", target); + return; + } + + // Create symlink to the immediate subfiles and subdirectories of the xts test cases. + // For dynamic download jobs, only create symlinks for the test cases in the test list. + // For non dynamic download jobs, create symlinks for the test cases not in the test list. + List subTestCases = localFileUtil.listFileOrDirPaths(target.toString()); + for (String subTestCase : subTestCases) { + Path subTestCasePath = Path.of(subTestCase); + String subTestCaseName = subTestCasePath.getFileName().toString(); + boolean shouldCreateSymlink = + isDynamicDownload + ? dynamicDownloadTestList.contains(subTestCaseName) + : !dynamicDownloadTestList.contains(subTestCaseName) + || STATIC_JOB_TEST_DEPENDENCIES.contains(subTestCaseName); + + if (shouldCreateSymlink) { + Path tmpXtsTestcasePath = link.resolve(subTestCasePath.getFileName().toString()); + createSymlink(tmpXtsTestcasePath, subTestCasePath); + } + } + + logger.atInfo().log( + "Finished integrating the test cases [%s] with the temp XTS workspace [%s].", target, link); + } + + /** Returns {@code true} if xts dynamic downloader is enabled. */ + private static boolean isXtsDynamicDownloaderEnabled(TestInfo testInfo) { + return testInfo + .jobInfo() + .properties() + .getBoolean(XtsConstants.IS_XTS_DYNAMIC_DOWNLOAD_ENABLED) + .orElse(false); + } + + private ImmutableSet getStringSetFromResourceFile(String filePath) + throws MobileHarnessException { + // String filePath = resUtilProvider.get().getResourceFile(getClass(), resPathInJar); + return localFileUtil.readLineListFromFile(filePath).stream() + .map(String::trim) + .filter(line -> !line.isEmpty()) + .collect(toImmutableSet()); + } + private static boolean isRunRetryWithSubPlan(XtsTradefedTestDriverSpec spec) { return spec.getXtsTestPlan().equals("retry") && !spec.getSubplanXml().isEmpty(); } @@ -1047,4 +1143,8 @@ private static boolean isRunWithSubPlan(XtsTradefedTestDriverSpec spec) { private String getTradefedAgentFilePath() throws MobileHarnessException { return resUtil.getResourceFile(getClass(), TF_AGENT_RESOURCE_PATH); } + + private String getStaticMctsListFilePath() throws MobileHarnessException { + return resUtil.getResourceFile(getClass(), STATIC_MCTS_LIST_FILE_PATH); + } } diff --git a/src/javatests/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader/BUILD b/src/javatests/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader/BUILD index d1e975b68..d7716f0c0 100644 --- a/src/javatests/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader/BUILD +++ b/src/javatests/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader/BUILD @@ -31,6 +31,7 @@ java_library( "//src/java/com/google/devtools/mobileharness/platform/android/packagemanager:info", "//src/java/com/google/devtools/mobileharness/platform/android/sdktool/adb:adb_util", "//src/java/com/google/devtools/mobileharness/platform/android/sdktool/adb:enums", + "//src/java/com/google/devtools/mobileharness/platform/android/xts/common/util:xts_constants", "//src/java/com/google/devtools/mobileharness/shared/util/file/local", "//src/java/com/google/wireless/qa/mobileharness/shared/controller/event:test", "//src/java/com/google/wireless/qa/mobileharness/shared/model/job", diff --git a/src/javatests/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader/MctsDynamicDownloadPluginTest.java b/src/javatests/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader/MctsDynamicDownloadPluginTest.java index 9e111b988..dc5205b84 100644 --- a/src/javatests/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader/MctsDynamicDownloadPluginTest.java +++ b/src/javatests/com/google/devtools/mobileharness/infra/controller/test/util/xtsdownloader/MctsDynamicDownloadPluginTest.java @@ -32,6 +32,7 @@ import com.google.devtools.mobileharness.platform.android.packagemanager.ModuleInfo; import com.google.devtools.mobileharness.platform.android.sdktool.adb.AndroidAdbUtil; import com.google.devtools.mobileharness.platform.android.sdktool.adb.AndroidProperty; +import com.google.devtools.mobileharness.platform.android.xts.common.util.XtsConstants; import com.google.devtools.mobileharness.shared.util.file.local.LocalFileUtil; import com.google.wireless.qa.mobileharness.shared.controller.event.LocalTestStartingEvent; import com.google.wireless.qa.mobileharness.shared.model.job.JobInfo; @@ -63,11 +64,13 @@ public final class MctsDynamicDownloadPluginTest { @Mock private AndroidAdbUtil mockAdbUtil; @Mock private AndroidPackageManagerUtil mockAndroidPackageManagerUtil; @Mock private Properties testProperties; + @Mock private Properties jobProperties; @Mock private DeviceLocator mockDeviceLocator; private MctsDynamicDownloadPlugin spyMctsDynamicDownloadPlugin; private final LocalFileUtil localFileUtil = new LocalFileUtil(); + @SuppressWarnings("DirectInvocationOnMock") @Before public void setUp() throws MobileHarnessException, InterruptedException { when(mockEvent.getTest()).thenReturn(mockTestInfo); @@ -76,6 +79,9 @@ public void setUp() throws MobileHarnessException, InterruptedException { when(mockTestInfo.jobInfo()).thenReturn(mockJobInfo); when(mockTestInfo.getTmpFileDir()).thenReturn("/tmp"); when(mockTestInfo.properties()).thenReturn(testProperties); + when(mockTestInfo.jobInfo().properties()).thenReturn(jobProperties); + when(jobProperties.get(XtsConstants.XTS_DYNAMIC_DOWNLOAD_JOB_TYPE)) + .thenReturn(XtsConstants.DYNAMIC_XTS_JOB); when(mockAndroidPackageManagerUtil.getAppVersionCode( any(), eq("com.google.android.modulemetadata"))) .thenReturn(351050004); @@ -211,6 +217,11 @@ public void setUp() throws MobileHarnessException, InterruptedException { .downloadPublicUrlFiles( "https://dl.google.com/dl/android/xts/mcts/tool/mcts_exclude/30/2024-10/mcts-exclude.txt", "/android/xts/mcts/tool/mcts_exclude/30/2024-10/mcts-exclude.txt"); + Mockito.doReturn(null) + .when(spyMctsDynamicDownloadPlugin) + .downloadPublicUrlFiles( + "https://dl.google.com/dl/android/xts/mcts/2024-10/arm64/mcts_test_list.txt", + "/android/xts/mcts/2024-10/arm64/mcts_test_list.txt"); } @Test