• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.ConfigurationDef.OptionDef;
19 import com.android.tradefed.config.ConfigurationException;
20 import com.android.tradefed.config.ConfigurationFactory;
21 import com.android.tradefed.config.ConfigurationUtil;
22 import com.android.tradefed.config.IConfiguration;
23 import com.android.tradefed.config.IConfigurationFactory;
24 import com.android.tradefed.log.LogUtil.CLog;
25 import com.android.tradefed.targetprep.ITargetPreparer;
26 import com.android.tradefed.testtype.IAbi;
27 import com.android.tradefed.testtype.IAbiReceiver;
28 import com.android.tradefed.testtype.IRemoteTest;
29 import com.android.tradefed.testtype.ITestFileFilterReceiver;
30 import com.android.tradefed.testtype.ITestFilterReceiver;
31 import com.android.tradefed.testtype.suite.params.IModuleParameter;
32 import com.android.tradefed.testtype.suite.params.ModuleParameters;
33 import com.android.tradefed.testtype.suite.params.ModuleParametersHelper;
34 import com.android.tradefed.testtype.suite.params.NegativeHandler;
35 import com.android.tradefed.testtype.suite.params.NotMultiAbiHandler;
36 import com.android.tradefed.util.AbiUtils;
37 import com.android.tradefed.util.FileUtil;
38 import com.android.tradefed.util.StreamUtil;
39 
40 import com.google.common.base.Strings;
41 
42 import java.io.File;
43 import java.io.FilenameFilter;
44 import java.io.IOException;
45 import java.io.PrintWriter;
46 import java.util.ArrayList;
47 import java.util.Arrays;
48 import java.util.Collection;
49 import java.util.Collections;
50 import java.util.HashMap;
51 import java.util.HashSet;
52 import java.util.LinkedHashMap;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Set;
56 import java.util.regex.Matcher;
57 import java.util.regex.Pattern;
58 
59 /**
60  * Retrieves Compatibility test module definitions from the repository. TODO: Add the expansion of
61  * suite when loading a module.
62  */
63 public class SuiteModuleLoader {
64 
65     public static final String CONFIG_EXT = ".config";
66     private Map<String, List<OptionDef>> mTestOptions = new HashMap<>();
67     private Map<String, List<OptionDef>> mModuleOptions = new HashMap<>();
68     private boolean mIncludeAll;
69     private Map<String, List<SuiteTestFilter>> mIncludeFilters = new HashMap<>();
70     private Map<String, List<SuiteTestFilter>> mExcludeFilters = new HashMap<>();
71     private IConfigurationFactory mConfigFactory = ConfigurationFactory.getInstance();
72 
73     private boolean mAllowParameterizedModules = false;
74     private ModuleParameters mForcedModuleParameter = null;
75     private Set<ModuleParameters> mExcludedModuleParameters = new HashSet<>();
76 
77     /**
78      * Ctor for the SuiteModuleLoader.
79      *
80      * @param includeFilters The formatted and parsed include filters.
81      * @param excludeFilters The formatted and parsed exclude filters.
82      * @param testArgs the list of test ({@link IRemoteTest}) arguments.
83      * @param moduleArgs the list of module arguments.
84      */
SuiteModuleLoader( Map<String, List<SuiteTestFilter>> includeFilters, Map<String, List<SuiteTestFilter>> excludeFilters, List<String> testArgs, List<String> moduleArgs)85     public SuiteModuleLoader(
86             Map<String, List<SuiteTestFilter>> includeFilters,
87             Map<String, List<SuiteTestFilter>> excludeFilters,
88             List<String> testArgs,
89             List<String> moduleArgs) {
90         mIncludeAll = includeFilters.isEmpty();
91         mIncludeFilters = includeFilters;
92         mExcludeFilters = excludeFilters;
93 
94         parseArgs(testArgs, mTestOptions);
95         parseArgs(moduleArgs, mModuleOptions);
96     }
97 
98     /** Sets whether or not to allow parameterized modules. */
setParameterizedModules(boolean allowed)99     public final void setParameterizedModules(boolean allowed) {
100         mAllowParameterizedModules = allowed;
101     }
102 
103     /** Sets the only {@link ModuleParameters} type that should be run. */
setModuleParameter(ModuleParameters param)104     public final void setModuleParameter(ModuleParameters param) {
105         mForcedModuleParameter = param;
106     }
107 
108     /** Sets the set of {@link ModuleParameters} that should not be considered at all. */
setExcludedModuleParameters(Set<ModuleParameters> excludedParams)109     public final void setExcludedModuleParameters(Set<ModuleParameters> excludedParams) {
110         mExcludedModuleParameters = excludedParams;
111     }
112 
113     /** Main loading of configurations, looking into a folder */
loadConfigsFromDirectory( List<File> testsDirs, Set<IAbi> abis, String suitePrefix, String suiteTag, List<String> patterns)114     public LinkedHashMap<String, IConfiguration> loadConfigsFromDirectory(
115             List<File> testsDirs,
116             Set<IAbi> abis,
117             String suitePrefix,
118             String suiteTag,
119             List<String> patterns) {
120         LinkedHashMap<String, IConfiguration> toRun = new LinkedHashMap<>();
121         List<File> listConfigFiles = new ArrayList<>();
122         listConfigFiles.addAll(
123                 ConfigurationUtil.getConfigNamesFileFromDirs(suitePrefix, testsDirs, patterns));
124         // Ensure stable initial order of configurations.
125         Collections.sort(listConfigFiles);
126         for (File configFile : listConfigFiles) {
127             toRun.putAll(
128                     loadOneConfig(
129                             configFile.getName(), configFile.getAbsolutePath(), abis, suiteTag));
130         }
131         return toRun;
132     }
133 
134     /**
135      * Main loading of configurations, looking into the resources on the classpath. (TF configs for
136      * example).
137      */
loadConfigsFromJars( Set<IAbi> abis, String suitePrefix, String suiteTag)138     public LinkedHashMap<String, IConfiguration> loadConfigsFromJars(
139             Set<IAbi> abis, String suitePrefix, String suiteTag) {
140         LinkedHashMap<String, IConfiguration> toRun = new LinkedHashMap<>();
141 
142         IConfigurationFactory configFactory = ConfigurationFactory.getInstance();
143         List<String> configs = configFactory.getConfigList(suitePrefix, false);
144         // Sort configs to ensure they are always evaluated and added in the same order.
145         Collections.sort(configs);
146         for (String configName : configs) {
147             toRun.putAll(loadOneConfig(configName, configName, abis, suiteTag));
148         }
149         return toRun;
150     }
151 
152     /**
153      * Pass the filters to the {@link IRemoteTest}. Default behavior is to ignore if the IRemoteTest
154      * does not implements {@link ITestFileFilterReceiver}. This can be overriden to create a more
155      * restrictive behavior.
156      *
157      * @param test The {@link IRemoteTest} that is being considered.
158      * @param abi The Abi we are currently working on.
159      * @param name The name of the module.
160      * @param includeFilters The formatted and parsed include filters.
161      * @param excludeFilters The formatted and parsed exclude filters.
162      */
addFiltersToTest( IRemoteTest test, IAbi abi, String name, Map<String, List<SuiteTestFilter>> includeFilters, Map<String, List<SuiteTestFilter>> excludeFilters)163     public void addFiltersToTest(
164             IRemoteTest test,
165             IAbi abi,
166             String name,
167             Map<String, List<SuiteTestFilter>> includeFilters,
168             Map<String, List<SuiteTestFilter>> excludeFilters) {
169         String moduleId = AbiUtils.createId(abi.getName(), name);
170         if (!(test instanceof ITestFilterReceiver)) {
171             CLog.e("Test in module %s does not implement ITestFilterReceiver.", moduleId);
172             return;
173         }
174         List<SuiteTestFilter> mdIncludes = getFilterList(includeFilters, moduleId);
175         List<SuiteTestFilter> mdExcludes = getFilterList(excludeFilters, moduleId);
176         if (!mdIncludes.isEmpty()) {
177             addTestIncludes((ITestFilterReceiver) test, mdIncludes, name);
178         }
179         if (!mdExcludes.isEmpty()) {
180             addTestExcludes((ITestFilterReceiver) test, mdExcludes, name);
181         }
182     }
183 
184     /**
185      * Load a single config location (file or on TF classpath). It can results in several {@link
186      * IConfiguration}. If a single configuration get expanded in different ways.
187      *
188      * @param configName The actual config name only. (no path)
189      * @param configFullName The fully qualified config name. (with path, if any).
190      * @param abis The set of all abis that needs to run.
191      * @param suiteTag the Tag of the suite aimed to be run.
192      * @return A map of loaded configuration.
193      */
loadOneConfig( String configName, String configFullName, Set<IAbi> abis, String suiteTag)194     private LinkedHashMap<String, IConfiguration> loadOneConfig(
195             String configName, String configFullName, Set<IAbi> abis, String suiteTag) {
196         LinkedHashMap<String, IConfiguration> toRun = new LinkedHashMap<>();
197         final String name = configName.replace(CONFIG_EXT, "");
198         final String[] pathArg = new String[] {configFullName};
199         try {
200             boolean primaryAbi = true;
201             boolean shouldCreateMultiAbi = true;
202             // If a particular parameter was requested to be run, find it.
203             IModuleParameter mForcedParameter = null;
204             if (mForcedModuleParameter != null) {
205                 mForcedParameter =
206                         ModuleParametersHelper.getParameterHandler(
207                                 mForcedModuleParameter, /* optionalParams */ false);
208             }
209 
210             // Invokes parser to process the test module config file
211             // Need to generate a different config for each ABI as we cannot guarantee the
212             // configs are idempotent. This however means we parse the same file multiple times
213             for (IAbi abi : abis) {
214                 // Only enable the primary abi filtering when switching to the parameterized mode
215                 if (mAllowParameterizedModules && !primaryAbi && !shouldCreateMultiAbi) {
216                     continue;
217                 }
218                 String baseId = AbiUtils.createId(abi.getName(), name);
219                 IConfiguration config = null;
220                 try {
221                     config = mConfigFactory.createConfigurationFromArgs(pathArg);
222                 } catch (ConfigurationException e) {
223                     // If the module should not have been running in the first place, give it a
224                     // pass on the configuration failure.
225                     if (!shouldRunModule(baseId)) {
226                         primaryAbi = false;
227                         // If the module should not run tests based on the state of filters,
228                         // skip this name/abi combination.
229                         continue;
230                     }
231                     throw e;
232                 }
233 
234                 // If a suiteTag is used, we load with it.
235                 if (!Strings.isNullOrEmpty(suiteTag)
236                         && !config.getConfigurationDescription()
237                                 .getSuiteTags()
238                                 .contains(suiteTag)) {
239                     // Do not print here, it could leave several hundred lines of logs.
240                     continue;
241                 }
242 
243                 boolean skipCreatingBaseConfig = false;
244                 List<IModuleParameter> params = null;
245                 try {
246                     params = getModuleParameters(name, config);
247                 } catch (ConfigurationException e) {
248                     // If the module should not have been running in the first place, give it a
249                     // pass on the configuration failure.
250                     if (!shouldRunModule(baseId)) {
251                         primaryAbi = false;
252                         // If the module should not run tests based on the state of filters,
253                         // skip this name/abi combination.
254                         continue;
255                     }
256                     throw e;
257                 }
258 
259                 // Handle parameterized modules if enabled.
260                 if (mAllowParameterizedModules) {
261 
262                     if (params.isEmpty()
263                             && mForcedParameter != null
264                             && !(mForcedParameter instanceof NegativeHandler)) {
265                         // If the AndroidTest.xml doesn't specify any parameter but we forced a
266                         // parameter like 'instant' to execute. In this case we don't create the
267                         // standard module.
268                         continue;
269                     }
270 
271                     shouldCreateMultiAbi = shouldCreateMultiAbiForBase(params);
272 
273                     // If we find any parameterized combination.
274                     for (IModuleParameter param : params) {
275                         if (param instanceof NegativeHandler) {
276                             if (mForcedParameter != null
277                                     && !param.getClass().equals(mForcedParameter.getClass())) {
278                                 skipCreatingBaseConfig = true;
279                             }
280                             continue;
281                         }
282                         if (mForcedParameter != null) {
283                             // When a particular parameter is forced, only create it not the others
284                             if (param.getClass().equals(mForcedParameter.getClass())) {
285                                 skipCreatingBaseConfig = true;
286                             } else {
287                                 continue;
288                             }
289                         }
290                         // Only create primary abi of parameterized modules
291                         if (!primaryAbi) {
292                             continue;
293                         }
294                         String fullId =
295                                 String.format("%s[%s]", baseId, param.getParameterIdentifier());
296                         if (shouldRunParameterized(baseId, fullId)) {
297                             IConfiguration paramConfig =
298                                     mConfigFactory.createConfigurationFromArgs(pathArg);
299                             setUpConfig(name, baseId, fullId, paramConfig, abi);
300                             param.applySetup(paramConfig);
301                             toRun.put(fullId, paramConfig);
302                         }
303                     }
304                 }
305                 primaryAbi = false;
306                 // If a parameterized form of the module was forced, we don't create the standard
307                 // version of it.
308                 if (skipCreatingBaseConfig) {
309                     continue;
310                 }
311                 if (shouldRunModule(baseId)) {
312                     // Always add the base regular configuration to the execution.
313                     setUpConfig(name, baseId, baseId, config, abi);
314                     toRun.put(baseId, config);
315                 }
316             }
317         } catch (ConfigurationException e) {
318             throw new RuntimeException(
319                     String.format(
320                             "Error parsing configuration: %s: '%s'",
321                             configFullName, e.getMessage()),
322                     e);
323         }
324 
325         return toRun;
326     }
327 
328     /** @return the {@link Set} of modules whose name contains the given pattern. */
getModuleNamesMatching( File directory, String suitePrefix, String pattern)329     public static Set<File> getModuleNamesMatching(
330             File directory, String suitePrefix, String pattern) {
331         List<File> extraTestCasesDirs = Arrays.asList(directory);
332         List<String> patterns = new ArrayList<>();
333         patterns.add(pattern);
334         Set<File> modules =
335                 ConfigurationUtil.getConfigNamesFileFromDirs(
336                         suitePrefix, extraTestCasesDirs, patterns);
337         return modules;
338     }
339 
340     /**
341      * Utility method that allows to parse and create a structure with the option filters.
342      *
343      * @param stringFilters The original option filters format.
344      * @param filters The filters parsed from the string format.
345      * @param abis The Abis to consider in the filtering.
346      */
addFilters( Set<String> stringFilters, Map<String, List<SuiteTestFilter>> filters, Set<IAbi> abis)347     public static void addFilters(
348             Set<String> stringFilters, Map<String, List<SuiteTestFilter>> filters, Set<IAbi> abis) {
349         for (String filterString : stringFilters) {
350             SuiteTestFilter filter = SuiteTestFilter.createFrom(filterString);
351             String abi = filter.getAbi();
352             if (abi == null) {
353                 for (IAbi a : abis) {
354                     addFilter(a.getName(), filter, filters);
355                 }
356             } else {
357                 addFilter(abi, filter, filters);
358             }
359         }
360     }
361 
addFilter( String abi, SuiteTestFilter filter, Map<String, List<SuiteTestFilter>> filters)362     private static void addFilter(
363             String abi, SuiteTestFilter filter, Map<String, List<SuiteTestFilter>> filters) {
364         getFilterList(filters, AbiUtils.createId(abi, filter.getName())).add(filter);
365     }
366 
getFilterList( Map<String, List<SuiteTestFilter>> filters, String id)367     private static List<SuiteTestFilter> getFilterList(
368             Map<String, List<SuiteTestFilter>> filters, String id) {
369         List<SuiteTestFilter> fs = filters.get(id);
370         if (fs == null) {
371             fs = new ArrayList<>();
372             filters.put(id, fs);
373         }
374         return fs;
375     }
376 
shouldRunModule(String moduleId)377     private boolean shouldRunModule(String moduleId) {
378         List<SuiteTestFilter> mdIncludes = getFilterList(mIncludeFilters, moduleId);
379         List<SuiteTestFilter> mdExcludes = getFilterList(mExcludeFilters, moduleId);
380         // if including all modules or includes exist for this module, and there are not excludes
381         // for the entire module, this module should be run.
382         return (mIncludeAll || !mdIncludes.isEmpty()) && !containsModuleExclude(mdExcludes);
383     }
384 
385     /**
386      * Except if the parameterized module is explicitly excluded, including the base module result
387      * in including its parameterization variant.
388      */
shouldRunParameterized(String baseId, String parameterModuleId)389     private boolean shouldRunParameterized(String baseId, String parameterModuleId) {
390         // Explicitly excluded
391         List<SuiteTestFilter> mdExcludes = getFilterList(mExcludeFilters, parameterModuleId);
392         if (containsModuleExclude(mdExcludes)) {
393             return false;
394         }
395         // itself or its base is included
396         List<SuiteTestFilter> mdIncludes = getFilterList(mIncludeFilters, baseId);
397         List<SuiteTestFilter> mParamIncludes = getFilterList(mIncludeFilters, parameterModuleId);
398         if (mIncludeAll || !mdIncludes.isEmpty() || !mParamIncludes.isEmpty()) {
399             return true;
400         }
401         return false;
402     }
403 
addTestIncludes( ITestFilterReceiver test, List<SuiteTestFilter> includes, String name)404     private void addTestIncludes(
405             ITestFilterReceiver test, List<SuiteTestFilter> includes, String name) {
406         if (test instanceof ITestFileFilterReceiver) {
407             File includeFile = createFilterFile(name, ".include", includes);
408             ((ITestFileFilterReceiver) test).setIncludeTestFile(includeFile);
409         } else {
410             // add test includes one at a time
411             for (SuiteTestFilter include : includes) {
412                 String filterTestName = include.getTest();
413                 if (filterTestName != null) {
414                     test.addIncludeFilter(filterTestName);
415                 }
416             }
417         }
418     }
419 
addTestExcludes( ITestFilterReceiver test, List<SuiteTestFilter> excludes, String name)420     private void addTestExcludes(
421             ITestFilterReceiver test, List<SuiteTestFilter> excludes, String name) {
422         if (test instanceof ITestFileFilterReceiver) {
423             File excludeFile = createFilterFile(name, ".exclude", excludes);
424             ((ITestFileFilterReceiver) test).setExcludeTestFile(excludeFile);
425         } else {
426             // add test excludes one at a time
427             for (SuiteTestFilter exclude : excludes) {
428                 test.addExcludeFilter(exclude.getTest());
429             }
430         }
431     }
432 
createFilterFile(String prefix, String suffix, List<SuiteTestFilter> filters)433     private File createFilterFile(String prefix, String suffix, List<SuiteTestFilter> filters) {
434         File filterFile = null;
435         PrintWriter out = null;
436         try {
437             filterFile = FileUtil.createTempFile(prefix, suffix);
438             out = new PrintWriter(filterFile);
439             for (SuiteTestFilter filter : filters) {
440                 String filterTest = filter.getTest();
441                 if (filterTest != null) {
442                     out.println(filterTest);
443                 }
444             }
445             out.flush();
446         } catch (IOException e) {
447             throw new RuntimeException("Failed to create filter file");
448         } finally {
449             StreamUtil.close(out);
450         }
451         filterFile.deleteOnExit();
452         return filterFile;
453     }
454 
455     /** Returns true iff one or more test filters in excludes apply to the entire module. */
containsModuleExclude(Collection<SuiteTestFilter> excludes)456     private boolean containsModuleExclude(Collection<SuiteTestFilter> excludes) {
457         for (SuiteTestFilter exclude : excludes) {
458             if (exclude.getTest() == null) {
459                 return true;
460             }
461         }
462         return false;
463     }
464 
465     /** A {@link FilenameFilter} to find all the config files in a directory. */
466     public static class ConfigFilter implements FilenameFilter {
467 
468         /** {@inheritDoc} */
469         @Override
accept(File dir, String name)470         public boolean accept(File dir, String name) {
471             return name.endsWith(CONFIG_EXT);
472         }
473     }
474 
475     /**
476      * Parse a list of args formatted as expected into {@link OptionDef} to be injected to module
477      * configurations.
478      *
479      * <p>Format: <module name / module id / class runner>:<option name>:[<arg-key>:=]<arg-value>
480      */
parseArgs(List<String> args, Map<String, List<OptionDef>> moduleOptions)481     private void parseArgs(List<String> args, Map<String, List<OptionDef>> moduleOptions) {
482         for (String arg : args) {
483             int moduleSep = arg.indexOf(":");
484             if (moduleSep == -1) {
485                 throw new RuntimeException("Expected delimiter ':' for module or class.");
486             }
487             String moduleName = arg.substring(0, moduleSep);
488             String remainder = arg.substring(moduleSep + 1);
489             List<OptionDef> listOption = moduleOptions.get(moduleName);
490             if (listOption == null) {
491                 listOption = new ArrayList<>();
492                 moduleOptions.put(moduleName, listOption);
493             }
494             int optionNameSep = remainder.indexOf(":");
495             if (optionNameSep == -1) {
496                 throw new RuntimeException(
497                         "Expected delimiter ':' between option name and values.");
498             }
499             String optionName = remainder.substring(0, optionNameSep);
500             Pattern pattern = Pattern.compile("\\{(.*)\\}(.*)");
501             Matcher match = pattern.matcher(optionName);
502             if (match.find()) {
503                 String alias = match.group(1);
504                 String name = match.group(2);
505                 optionName = alias + ":" + name;
506             }
507             String optionValueString = remainder.substring(optionNameSep + 1);
508             // TODO: See if QuotationTokenizer can be improved for multi-character delimiter.
509             // or change the delimiter to a single char.
510             String[] tokens = optionValueString.split(":=");
511             OptionDef option = null;
512             if (tokens.length == 1) {
513                 option = new OptionDef(optionName, tokens[0], moduleName);
514             } else if (tokens.length == 2) {
515                 option = new OptionDef(optionName, tokens[0], tokens[1], moduleName);
516             }
517             listOption.add(option);
518         }
519     }
520 
521     /** Gets the list of {@link IModuleParameter}s associated with a module. */
getModuleParameters(String moduleName, IConfiguration config)522     private List<IModuleParameter> getModuleParameters(String moduleName, IConfiguration config)
523             throws ConfigurationException {
524         List<IModuleParameter> params = new ArrayList<>();
525         // Track family of the parameters to make sure we have no duplicate.
526         Map<String, ModuleParameters> duplicateModule = new LinkedHashMap<>();
527 
528         List<String> parameters =
529                 config.getConfigurationDescription().getMetaData(ITestSuite.PARAMETER_KEY);
530         if (parameters == null || parameters.isEmpty()) {
531             return params;
532         }
533         for (String p : parameters) {
534             ModuleParameters suiteParam = ModuleParameters.valueOf(p.toUpperCase());
535             String family = suiteParam.getFamily();
536             if (duplicateModule.containsKey(family)) {
537                 // Duplicate family members are not accepted.
538                 throw new ConfigurationException(
539                         String.format(
540                                 "Module %s is declaring parameter: "
541                                         + "%s and %s when only one expected.",
542                                 moduleName, suiteParam, duplicateModule.get(family)));
543             } else {
544                 duplicateModule.put(suiteParam.getFamily(), suiteParam);
545             }
546             // Do not consider the excluded parameterization dimension
547             if (mExcludedModuleParameters.contains(suiteParam)) {
548                 CLog.d("'%s' was excluded via exclude-module-parameters.");
549                 continue;
550             }
551             IModuleParameter handler =
552                     ModuleParametersHelper.getParameterHandler(
553                             suiteParam, /* optionalParams */ false);
554             params.add(handler);
555         }
556         return params;
557     }
558 
559     /**
560      * Setup the options for the module configuration.
561      *
562      * @param name The base name of the module
563      * @param id The base id name of the module.
564      * @param fullId The full id of the module.
565      * @param config The module configuration.
566      * @param abi The abi of the module.
567      * @throws ConfigurationException
568      */
setUpConfig(String name, String id, String fullId, IConfiguration config, IAbi abi)569     private void setUpConfig(String name, String id, String fullId, IConfiguration config, IAbi abi)
570             throws ConfigurationException {
571         List<OptionDef> optionsToInject = new ArrayList<>();
572         if (mModuleOptions.containsKey(name)) {
573             optionsToInject.addAll(mModuleOptions.get(name));
574         }
575         if (mModuleOptions.containsKey(id)) {
576             optionsToInject.addAll(mModuleOptions.get(id));
577         }
578         if (mModuleOptions.containsKey(fullId)) {
579             optionsToInject.addAll(mModuleOptions.get(fullId));
580         }
581         config.injectOptionValues(optionsToInject);
582 
583         // Set target preparers
584         List<ITargetPreparer> preparers = config.getTargetPreparers();
585         for (ITargetPreparer preparer : preparers) {
586             if (preparer instanceof IAbiReceiver) {
587                 ((IAbiReceiver) preparer).setAbi(abi);
588             }
589         }
590 
591         // Set IRemoteTests
592         List<IRemoteTest> tests = config.getTests();
593         for (IRemoteTest test : tests) {
594             String className = test.getClass().getName();
595             if (mTestOptions.containsKey(className)) {
596                 config.injectOptionValues(mTestOptions.get(className));
597             }
598             addFiltersToTest(test, abi, name, mIncludeFilters, mExcludeFilters);
599             if (test instanceof IAbiReceiver) {
600                 ((IAbiReceiver) test).setAbi(abi);
601             }
602         }
603 
604         // add the abi and module name to the description
605         config.getConfigurationDescription().setAbi(abi);
606         config.getConfigurationDescription().setModuleName(name);
607 
608         config.validateOptions(false);
609     }
610 
611     /** Whether or not the base configuration should be created for all abis or not. */
shouldCreateMultiAbiForBase(List<IModuleParameter> params)612     private boolean shouldCreateMultiAbiForBase(List<IModuleParameter> params) {
613         for (IModuleParameter param : params) {
614             if (param instanceof NotMultiAbiHandler) {
615                 return false;
616             }
617         }
618         return true;
619     }
620 }
621