1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.tradefed.testtype.suite; 17 18 import com.android.tradefed.config.ConfigurationFactory; 19 import com.android.tradefed.config.IConfiguration; 20 import com.android.tradefed.config.IConfigurationFactory; 21 import com.android.tradefed.config.Option; 22 import com.android.tradefed.config.OptionCopier; 23 import com.android.tradefed.config.Option.Importance; 24 import com.android.tradefed.log.LogUtil.CLog; 25 import com.android.tradefed.result.ITestInvocationListener; 26 import com.android.tradefed.result.SubprocessResultsReporter; 27 import com.android.tradefed.targetprep.ITargetPreparer; 28 import com.android.tradefed.testtype.IAbi; 29 import com.android.tradefed.testtype.InstrumentationTest; 30 import com.android.tradefed.testtype.IRemoteTest; 31 import com.android.tradefed.testtype.ITestFilterReceiver; 32 import java.io.File; 33 import java.util.ArrayList; 34 import java.util.HashSet; 35 import java.util.LinkedHashMap; 36 import java.util.List; 37 import java.util.Set; 38 import java.util.regex.Matcher; 39 import java.util.regex.Pattern; 40 41 42 /** Implementation of {@link ITestSuite} */ 43 public class AtestRunner extends BaseTestSuite { 44 45 private static final Pattern CONFIG_RE = 46 Pattern.compile(".*/(?<config>[^/]+).config", Pattern.CASE_INSENSITIVE); 47 48 @Option(name = "all-abi", description = "Determine run all abi or not.") 49 private boolean mAllAbi = false; 50 51 @Option( 52 name = "wait-for-debugger", 53 description = "For InstrumentationTests, we pass debug to the instrumentation run." 54 ) 55 private boolean mDebug = false; 56 57 @Option( 58 name = "disable-target-preparers", 59 description = 60 "Skip the target preparer steps enumerated in test config. Skips the teardown step " 61 + "as well." 62 ) 63 private boolean mSkipSetUp = false; 64 65 @Option(name = "disable-teardown", description = "Skip the teardown of the target preparers.") 66 private boolean mSkipTearDown = false; 67 68 @Option( 69 name = "subprocess-report-port", 70 description = "the port where to connect to send the" + "events." 71 ) 72 private Integer mReportPort = null; 73 74 @Option( 75 name = "atest-include-filter", 76 description = 77 "the include filters to pass to a module. The expected format is" 78 + "\"<module-name>:<include-filter-value>\"", 79 importance = Importance.ALWAYS 80 ) 81 private List<String> mIncludeFilters = new ArrayList<>(); 82 83 @Option( 84 name = "tf-config-path", 85 description = 86 "Allows to run a specific TF configuration path." 87 ) 88 private List<String> mTfConfigPaths = new ArrayList<>(); 89 90 @Option( 91 name = "module-config-path", 92 description = 93 "Allows to run a specific module configuration path." 94 ) 95 private List<File> mModuleConfigPaths = new ArrayList<>(); 96 97 @Override loadingStrategy(Set<IAbi> abis, List<File> testsDirs, String suitePrefix, String suiteTag)98 public LinkedHashMap<String, IConfiguration> loadingStrategy(Set<IAbi> abis, 99 List<File> testsDirs, 100 String suitePrefix, String suiteTag) { 101 if (mTfConfigPaths.isEmpty() && mModuleConfigPaths.isEmpty()) { 102 return super.loadingStrategy(abis, testsDirs, suitePrefix, suiteTag); 103 } 104 LinkedHashMap<String, IConfiguration> loadedConfigs = new LinkedHashMap<>(); 105 loadedConfigs.putAll( 106 getModuleLoader().loadTfConfigsFromSpecifiedPaths(mTfConfigPaths, abis, suiteTag)); 107 loadedConfigs.putAll( 108 getModuleLoader().loadConfigsFromSpecifiedPaths( 109 mModuleConfigPaths, abis, suiteTag)); 110 return loadedConfigs; 111 } 112 113 @Override loadTests()114 public LinkedHashMap<String, IConfiguration> loadTests() { 115 // atest only needs to run on primary or specified abi. 116 if (getRequestedAbi() == null && !mAllAbi) { 117 setPrimaryAbiRun(true); 118 } 119 LinkedHashMap<String, IConfiguration> configMap = super.loadTests(); 120 LinkedHashMap<String, HashSet<String>> includeFilters = getIncludeFilters(); 121 for (IConfiguration testConfig : configMap.values()) { 122 if (mSkipSetUp || mSkipTearDown) { 123 disableTargetPreparers(testConfig, mSkipSetUp, mSkipTearDown); 124 } 125 if (mDebug) { 126 addDebugger(testConfig); 127 } 128 129 // Inject include-filter to test. 130 HashSet<String> moduleFilters = 131 includeFilters.get(canonicalizeConfigName(testConfig.getName())); 132 if (moduleFilters != null) { 133 for (String filter : moduleFilters) { 134 addFilter(testConfig, filter); 135 } 136 } 137 } 138 139 return configMap; 140 } 141 142 /** Get a collection of include filters grouped by module name. */ getIncludeFilters()143 private LinkedHashMap<String, HashSet<String>> getIncludeFilters() { 144 LinkedHashMap<String, HashSet<String>> includeFilters = 145 new LinkedHashMap<String, HashSet<String>>(); 146 for (String filter : mIncludeFilters) { 147 int moduleSep = filter.indexOf(":"); 148 if (moduleSep == -1) { 149 throw new RuntimeException("Expected delimiter ':' for module or class."); 150 } 151 String moduleName = canonicalizeConfigName(filter.substring(0, moduleSep)); 152 String moduleFilter = filter.substring(moduleSep + 1); 153 HashSet<String> moduleFilters = includeFilters.get(moduleName); 154 if (moduleFilters == null) { 155 moduleFilters = new HashSet<String>(); 156 includeFilters.put(moduleName, moduleFilters); 157 } 158 moduleFilters.add(moduleFilter); 159 } 160 return includeFilters; 161 } 162 163 /** 164 * Non-integrated modules have full file paths as their name, .e.g /foo/bar/name.config, but all 165 * we want is the name. 166 */ canonicalizeConfigName(String originalName)167 private String canonicalizeConfigName(String originalName) { 168 Matcher match = CONFIG_RE.matcher(originalName); 169 if (match.find()) { 170 return match.group("config"); 171 } 172 return originalName; 173 } 174 175 /** 176 * Add filter to the tests in an IConfiguration. 177 * 178 * @param testConfig The configuration containing tests to filter. 179 * @param filter The filter to add to the tests in the testConfig. 180 */ addFilter(IConfiguration testConfig, String filter)181 private void addFilter(IConfiguration testConfig, String filter) { 182 List<IRemoteTest> tests = testConfig.getTests(); 183 for (IRemoteTest test : tests) { 184 if (test instanceof ITestFilterReceiver) { 185 CLog.d( 186 "%s:%s - Applying filter (%s)", 187 testConfig.getName(), test.getClass().getSimpleName(), filter); 188 ((ITestFilterReceiver) test).addIncludeFilter(filter); 189 } else { 190 CLog.e( 191 "Test Class (%s) does not support filtering. Cannot apply filter: %s.\n" 192 + "Please update test to use a class that implements " 193 + "ITestFilterReceiver. Running entire test module instead.", 194 test.getClass().getSimpleName(), filter); 195 } 196 } 197 } 198 199 /** Return a ConfigurationFactory instance. Organized this way for testing purposes. */ loadConfigFactory()200 public IConfigurationFactory loadConfigFactory() { 201 return ConfigurationFactory.getInstance(); 202 } 203 204 /** {@inheritDoc} */ 205 @Override createModuleListeners()206 protected List<ITestInvocationListener> createModuleListeners() { 207 List<ITestInvocationListener> listeners = super.createModuleListeners(); 208 if (mReportPort != null) { 209 SubprocessResultsReporter subprocessResult = new SubprocessResultsReporter(); 210 OptionCopier.copyOptionsNoThrow(this, subprocessResult); 211 listeners.add(subprocessResult); 212 } 213 return listeners; 214 } 215 216 /** Helper to attach the debugger to any Instrumentation tests in the config. */ addDebugger(IConfiguration testConfig)217 private void addDebugger(IConfiguration testConfig) { 218 for (IRemoteTest test : testConfig.getTests()) { 219 if (test instanceof InstrumentationTest) { 220 ((InstrumentationTest) test).setDebug(true); 221 } 222 } 223 } 224 225 /** Helper to disable TargetPreparers of a test. */ disableTargetPreparers( IConfiguration testConfig, boolean skipSetUp, boolean skipTearDown)226 private void disableTargetPreparers( 227 IConfiguration testConfig, boolean skipSetUp, boolean skipTearDown) { 228 for (ITargetPreparer targetPreparer : testConfig.getTargetPreparers()) { 229 if (skipSetUp) { 230 CLog.d( 231 "%s: Disabling Target Preparer (%s)", 232 testConfig.getName(), targetPreparer.getClass().getSimpleName()); 233 targetPreparer.setDisable(true); 234 } else if (skipTearDown) { 235 CLog.d( 236 "%s: Disabling Target Preparer TearDown (%s)", 237 testConfig.getName(), targetPreparer.getClass().getSimpleName()); 238 targetPreparer.setDisableTearDown(true); 239 } 240 } 241 } 242 } 243