blob: 82847b91f97feb58f18a1e130a97266f252aa8ad [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tradefed.presubmit;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.build.IDeviceBuildInfo;
import com.android.tradefed.config.ConfigurationDescriptor;
import com.android.tradefed.config.ConfigurationException;
import com.android.tradefed.config.ConfigurationFactory;
import com.android.tradefed.config.ConfigurationUtil;
import com.android.tradefed.config.IConfiguration;
import com.android.tradefed.config.IConfigurationFactory;
import com.android.tradefed.config.IDeviceConfiguration;
import com.android.tradefed.config.Option;
import com.android.tradefed.log.LogUtil;
import com.android.tradefed.targetprep.ITargetPreparer;
import com.android.tradefed.targetprep.PushFilePreparer;
import com.android.tradefed.targetprep.TestAppInstallSetup;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.IBuildReceiver;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.testtype.IsolatedHostTest;
import com.android.tradefed.testtype.suite.ITestSuite;
import com.android.tradefed.testtype.suite.ValidateSuiteConfigHelper;
import com.android.tradefed.testtype.suite.params.ModuleParameters;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.ModuleTestTypeUtil;
import com.google.common.base.Joiner;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Validation tests to run against the configuration in general-tests.zip to ensure they can all
* parse.
*
* <p>Do not add to UnitTests.java. This is meant to run standalone.
*/
@RunWith(DeviceJUnit4ClassRunner.class)
public class GeneralTestsConfigValidation implements IBuildReceiver {
@Option(
name = "config-extension",
description = "The expected extension from configuration to check.")
private String mConfigExtension = "config";
@Option(
name = "disallowed-test-type",
description = "The disallowed test type for configs in general-tests.zip")
private List<String> mDisallowedTestTypes = new ArrayList<>();
private IBuildInfo mBuild;
/**
* List of the officially supported runners in general-tests. Any new addition should go through
* a review to ensure all runners have a high quality bar.
*/
private static final Set<String> SUPPORTED_TEST_RUNNERS =
new HashSet<>(
Arrays.asList(
// Cts runners
"com.android.compatibility.common.tradefed.testtype.JarHostTest",
"com.android.compatibility.testtype.DalvikTest",
"com.android.compatibility.testtype.LibcoreTest",
"com.drawelements.deqp.runner.DeqpTestRunner",
// Tradefed runners
"com.android.tradefed.testtype.UiAutomatorTest",
"com.android.tradefed.testtype.InstrumentationTest",
"com.android.tradefed.testtype.AndroidJUnitTest",
"com.android.tradefed.testtype.HostTest",
"com.android.tradefed.testtype.GTest",
"com.android.tradefed.testtype.HostGTest",
"com.android.tradefed.testtype.GoogleBenchmarkTest",
"com.android.tradefed.testtype.IsolatedHostTest",
"com.android.tradefed.testtype.python.PythonBinaryHostTest",
"com.android.tradefed.testtype.binary.ExecutableHostTest",
"com.android.tradefed.testtype.binary.ExecutableTargetTest",
"com.android.tradefed.testtype.rust.RustBinaryHostTest",
"com.android.tradefed.testtype.rust.RustBinaryTest",
"com.android.tradefed.testtype.StubTest",
"com.android.tradefed.testtype.ArtRunTest",
"com.android.tradefed.testtype.ArtGTest",
"com.android.tradefed.testtype.mobly.MoblyBinaryHostTest",
"com.android.tradefed.testtype.pandora.PtsBotTest",
// VTS runners
"com.android.tradefed.testtype.binary.KernelTargetTest",
// Others
"com.google.android.deviceconfig.RebootTest",
"com.android.scenario.AppSetup"));
/**
* List of configs that will be exempted until they are converted to use MediaPreparers.
* (b/274674920)
*/
private static final Set<String> MEDIAPREPARER_EXEMPTED_CONFIGS =
new HashSet<>(
Arrays.asList(
"OpusHeaderTest.config",
"AmrnbEncoderTest.config",
"AmrnbDecoderTest.config",
"AmrwbEncoderTest.config",
"AmrwbDecoderTest.config",
"HEVCUtilsUnitTest.config",
"ExtractorUnitTest.config",
"MediaTranscoderBenchmark.config",
"TimedTextUnitTest.config",
"VorbisDecoderTest.config",
"MediaTrackTranscoderBenchmark.config",
"ID3Test.config",
"ExtractorFactoryTest.config",
"MediaSampleReaderBenchmark.config",
"Mpeg4H263EncoderTest.config",
"Mp3DecoderTest.config",
"Mpeg2tsUnitTest.config",
"Mpeg4H263DecoderTest.config"));
/** List of configs that will be exempted until b/274930471 is fixed. */
private static final Set<String> EXEMPTED_PYTHON_TEST_MODULES =
new HashSet<>(
Arrays.asList(
"aidl_integration_test.config",
"hidl_test.config",
"hidl_test_java.config",
"fmq_test.config"));
/** List of configs to exclude until b/277261121 is fixed. */
private static final Set<String> EXEMPTED_KERNEL_MODULES =
new HashSet<>(
Arrays.asList(
"vts_ltp_test_arm_64.config",
"vts_ltp_test_arm_64_lowmem.config",
"vts_ltp_test_arm_64_hwasan.config",
"vts_ltp_test_arm_64_lowmem_hwasan.config",
"vts_ltp_test_arm.config",
"vts_ltp_test_arm_lowmem.config",
"vts_ltp_test_x86_64.config",
"vts_ltp_test_x86.config",
"vts_linux_kselftest_arm_64.config",
"vts_linux_kselftest_arm_32.config",
"vts_linux_kselftest_x86_64.config",
"vts_linux_kselftest_x86_32.config",
"vts_linux_kselftest_riscv_64.config"));
/**
* Temporarily exempt the current configs so that the test can be submitted to block new
* configs.
*/
private static final Set<String> TEMP_EXEMPTED_MODULES =
new HashSet<>(
Arrays.asList(
"PtsStorageFuncTestCases.config",
"PtsPowerTestCases.config",
"PtsPerformanceLongTestCases.config",
"FirmwareDtboVerification.config",
"net_unittests_tester.config",
"PerfStressTests.config",
"binderHostDeviceTest.config",
"PerfUiGfxTests.config",
"PtsStorageUITestCases.config",
"PtsStoragePerfTestCases.config",
"PtsNgaTestCases.config",
"PerfUiMiscTests.config",
"GtsStatsdHostTestCases.config",
"PtsBackupHostSideTestCases.config",
"PtsStorageQualTestCases.config",
"PtsStoragePowerTestCases.config",
"PtsUipbUnitTests.config",
"PtsSensorHostTestCases.config",
"PerfCheckTests.config",
"cronet_unittests_tester.config",
"PerfUiPreconditionTest.config",
"PtsStorageLongTestCases.config",
"CtsAdServicesCUJTestCases.config",
"hwuimacro.config",
"libinputserialtracker_tests.config",
"MediaProviderTests.config",
"libsurfaceflinger_arc_test.config",
"PtsCoolingMapTests.config",
"hwuimicro.config",
"rustBinderTestService.config",
"hwui_unit_tests.config",
"libinputreader_arc_tests.config",
"PtsTpuPwrStateTests.config",
"CtsAdExtServicesCUJTestCases.config",
"InteractiveNeneTest.config",
"SdkSandboxPerfScenarioTests.config",
"libinputreporter_arc_tests.config",
"libwayland_service_tests.config",
"messagingtests.config",
"GtsPermissionTestCases.config",
"GtsReadLogStringTest.config",
"rustBinderTest.config",
"libsurfaceflinger_arc_backend_test.config",
"MicrodroidBenchmarkApp.config",
"OverlayHostTests.config",
"ComponentAliasTests.config",
"WMShellFlickerTests.config",
"AppEnumerationInternalTests.config",
"ComponentAliasTests2.config",
"ComponentAliasTests1.config",
"NeuralNetworksApiCrashTest.config",
"FrameworksServicesTests.config",
"MediaSampleQueueTests.config",
"HdrTranscodeTests.config",
"MediaSampleReaderNDKTests.config",
"MediaTrackTranscoderTests.config",
"PassthroughTrackTranscoderTests.config",
"MediaTranscoderTests.config",
"VideoTrackTranscoderTests.config",
"MediaSampleWriterTests.config",
"art-run-test-656-checker-simd-opt.config",
"PtsChreTestCases.config",
"chre_nanoapps_loaded.config",
"BiometricsMicrobenchmark.config",
"GoogleSearchPrebuiltDebug.config",
"SystemUIMicrobenchmark.config",
"PlatformScenarioTests.config",
"UiBenchMicrobenchmark_Internal.config",
"CellBroadcastReceiverGoogleUnitTests.config",
"fixed-appstartup-login-base.config",
"open-fixed-calculator.config",
"fixed-appstartup-base.config",
"open-prebuilt-maps.config",
"transition-coldlaunch-phone.config",
"transition-hot-applaunch-from-qs-base.config",
"open-fixed-messages-warm.config",
"transition-hotlaunch-gmail.config",
"open-fixed-chrome-hot.config",
"open-fixed-maps.config",
"open-prebuilt-photos.config",
"open-fixed-phone.config",
"prebuilt-appstartup-login-base.config",
"open-fixed-calculator-flicker.config",
"open-fixed-contacts.config",
"transition-hotlaunch-messages.config",
"open-fixed-gmail-hot.config",
"transition-hotlaunch-calculator.config",
"transition-hotlaunch-maps.config",
"open-fixed-gmail-warm.config",
"open-fixed-calculator-hot.config",
"open-prebuilt-gmail.config",
"transition-coldlaunch-chrome.config",
"open-fixed-chrome.config",
"transition-coldlaunch-maps.config",
"transition-coldlaunch-messages.config",
"transition-hotlaunch-from-qs-calculator.config",
"open-fixed-youtube.config",
"open-prebuilt-clock.config",
"open-prebuilt-youtube.config",
"transition-hotlaunch-phone.config",
"transition-hot-applaunch-from-qs-login-base.config",
"prebuilt-appstartup-base.config",
"open-prebuilt-contacts.config",
"transition-coldlaunch-gmail.config",
"open-fixed-calculator-warm.config",
"appstartup-base.config",
"transition-hotlaunch-from-qs-phone.config",
"AppMicrobenchmark.config",
"open-fixed-clock.config",
"open-prebuilt-phone.config",
"transition-hotlaunch-from-qs-gmail.config",
"open-prebuilt-calendar.config",
"open-fixed-chrome-warm.config",
"open-fixed-calendar.config",
"transition-hot-applaunch-login-base.config",
"transition-hotlaunch-chrome.config",
"open-prebuilt-calculator.config",
"open-fixed-phone-hot.config",
"transition-hot-applaunch-base.config",
"transition-coldlaunch-calculator.config",
"open-fixed-photos.config",
"transition-hotlaunch-from-qs-chrome.config",
"transition-hotlaunch-from-qs-maps.config",
"open-fixed-messages.config",
"open-prebuilt-camera.config",
"open-fixed-phone-warm.config",
"transition-hotlaunch-from-qs-messages.config",
"open-prebuilt-messages.config",
"open-fixed-messages-hot.config",
"open-fixed-camera.config",
"open-fixed-gmail.config",
"GoogleSearchPrebuiltDebugService.config",
"UiBenchJankTests_Internal.config",
"HubUIScenarioTests.config",
"LauncherMicrobenchmark.config",
"MultitaskingTests.config",
"art-run-test-156-register-dex-file-multi-loader.config",
"PtsKmsVBlankTestCases.config",
"PtsGemBltTestCases.config",
"PtsSyncobjBasicTestCases.config",
"PtsKmsAddfbBasicTestCases.config",
"PtsKmsAtomicTransitionTestCases.config",
"PtsKmsThroughputTestCases.config",
"CollectorsHelperTest.config",
"PtsKmsAtomicInterruptibleTestCases.config",
"PtsKmsAtomicTestCases.config",
"PtsKmsPropBlobTestCases.config",
"PtsSyncobjWaitTestCases.config",
"PtsKmsPropertiesTestCases.config",
"PtsKmsPlaneScalingTestCases.config",
"PtsCoreAuthTestCases.config",
"PtsCoreGetclientTestCases.config",
"PtsKmsGetfbTestCases.config",
"PtsKmsFlipTestCases.config",
"s2-geometry-library-java-tests.config"));
@Override
public void setBuild(IBuildInfo buildInfo) {
mBuild = buildInfo;
}
/** Get all the configuration copied to the build tests dir and check if they load. */
@Test
public void testConfigsLoad() throws Exception {
List<String> errors = new ArrayList<>();
Assume.assumeTrue(mBuild instanceof IDeviceBuildInfo);
IConfigurationFactory configFactory = ConfigurationFactory.getInstance();
List<File> configs = new ArrayList<>();
IDeviceBuildInfo deviceBuildInfo = (IDeviceBuildInfo) mBuild;
File testsDir = deviceBuildInfo.getTestsDir();
List<File> extraTestCasesDirs = Arrays.asList(testsDir);
String configPattern = ".*\\." + mConfigExtension + "$";
// include config files with same name, but with different contents (for example: host and
// device variants of the same config).
configs.addAll(
ConfigurationUtil.getConfigNamesFileFromDirs(
null, extraTestCasesDirs, Arrays.asList(configPattern), true));
for (File config : configs) {
try {
IConfiguration c =
configFactory.createConfigurationFromArgs(
new String[] {config.getAbsolutePath()});
// All configurations in general-tests.zip should be module since they are generated
// from AndroidTest.xml
ValidateSuiteConfigHelper.validateConfig(c);
for (IDeviceConfiguration dConfig : c.getDeviceConfig()) {
validatePreparers(config, dConfig.getTargetPreparers());
}
// Check that all the tests runners are well supported.
checkRunners(c.getTests(), "general-tests");
ConfigurationDescriptor cd = c.getConfigurationDescription();
checkModuleParameters(c.getName(), cd.getMetaData(ITestSuite.PARAMETER_KEY));
// Check for disallowed test types
checkDisallowedTestType(c, mDisallowedTestTypes);
// Add more checks if necessary
} catch (ConfigurationException e) {
errors.add(String.format("\t%s: %s", config.getName(), e.getMessage()));
}
}
// If any errors report them in a final exception.
if (!errors.isEmpty()) {
throw new ConfigurationException(
String.format("Fail configuration check:\n%s", Joiner.on("\n").join(errors)));
}
}
public static void validatePreparers(File config, List<ITargetPreparer> preparers)
throws Exception {
if (EXEMPTED_PYTHON_TEST_MODULES.contains(config.getName())) {
LogUtil.CLog.w(
"Module %s is a python_test_host module. Ignoring until b/274930471 is fixed.s",
config.getName());
return;
}
if (EXEMPTED_KERNEL_MODULES.contains(config.getName())) {
LogUtil.CLog.w("Ignoring module %s until b/277261121 is fixed.s", config.getName());
return;
}
if (MEDIAPREPARER_EXEMPTED_CONFIGS.contains(config.getName())) {
LogUtil.CLog.w(
"Module %s is exempted until b/274674920 is fixed. Please Fix the config.",
config.getName());
return;
}
if (TEMP_EXEMPTED_MODULES.contains(config.getName())) {
LogUtil.CLog.w("Ignoring module %s temporarily.", config.getName());
return;
}
for (ITargetPreparer preparer : preparers) {
if (preparer instanceof TestAppInstallSetup) {
List<File> apkNames = new ArrayList<>();
TestAppInstallSetup installer = (TestAppInstallSetup) preparer;
// Ensure clean up is enabled
if (!installer.isCleanUpEnabled()) {
throw new ConfigurationException(
String.format("Config: %s should set cleanup-apks=true.", config));
}
apkNames.addAll(((TestAppInstallSetup) preparer).getTestsFileName());
// Ensure all apk dependencies are specified
for (File apk : apkNames) {
String apkName = apk.getName();
File apkFile = FileUtil.findFile(config.getParentFile(), apkName);
if (apkFile == null || !apkFile.exists()) {
throw new ConfigurationException(
String.format(
"Module %s is trying to install %s which does not "
+ "exists in testcases/. Make sure that it's added "
+ "in the Android.bp file of the module under "
+ "'data' field.",
config.getName(), apkName));
}
}
}
if (preparer instanceof PushFilePreparer) {
PushFilePreparer pusher = (PushFilePreparer) preparer;
if (!pusher.isCleanUpEnabled()) {
throw new ConfigurationException(
String.format(
"Config: %s should set cleanup=true for file pusher.", config));
}
for (File f : pusher.getPushSpecs(null).values()) {
String path = f.getPath();
// Use findFiles to also match top-level dir, which is a valid push spec
Set<String> toBePushed = FileUtil.findFiles(config.getParentFile(), path);
if (toBePushed.isEmpty()) {
// See if binary files exists
File file32 = FileUtil.findFile(config.getParentFile(), path + "32");
File file64 = FileUtil.findFile(config.getParentFile(), path + "64");
if (file32 == null || file64 == null) {
throw new ConfigurationException(
String.format(
"File %s wasn't found in module dependencies while it's"
+ " expected to be pushed as part of %s. Make"
+ " sure that it's added in the Android.bp file"
+ " of the module under 'data_device_bins_both'"
+ " field if it's a binary file or under 'data'"
+ " field for all other files.",
path, config.getName()));
}
}
}
}
}
}
public static void checkRunners(List<IRemoteTest> tests, String name)
throws ConfigurationException {
for (IRemoteTest test : tests) {
// Check that all the tests runners are well supported.
if (!SUPPORTED_TEST_RUNNERS.contains(test.getClass().getCanonicalName())) {
throw new ConfigurationException(
String.format(
"testtype %s is not officially supported in %s. "
+ "The supported ones are: %s",
test.getClass().getCanonicalName(), name, SUPPORTED_TEST_RUNNERS));
}
if (test instanceof IsolatedHostTest
&& ((IsolatedHostTest) test).useRobolectricResources()) {
throw new ConfigurationException(
String.format(
"Robolectric tests aren't supported in general-tests yet. They"
+ " have their own setup."));
}
}
}
public static void checkModuleParameters(String configName, List<String> parameters)
throws ConfigurationException {
if (parameters == null) {
return;
}
for (String param : parameters) {
try {
ModuleParameters.valueOf(param.toUpperCase());
} catch (IllegalArgumentException e) {
throw new ConfigurationException(
String.format(
"Config: %s includes an unknown parameter '%s'.",
configName, param));
}
}
}
/**
* Check the {@link config} to ensure it's not declared as one of the {#link
* disallowedTestTypes}.
*
* @param config The config to check.
* @param ConfigurationException The disallowed test types to check against.
* @throws ConfigurationException if the config is of disallowed test types.
*/
public static void checkDisallowedTestType(
IConfiguration config, List<String> disallowedTestTypes) throws ConfigurationException {
if (disallowedTestTypes == null || disallowedTestTypes.isEmpty()) {
return;
}
List<String> matched =
ModuleTestTypeUtil.getMatchedConfigTestTypes(config, disallowedTestTypes);
if (!matched.isEmpty()) {
throw new ConfigurationException(
String.format(
"Config %s of test type '%s' is not allowed.",
config.getName(), Joiner.on(", ").join(matched)));
}
}
}