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.compatibility.SuiteInfo;
19 import com.android.tradefed.build.IBuildInfo;
20 import com.android.tradefed.build.IFolderBuildInfo;
21 
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.text.SimpleDateFormat;
25 import java.util.Date;
26 import java.util.HashMap;
27 import java.util.Map;
28 
29 /**
30  * A simple helper that stores and retrieves information from a {@link IBuildInfo}.
31  */
32 public class CompatibilityBuildHelper {
33 
34     public static final String MODULE_IDS = "MODULE_IDS";
35 
36     private static final String ROOT_DIR = "ROOT_DIR";
37     private static final String ROOT_DIR2 = "ROOT_DIR2";
38     private static final String SUITE_BUILD = "SUITE_BUILD";
39     private static final String SUITE_NAME = "SUITE_NAME";
40     private static final String SUITE_FULL_NAME = "SUITE_FULL_NAME";
41     private static final String SUITE_VERSION = "SUITE_VERSION";
42     private static final String SUITE_PLAN = "SUITE_PLAN";
43     private static final String RESULT_DIR = "RESULT_DIR";
44     private static final String START_TIME_MS = "START_TIME_MS";
45     private static final String CONFIG_PATH_PREFIX = "DYNAMIC_CONFIG_FILE:";
46     private static final String DYNAMIC_CONFIG_OVERRIDE_URL = "DYNAMIC_CONFIG_OVERRIDE_URL";
47     private static final String COMMAND_LINE_ARGS = "command_line_args";
48     private static final String RETRY_COMMAND_LINE_ARGS = "retry_command_line_args";
49     private final IBuildInfo mBuildInfo;
50     private boolean mInitialized = false;
51 
52     /**
53      * Creates a {@link CompatibilityBuildHelper} wrapping the given {@link IBuildInfo}.
54      */
CompatibilityBuildHelper(IBuildInfo buildInfo)55     public CompatibilityBuildHelper(IBuildInfo buildInfo) {
56         mBuildInfo = buildInfo;
57     }
58 
59     /**
60      * Initializes the {@link IBuildInfo} from the manifest with the current time
61      * as the start time.
62      */
init(String suitePlan, String dynamicConfigUrl)63     public void init(String suitePlan, String dynamicConfigUrl) {
64         init(suitePlan, dynamicConfigUrl, System.currentTimeMillis());
65     }
66 
67     /**
68      * Initializes the {@link IBuildInfo} from the manifest.
69      */
init(String suitePlan, String dynamicConfigUrl, long startTimeMs)70     public void init(String suitePlan, String dynamicConfigUrl, long startTimeMs) {
71         if (mInitialized) {
72             return;
73         }
74         mInitialized = true;
75         mBuildInfo.addBuildAttribute(SUITE_BUILD, SuiteInfo.BUILD_NUMBER);
76         mBuildInfo.addBuildAttribute(SUITE_NAME, SuiteInfo.NAME);
77         mBuildInfo.addBuildAttribute(SUITE_FULL_NAME, SuiteInfo.FULLNAME);
78         mBuildInfo.addBuildAttribute(SUITE_VERSION, SuiteInfo.VERSION);
79         mBuildInfo.addBuildAttribute(SUITE_PLAN, suitePlan);
80         mBuildInfo.addBuildAttribute(START_TIME_MS, Long.toString(startTimeMs));
81         mBuildInfo.addBuildAttribute(RESULT_DIR, getDirSuffix(startTimeMs));
82         String rootDirPath = null;
83         if (mBuildInfo instanceof IFolderBuildInfo) {
84             File rootDir = ((IFolderBuildInfo) mBuildInfo).getRootDir();
85             if (rootDir != null) {
86                 rootDirPath = rootDir.getAbsolutePath();
87             }
88         }
89         rootDirPath = System.getProperty(String.format("%s_ROOT", SuiteInfo.NAME), rootDirPath);
90         if (rootDirPath == null || rootDirPath.trim().equals("")) {
91             throw new IllegalArgumentException(
92                     String.format("Missing install path property %s_ROOT", SuiteInfo.NAME));
93         }
94         File rootDir = new File(rootDirPath);
95         if (!rootDir.exists()) {
96             throw new IllegalArgumentException(
97                     String.format("Root directory doesn't exist %s", rootDir.getAbsolutePath()));
98         }
99         mBuildInfo.addBuildAttribute(ROOT_DIR, rootDir.getAbsolutePath());
100         if (dynamicConfigUrl != null && !dynamicConfigUrl.isEmpty()) {
101             mBuildInfo.addBuildAttribute(DYNAMIC_CONFIG_OVERRIDE_URL,
102                     dynamicConfigUrl.replace("{suite-name}", getSuiteName()));
103         }
104     }
105 
getBuildInfo()106     public IBuildInfo getBuildInfo() {
107         return mBuildInfo;
108     }
109 
setRetryCommandLineArgs(String commandLineArgs)110     public void setRetryCommandLineArgs(String commandLineArgs) {
111         mBuildInfo.addBuildAttribute(RETRY_COMMAND_LINE_ARGS, commandLineArgs);
112     }
113 
getCommandLineArgs()114     public String getCommandLineArgs() {
115         if (mBuildInfo.getBuildAttributes().containsKey(RETRY_COMMAND_LINE_ARGS)) {
116             return mBuildInfo.getBuildAttributes().get(RETRY_COMMAND_LINE_ARGS);
117         } else {
118             // NOTE: this is a temporary workaround set in TestInvocation#invoke in tradefed.
119             // This will be moved to a separate method in a new invocation metadata class.
120             return mBuildInfo.getBuildAttributes().get(COMMAND_LINE_ARGS);
121         }
122     }
123 
getSuiteBuild()124     public String getSuiteBuild() {
125         return mBuildInfo.getBuildAttributes().get(SUITE_BUILD);
126     }
127 
getSuiteName()128     public String getSuiteName() {
129         return mBuildInfo.getBuildAttributes().get(SUITE_NAME);
130     }
131 
getSuiteFullName()132     public String getSuiteFullName() {
133         return mBuildInfo.getBuildAttributes().get(SUITE_FULL_NAME);
134     }
135 
getSuiteVersion()136     public String getSuiteVersion() {
137         return mBuildInfo.getBuildAttributes().get(SUITE_VERSION);
138     }
139 
getSuitePlan()140     public String getSuitePlan() {
141         return mBuildInfo.getBuildAttributes().get(SUITE_PLAN);
142     }
143 
getDynamicConfigUrl()144     public String getDynamicConfigUrl() {
145         return mBuildInfo.getBuildAttributes().get(DYNAMIC_CONFIG_OVERRIDE_URL);
146     }
147 
getStartTime()148     public long getStartTime() {
149         return Long.parseLong(mBuildInfo.getBuildAttributes().get(START_TIME_MS));
150     }
151 
addDynamicConfigFile(String moduleName, File configFile)152     public void addDynamicConfigFile(String moduleName, File configFile) {
153         mBuildInfo.addBuildAttribute(CONFIG_PATH_PREFIX + moduleName, configFile.getAbsolutePath());
154     }
155 
setModuleIds(String[] moduleIds)156     public void setModuleIds(String[] moduleIds) {
157         mBuildInfo.addBuildAttribute(MODULE_IDS, String.join(",", moduleIds));
158     }
159 
getDynamicConfigFiles()160     public Map<String, File> getDynamicConfigFiles() {
161         Map<String, File> configMap = new HashMap<>();
162         for (String key : mBuildInfo.getBuildAttributes().keySet()) {
163             if (key.startsWith(CONFIG_PATH_PREFIX)) {
164                 configMap.put(key.substring(CONFIG_PATH_PREFIX.length()),
165                         new File(mBuildInfo.getBuildAttributes().get(key)));
166             }
167         }
168         return configMap;
169     }
170 
171     /**
172      * @return a {@link File} representing the directory holding the Compatibility installation
173      * @throws FileNotFoundException if the directory does not exist
174      */
getRootDir()175     public File getRootDir() throws FileNotFoundException {
176         File dir = null;
177         if (mBuildInfo instanceof IFolderBuildInfo) {
178             dir = ((IFolderBuildInfo) mBuildInfo).getRootDir();
179         }
180         if (dir == null || !dir.exists()) {
181             dir = new File(mBuildInfo.getBuildAttributes().get(ROOT_DIR));
182             if (!dir.exists()) {
183                 dir = new File(mBuildInfo.getBuildAttributes().get(ROOT_DIR2));
184             }
185         }
186         if (!dir.exists()) {
187             throw new FileNotFoundException(String.format(
188                     "Compatibility root directory %s does not exist",
189                     dir.getAbsolutePath()));
190         }
191         return dir;
192     }
193 
194     /**
195      * @return a {@link File} representing the "android-<suite>" folder of the Compatibility
196      * installation
197      * @throws FileNotFoundException if the directory does not exist
198      */
getDir()199     public File getDir() throws FileNotFoundException {
200         File dir = new File(getRootDir(), String.format("android-%s", getSuiteName().toLowerCase()));
201         if (!dir.exists()) {
202             throw new FileNotFoundException(String.format(
203                     "Compatibility install folder %s does not exist",
204                     dir.getAbsolutePath()));
205         }
206         return dir;
207     }
208 
209     /**
210      * @return a {@link File} representing the results directory.
211      * @throws FileNotFoundException if the directory structure is not valid.
212      */
getResultsDir()213     public File getResultsDir() throws FileNotFoundException {
214         return new File(getDir(), "results");
215     }
216 
217     /**
218      * @return a {@link File} representing the result directory of the current invocation.
219      * @throws FileNotFoundException if the directory structure is not valid.
220      */
getResultDir()221     public File getResultDir() throws FileNotFoundException {
222         return new File(getResultsDir(),
223             getDirSuffix(Long.parseLong(mBuildInfo.getBuildAttributes().get(START_TIME_MS))));
224     }
225 
226     /**
227      * @return a {@link File} representing the directory to store result logs.
228      * @throws FileNotFoundException if the directory structure is not valid.
229      */
getLogsDir()230     public File getLogsDir() throws FileNotFoundException {
231         return new File(getDir(), "logs");
232     }
233 
234     /**
235      * @return a {@link File} representing the test modules directory.
236      * @throws FileNotFoundException if the directory structure is not valid.
237      */
getTestsDir()238     public File getTestsDir() throws FileNotFoundException {
239         File testsDir = new File(getDir(), "testcases");
240         if (!testsDir.exists()) {
241             throw new FileNotFoundException(String.format(
242                     "Compatibility tests folder %s does not exist",
243                     testsDir.getAbsolutePath()));
244         }
245         return testsDir;
246     }
247 
248     /**
249      * @return a {@link String} to use for directory suffixes created from the given time.
250      */
getDirSuffix(long millis)251     public static String getDirSuffix(long millis) {
252         return new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss").format(new Date(millis));
253     }
254 }
255