• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.compatibility.common.tradefed.build;
17 
18 import com.android.tradefed.build.IBuildInfo;
19 import com.android.tradefed.build.IDeviceBuildInfo;
20 import com.android.tradefed.build.IFolderBuildInfo;
21 import com.android.tradefed.build.VersionedFile;
22 import com.android.tradefed.testtype.IAbi;
23 import com.android.tradefed.util.FileUtil;
24 
25 
26 import java.io.File;
27 import java.io.FileNotFoundException;
28 import java.io.IOException;
29 import java.text.SimpleDateFormat;
30 import java.util.Date;
31 import java.util.HashMap;
32 import java.util.Map;
33 
34 /**
35  * A simple helper that stores and retrieves information from a {@link IBuildInfo}.
36  */
37 public class CompatibilityBuildHelper {
38 
39     public static final String MODULE_IDS = "MODULE_IDS";
40     public static final String ROOT_DIR = "ROOT_DIR";
41     public static final String SUITE_BUILD = "SUITE_BUILD";
42     public static final String SUITE_NAME = "SUITE_NAME";
43     public static final String SUITE_FULL_NAME = "SUITE_FULL_NAME";
44     public static final String SUITE_VERSION = "SUITE_VERSION";
45     public static final String SUITE_PLAN = "SUITE_PLAN";
46     public static final String START_TIME_MS = "START_TIME_MS";
47     public static final String COMMAND_LINE_ARGS = "command_line_args";
48 
49     private static final String ROOT_DIR2 = "ROOT_DIR2";
50     private static final String DYNAMIC_CONFIG_OVERRIDE_URL = "DYNAMIC_CONFIG_OVERRIDE_URL";
51     private static final String BUSINESS_LOGIC_HOST_FILE = "BUSINESS_LOGIC_HOST_FILE";
52     private static final String RETRY_COMMAND_LINE_ARGS = "retry_command_line_args";
53 
54     private static final String CONFIG_PATH_PREFIX = "DYNAMIC_CONFIG_FILE:";
55 
56     private final IBuildInfo mBuildInfo;
57 
58     /**
59      * Creates a {@link CompatibilityBuildHelper} wrapping the given {@link IBuildInfo}.
60      */
CompatibilityBuildHelper(IBuildInfo buildInfo)61     public CompatibilityBuildHelper(IBuildInfo buildInfo) {
62         mBuildInfo = buildInfo;
63     }
64 
getBuildInfo()65     public IBuildInfo getBuildInfo() {
66         return mBuildInfo;
67     }
68 
setRetryCommandLineArgs(String commandLineArgs)69     public void setRetryCommandLineArgs(String commandLineArgs) {
70         mBuildInfo.addBuildAttribute(RETRY_COMMAND_LINE_ARGS, commandLineArgs);
71     }
72 
getCommandLineArgs()73     public String getCommandLineArgs() {
74         if (mBuildInfo.getBuildAttributes().containsKey(RETRY_COMMAND_LINE_ARGS)) {
75             return mBuildInfo.getBuildAttributes().get(RETRY_COMMAND_LINE_ARGS);
76         } else {
77             // NOTE: this is a temporary workaround set in TestInvocation#invoke in tradefed.
78             // This will be moved to a separate method in a new invocation metadata class.
79             return mBuildInfo.getBuildAttributes().get(COMMAND_LINE_ARGS);
80         }
81     }
82 
getRecentCommandLineArgs()83     public String getRecentCommandLineArgs() {
84         return mBuildInfo.getBuildAttributes().get(COMMAND_LINE_ARGS);
85     }
86 
getSuiteBuild()87     public String getSuiteBuild() {
88         return mBuildInfo.getBuildAttributes().get(SUITE_BUILD);
89     }
90 
getSuiteName()91     public String getSuiteName() {
92         return mBuildInfo.getBuildAttributes().get(SUITE_NAME);
93     }
94 
getSuiteFullName()95     public String getSuiteFullName() {
96         return mBuildInfo.getBuildAttributes().get(SUITE_FULL_NAME);
97     }
98 
getSuiteVersion()99     public String getSuiteVersion() {
100         return mBuildInfo.getBuildAttributes().get(SUITE_VERSION);
101     }
102 
getSuitePlan()103     public String getSuitePlan() {
104         return mBuildInfo.getBuildAttributes().get(SUITE_PLAN);
105     }
106 
getDynamicConfigUrl()107     public String getDynamicConfigUrl() {
108         return mBuildInfo.getBuildAttributes().get(DYNAMIC_CONFIG_OVERRIDE_URL);
109     }
110 
getStartTime()111     public long getStartTime() {
112         return Long.parseLong(mBuildInfo.getBuildAttributes().get(START_TIME_MS));
113     }
114 
addDynamicConfigFile(String moduleName, File configFile)115     public void addDynamicConfigFile(String moduleName, File configFile) {
116         // If invocation fails and ResultReporter never moves this file into the result,
117         // using setFile() ensures BuildInfo will delete upon cleanUp().
118         mBuildInfo.setFile(configFile.getName(), configFile,
119                 CONFIG_PATH_PREFIX + moduleName /* version */);
120     }
121 
122     /**
123      * Set the business logic file for this invocation.
124      *
125      * @param hostFile The business logic host file.
126      */
setBusinessLogicHostFile(File hostFile)127     public void setBusinessLogicHostFile(File hostFile) {
128         setBusinessLogicHostFile(hostFile, null);
129     }
130 
131     /**
132      * Set the business logic file with specific module id for this invocation.
133      *
134      * @param hostFile The business logic host file.
135      * @param moduleId The name of the moduleId.
136      */
setBusinessLogicHostFile(File hostFile, String moduleId)137     public void setBusinessLogicHostFile(File hostFile, String moduleId) {
138         String key = (moduleId == null) ? "" : moduleId;
139         mBuildInfo.setFile(BUSINESS_LOGIC_HOST_FILE + key, hostFile,
140                 hostFile.getName()/* version */);
141     }
142 
setModuleIds(String[] moduleIds)143     public void setModuleIds(String[] moduleIds) {
144         mBuildInfo.addBuildAttribute(MODULE_IDS, String.join(",", moduleIds));
145     }
146 
147     /**
148      * Returns the map of the dynamic config files downloaded.
149      */
getDynamicConfigFiles()150     public Map<String, File> getDynamicConfigFiles() {
151         Map<String, File> configMap = new HashMap<>();
152         for (VersionedFile vFile : mBuildInfo.getFiles()) {
153             if (vFile.getVersion().startsWith(CONFIG_PATH_PREFIX)) {
154                 configMap.put(
155                         vFile.getVersion().substring(CONFIG_PATH_PREFIX.length()),
156                         vFile.getFile());
157             }
158         }
159         return configMap;
160     }
161 
162     /**
163      * @return whether the business logic file has been set for this invocation.
164      */
hasBusinessLogicHostFile()165     public boolean hasBusinessLogicHostFile() {
166         return hasBusinessLogicHostFile(null);
167     }
168 
169     /**
170      * Check whether the business logic file has been set with specific module id for this
171      * invocation.
172      *
173      * @param moduleId The name of the moduleId.
174      * @return True if the business logic file has been set. False otherwise.
175      */
hasBusinessLogicHostFile(String moduleId)176     public boolean hasBusinessLogicHostFile(String moduleId) {
177         String key = (moduleId == null) ? "" : moduleId;
178         return mBuildInfo.getFile(BUSINESS_LOGIC_HOST_FILE + key) != null;
179     }
180 
181     /**
182      * @return a {@link File} representing the file containing business logic data for this
183      * invocation, or null if the business logic file has not been set.
184      */
getBusinessLogicHostFile()185     public File getBusinessLogicHostFile() {
186         return getBusinessLogicHostFile(null);
187     }
188 
189     /**
190      * Get the file containing business logic data with specific module id for this invocation.
191      *
192      * @param moduleId The name of the moduleId.
193      * @return a {@link File} representing the file containing business logic data with
194      * specific module id for this invocation , or null if the business logic file has not been set.
195      */
getBusinessLogicHostFile(String moduleId)196     public File getBusinessLogicHostFile(String moduleId) {
197         String key = (moduleId == null) ? "" : moduleId;
198         return mBuildInfo.getFile(BUSINESS_LOGIC_HOST_FILE + key);
199     }
200 
201     /**
202      * @return a {@link File} representing the directory holding the Compatibility installation
203      * @throws FileNotFoundException if the directory does not exist
204      */
getRootDir()205     public File getRootDir() throws FileNotFoundException {
206         File dir = null;
207         if (mBuildInfo instanceof IFolderBuildInfo) {
208             dir = ((IFolderBuildInfo) mBuildInfo).getRootDir();
209         }
210         if (dir == null || !dir.exists()) {
211             dir = new File(mBuildInfo.getBuildAttributes().get(ROOT_DIR));
212             if (!dir.exists()) {
213                 dir = new File(mBuildInfo.getBuildAttributes().get(ROOT_DIR2));
214             }
215         }
216         if (!dir.exists()) {
217             throw new FileNotFoundException(String.format(
218                     "Compatibility root directory %s does not exist",
219                     dir.getAbsolutePath()));
220         }
221         return dir;
222     }
223 
224     /**
225      * @return a {@link File} representing the "android-<suite>" folder of the Compatibility
226      * installation
227      * @throws FileNotFoundException if the directory does not exist
228      */
getDir()229     public File getDir() throws FileNotFoundException {
230         File dir = new File(getRootDir(), String.format("android-%s", getSuiteName().toLowerCase()));
231         if (!dir.exists()) {
232             throw new FileNotFoundException(String.format(
233                     "Compatibility install folder %s does not exist",
234                     dir.getAbsolutePath()));
235         }
236         return dir;
237     }
238 
239     /**
240      * @return a {@link File} representing the results directory.
241      * @throws FileNotFoundException if the directory structure is not valid.
242      */
getResultsDir()243     public File getResultsDir() throws FileNotFoundException {
244         return new File(getDir(), "results");
245     }
246 
247     /**
248      * @return a {@link File} representing the result directory of the current invocation.
249      * @throws FileNotFoundException if the directory structure is not valid.
250      */
getResultDir()251     public File getResultDir() throws FileNotFoundException {
252         return new File(getResultsDir(),
253             getDirSuffix(Long.parseLong(mBuildInfo.getBuildAttributes().get(START_TIME_MS))));
254     }
255 
256     /**
257      * @return a {@link File} representing the directory to store result logs.
258      * @throws FileNotFoundException if the directory structure is not valid.
259      */
getLogsDir()260     public File getLogsDir() throws FileNotFoundException {
261         return new File(getDir(), "logs");
262     }
263 
264     /**
265      * @return a {@link File} representing the directory to store derivedplan files.
266      * @throws FileNotFoundException if the directory structure is not valid.
267      */
getSubPlansDir()268     public File getSubPlansDir() throws FileNotFoundException {
269         File subPlansDir = new File(getDir(), "subplans");
270         if (!subPlansDir.exists()) {
271             subPlansDir.mkdirs();
272         }
273         return subPlansDir;
274     }
275 
276     /**
277      * @return a {@link File} representing the test modules directory.
278      * @throws FileNotFoundException if the directory structure is not valid.
279      */
getTestsDir()280     public File getTestsDir() throws FileNotFoundException {
281         // We have 2 options that can be the test modules dir (and we're going
282         // look for them in the following order):
283         //   1. ../android-*ts/testcases/
284         //   2. The build info tests dir
285         // ANDROID_HOST_OUT and ANDROID_TARGET_OUT are already linked
286         // by tradefed to the tests dir when they exists so there is
287         // no need to explicitly search them.
288 
289         File testsDir = null;
290         try {
291             testsDir = new File(getDir(), "testcases");
292         } catch (FileNotFoundException | NullPointerException e) {
293             // Ok, no root dir for us to get, moving on to the next option.
294             testsDir = null;
295         }
296 
297         if (testsDir == null) {
298             if (mBuildInfo instanceof IDeviceBuildInfo) {
299                 testsDir = ((IDeviceBuildInfo) mBuildInfo).getTestsDir();
300             }
301         }
302 
303         // This just means we have no signs of where to check for the test dir.
304         if (testsDir == null) {
305             throw new FileNotFoundException(
306                 String.format("No Compatibility tests folder set, did you run lunch?"));
307         }
308 
309         if (!testsDir.exists()) {
310             throw new FileNotFoundException(String.format(
311                     "Compatibility tests folder %s does not exist",
312                     testsDir.getAbsolutePath()));
313         }
314 
315         return testsDir;
316     }
317 
318     /**
319      * @return a {@link File} representing the test file in the test modules directory.
320      * @throws FileNotFoundException if the test file cannot be found
321      */
getTestFile(String filename)322     public File getTestFile(String filename) throws FileNotFoundException {
323         return getTestFile(filename, null);
324     }
325 
326     /**
327      * @return a {@link File} representing the test file in the test modules directory.
328      * @throws FileNotFoundException if the test file cannot be found
329      */
getTestFile(String filename, IAbi abi)330     public File getTestFile(String filename, IAbi abi) throws FileNotFoundException {
331         File[] testDirs = {getTestsDir()};
332 
333         // The file may be in a subdirectory so do a more through search
334         // if it did not exist.
335         File testFile = null;
336         for (File testDir: testDirs) {
337             try {
338                 testFile = FileUtil.findFile(filename, abi, testDir);
339             } catch (IOException e) {
340                 throw new FileNotFoundException(String.format(
341                         "Failure in finding compatibility test file %s due to %s", filename, e));
342             }
343             if (testFile != null) {
344                 return testFile;
345             }
346         }
347 
348         throw new FileNotFoundException(String.format(
349                 "Compatibility test file %s does not exist", filename));
350     }
351 
352     /**
353      * @return a {@link File} in the resultDir for logging invocation failures
354      */
getInvocationFailureFile()355     public File getInvocationFailureFile() throws FileNotFoundException {
356         return new File(getResultDir(), "invocation_failure.txt");
357     }
358 
359     /**
360      * @return a {@link File} in the resultDir for counting expected test runs
361      */
getTestRunsFile()362     public File getTestRunsFile() throws FileNotFoundException {
363         return new File(getResultDir(), "test_runs.txt");
364     }
365 
366     /**
367      * @return a {@link String} to use for directory suffixes created from the given time.
368      */
getDirSuffix(long millis)369     public static String getDirSuffix(long millis) {
370         return new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss").format(new Date(millis));
371     }
372 }
373