• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.IDeviceConfiguration;
22 import com.android.tradefed.config.Option;
23 import com.android.tradefed.config.Option.Importance;
24 import com.android.tradefed.config.OptionCopier;
25 import com.android.tradefed.log.LogUtil.CLog;
26 import com.android.tradefed.result.ITestInvocationListener;
27 import com.android.tradefed.result.SubprocessResultsReporter;
28 import com.android.tradefed.targetprep.ITargetPreparer;
29 import com.android.tradefed.targetprep.incremental.IIncrementalSetup;
30 import com.android.tradefed.testtype.IAbi;
31 import com.android.tradefed.testtype.IRemoteTest;
32 import com.android.tradefed.testtype.ITestFilterReceiver;
33 import com.android.tradefed.testtype.InstrumentationTest;
34 import com.android.tradefed.testtype.IsolatedHostTest;
35 
36 import java.io.File;
37 import java.util.ArrayList;
38 import java.util.HashSet;
39 import java.util.LinkedHashMap;
40 import java.util.LinkedHashSet;
41 import java.util.List;
42 import java.util.Set;
43 import java.util.regex.Matcher;
44 import java.util.regex.Pattern;
45 
46 
47 /** Implementation of {@link ITestSuite} */
48 public class AtestRunner extends BaseTestSuite {
49 
50     private static final Pattern CONFIG_RE =
51             Pattern.compile(".*/(?<config>[^/]+).config", Pattern.CASE_INSENSITIVE);
52 
53     @Option(name = "all-abi", description = "Determine run all abi or not.")
54     private boolean mAllAbi = false;
55 
56     @Option(
57         name = "wait-for-debugger",
58         description = "For InstrumentationTests, we pass debug to the instrumentation run."
59     )
60     private boolean mDebug = false;
61 
62     @Option(
63         name = "disable-target-preparers",
64         description =
65                 "Skip the target preparer steps enumerated in test config. Skips the teardown step "
66                         + "as well."
67     )
68     private boolean mSkipSetUp = false;
69 
70     @Option(name = "disable-teardown", description = "Skip the teardown of the target preparers.")
71     private boolean mSkipTearDown = false;
72 
73     @Option(
74         name = "subprocess-report-port",
75         description = "the port where to connect to send the" + "events."
76     )
77     private Integer mReportPort = null;
78 
79     @Option(
80         name = "atest-include-filter",
81         description =
82                 "the include filters to pass to a module. The expected format is"
83                         + "\"<module-name>:<include-filter-value>\"",
84         importance = Importance.ALWAYS
85     )
86     private List<String> mIncludeFilters = new ArrayList<>();
87 
88     @Option(
89         name = "tf-config-path",
90         description =
91                 "Allows to run a specific TF configuration path."
92     )
93     private List<String> mTfConfigPaths = new ArrayList<>();
94 
95     @Option(
96         name = "module-config-path",
97         description =
98                 "Allows to run a specific module configuration path."
99     )
100     private List<File> mModuleConfigPaths = new ArrayList<>();
101 
102     @Option(
103         name = "incremental-setup",
104         description =
105                 "Indicates the user specification of whether to enable incremental setup, "
106                     + "default to UNSPECIFIED."
107     )
108     private IncrementalSetupEnabled mIncrementalSetupEnabled = IncrementalSetupEnabled.UNSPECIFIED;
109 
110     private static enum IncrementalSetupEnabled {
111         UNSPECIFIED,
112         NO,
113         YES,
114     }
115 
AtestRunner()116     public AtestRunner() {
117         setMultiDeviceStrategy(MultiDeviceModuleStrategy.RUN);
118     }
119 
120     @Override
loadingStrategy(Set<IAbi> abis, List<File> testsDirs, String suitePrefix, String suiteTag)121     public LinkedHashMap<String, IConfiguration> loadingStrategy(Set<IAbi> abis,
122         List<File> testsDirs,
123         String suitePrefix, String suiteTag) {
124         if (mTfConfigPaths.isEmpty() && mModuleConfigPaths.isEmpty()) {
125             return super.loadingStrategy(abis, testsDirs, suitePrefix, suiteTag);
126         }
127         LinkedHashMap<String, IConfiguration> loadedConfigs = new LinkedHashMap<>();
128         loadedConfigs.putAll(
129                 getModuleLoader().loadTfConfigsFromSpecifiedPaths(mTfConfigPaths, abis, suiteTag));
130         loadedConfigs.putAll(
131                 getModuleLoader().loadConfigsFromSpecifiedPaths(
132                         mModuleConfigPaths, abis, suiteTag));
133         return loadedConfigs;
134     }
135 
136     @Override
loadTests()137     public LinkedHashMap<String, IConfiguration> loadTests() {
138         // atest only needs to run on primary or specified abi.
139         if (getRequestedAbi() == null && !mAllAbi) {
140             setPrimaryAbiRun(true);
141         }
142         LinkedHashMap<String, IConfiguration> configMap = super.loadTests();
143         LinkedHashMap<String, HashSet<String>> includeFilters = getIncludeFilters();
144         for (IConfiguration testConfig : configMap.values()) {
145             if (mSkipSetUp || mSkipTearDown) {
146                 disableTargetPreparers(testConfig, mSkipSetUp, mSkipTearDown);
147             }
148             if (mDebug) {
149                 addDebugger(testConfig);
150             }
151 
152             if (mIncrementalSetupEnabled == IncrementalSetupEnabled.YES) {
153                 setIncrementalSetupEnabledForTargetPreparers(testConfig, /* shouldEnable= */ true);
154             } else if (mIncrementalSetupEnabled == IncrementalSetupEnabled.NO) {
155                 setIncrementalSetupEnabledForTargetPreparers(testConfig, /* shouldEnable= */ false);
156             }
157 
158             // Inject include-filter to test.
159             HashSet<String> moduleFilters =
160                     includeFilters.get(canonicalizeConfigName(testConfig.getName()));
161             if (moduleFilters != null) {
162                 for (String filter : moduleFilters) {
163                     addFilter(testConfig, filter);
164                 }
165             }
166         }
167 
168         return configMap;
169     }
170 
171     /** Get a collection of include filters grouped by module name. */
getIncludeFilters()172     private LinkedHashMap<String, HashSet<String>> getIncludeFilters() {
173         LinkedHashMap<String, HashSet<String>> includeFilters =
174                 new LinkedHashMap<String, HashSet<String>>();
175         for (String filter : mIncludeFilters) {
176             int moduleSep = filter.indexOf(":");
177             if (moduleSep == -1) {
178                 throw new RuntimeException("Expected delimiter ':' for module or class.");
179             }
180             String moduleName = canonicalizeConfigName(filter.substring(0, moduleSep));
181             String moduleFilter = filter.substring(moduleSep + 1);
182             HashSet<String> moduleFilters = includeFilters.get(moduleName);
183             if (moduleFilters == null) {
184                 moduleFilters = new LinkedHashSet<>();
185                 includeFilters.put(moduleName, moduleFilters);
186             }
187             moduleFilters.add(moduleFilter);
188         }
189         return includeFilters;
190     }
191 
192     /**
193      * Non-integrated modules have full file paths as their name, .e.g /foo/bar/name.config, but all
194      * we want is the name.
195      */
canonicalizeConfigName(String originalName)196     private String canonicalizeConfigName(String originalName) {
197         Matcher match = CONFIG_RE.matcher(originalName);
198         if (match.find()) {
199             return match.group("config");
200         }
201         return originalName;
202     }
203 
204     /**
205      * Add filter to the tests in an IConfiguration.
206      *
207      * @param testConfig The configuration containing tests to filter.
208      * @param filter The filter to add to the tests in the testConfig.
209      */
addFilter(IConfiguration testConfig, String filter)210     private void addFilter(IConfiguration testConfig, String filter) {
211         List<IRemoteTest> tests = testConfig.getTests();
212         for (IRemoteTest test : tests) {
213             if (test instanceof ITestFilterReceiver) {
214                 CLog.d(
215                         "%s:%s - Applying filter (%s)",
216                         testConfig.getName(), test.getClass().getSimpleName(), filter);
217                 ((ITestFilterReceiver) test).addIncludeFilter(filter);
218             } else {
219                 CLog.e(
220                         "Test Class (%s) does not support filtering. Cannot apply filter: %s.\n"
221                                 + "Please update test to use a class that implements "
222                                 + "ITestFilterReceiver. Running entire test module instead.",
223                         test.getClass().getSimpleName(), filter);
224             }
225         }
226     }
227 
228     /** Return a ConfigurationFactory instance. Organized this way for testing purposes. */
loadConfigFactory()229     public IConfigurationFactory loadConfigFactory() {
230         return ConfigurationFactory.getInstance();
231     }
232 
233     /** {@inheritDoc} */
234     @Override
createModuleListeners()235     protected List<ITestInvocationListener> createModuleListeners() {
236         List<ITestInvocationListener> listeners = super.createModuleListeners();
237         if (mReportPort != null) {
238             SubprocessResultsReporter subprocessResult = new SubprocessResultsReporter();
239             OptionCopier.copyOptionsNoThrow(this, subprocessResult);
240             listeners.add(subprocessResult);
241         }
242         return listeners;
243     }
244 
245     /** Helper to attach the debugger to any Instrumentation tests in the config. */
addDebugger(IConfiguration testConfig)246     private void addDebugger(IConfiguration testConfig) {
247         for (IRemoteTest test : testConfig.getTests()) {
248             if (test instanceof InstrumentationTest) {
249                 ((InstrumentationTest) test).setDebug(true);
250             }
251             if (test instanceof IsolatedHostTest) {
252                 ((IsolatedHostTest) test).setDebug(true);
253             }
254         }
255     }
256 
257     /** Helper to disable TargetPreparers of a test. */
disableTargetPreparers( IConfiguration testConfig, boolean skipSetUp, boolean skipTearDown)258     private void disableTargetPreparers(
259             IConfiguration testConfig, boolean skipSetUp, boolean skipTearDown) {
260         for (ITargetPreparer targetPreparer : testConfig.getTargetPreparers()) {
261             if (skipSetUp) {
262                 CLog.d(
263                         "%s: Disabling Target Preparer (%s)",
264                         testConfig.getName(), targetPreparer.getClass().getSimpleName());
265                 targetPreparer.setDisable(true);
266             } else if (skipTearDown) {
267                 CLog.d(
268                         "%s: Disabling Target Preparer TearDown (%s)",
269                         testConfig.getName(), targetPreparer.getClass().getSimpleName());
270                 targetPreparer.setDisableTearDown(true);
271             }
272         }
273     }
274 
275     /**
276      * Helper to set incremental setup enabled or disabled to TargetPreparers of a test.
277      *
278      * @param testConfig the test config which contains all target preparers.
279      * @param shouldEnable {@code true} to enable incremental setup, otherwise disable incremental
280      *     setup.
281      */
setIncrementalSetupEnabledForTargetPreparers( IConfiguration testConfig, boolean shouldEnable)282     private static void setIncrementalSetupEnabledForTargetPreparers(
283         IConfiguration testConfig, boolean shouldEnable) {
284         for (IDeviceConfiguration deviceConfig : testConfig.getDeviceConfig()) {
285             for (ITargetPreparer targetPreparer : deviceConfig.getTargetPreparers()) {
286                 if (targetPreparer instanceof IIncrementalSetup) {
287                     ((IIncrementalSetup) targetPreparer).setIncrementalSetupEnabled(shouldEnable);
288                 }
289             }
290         }
291     }
292 }
293