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.annotations.VisibleForTesting; 19 import com.android.compatibility.SuiteInfo; 20 import com.android.tradefed.build.BuildInfo; 21 import com.android.tradefed.build.BuildRetrievalError; 22 import com.android.tradefed.build.DeviceBuildInfo; 23 import com.android.tradefed.build.IBuildInfo; 24 import com.android.tradefed.build.IBuildProvider; 25 import com.android.tradefed.build.IDeviceBuildInfo; 26 import com.android.tradefed.build.IDeviceBuildProvider; 27 import com.android.tradefed.config.Option; 28 import com.android.tradefed.config.Option.Importance; 29 import com.android.tradefed.config.OptionClass; 30 import com.android.tradefed.device.DeviceNotAvailableException; 31 import com.android.tradefed.device.ITestDevice; 32 33 import java.io.File; 34 import java.text.SimpleDateFormat; 35 import java.util.Date; 36 import java.util.HashMap; 37 import java.util.Map; 38 import java.util.regex.Pattern; 39 /** 40 * A simple {@link IBuildProvider} that uses a pre-existing Compatibility install. 41 */ 42 @OptionClass(alias="compatibility-build-provider") 43 public class CompatibilityBuildProvider implements IDeviceBuildProvider { 44 45 private static final Pattern RELEASE_BUILD = Pattern.compile("^[A-Z]{3}\\d{2}[A-Z]{0,1}$"); 46 private static final String ROOT_DIR = "ROOT_DIR"; 47 private static final String SUITE_BUILD = "SUITE_BUILD"; 48 private static final String SUITE_NAME = "SUITE_NAME"; 49 private static final String SUITE_FULL_NAME = "SUITE_FULL_NAME"; 50 private static final String SUITE_VERSION = "SUITE_VERSION"; 51 private static final String SUITE_PLAN = "SUITE_PLAN"; 52 private static final String RESULT_DIR = "RESULT_DIR"; 53 private static final String START_TIME_MS = "START_TIME_MS"; 54 private static final String DYNAMIC_CONFIG_OVERRIDE_URL = "DYNAMIC_CONFIG_OVERRIDE_URL"; 55 56 /* API Key for compatibility test project, used for dynamic configuration */ 57 private static final String API_KEY = "AIzaSyAbwX5JRlmsLeygY2WWihpIJPXFLueOQ3U"; 58 59 @Option(name="branch", description="build branch name to supply.") 60 private String mBranch = null; 61 62 @Option(name = "build-id", 63 description = 64 "build version number to supply. Override the default cts version number.") 65 private String mBuildId = null; 66 67 @Option(name="build-flavor", description="build flavor name to supply.") 68 private String mBuildFlavor = null; 69 70 @Option(name="build-attribute", description="build attributes to supply.") 71 private Map<String, String> mBuildAttributes = new HashMap<String,String>(); 72 73 @Option(name="use-device-build-info", description="Bootstrap build info from device") 74 private boolean mUseDeviceBuildInfo = false; 75 76 @Option(name="test-tag", description="test tag name to supply.") 77 private String mTestTag = "cts"; 78 79 @Option(name = "dynamic-config-url", 80 description = "Specify the url for override config") 81 private String mURL = "https://androidpartner.googleapis.com/v1/dynamicconfig/" 82 + "suites/{suite-name}/modules/{module}/version/{version}?key=" + API_KEY; 83 84 @Option(name = "plan", 85 description = "the test suite plan to run, such as \"everything\" or \"cts\"", 86 importance = Importance.ALWAYS) 87 private String mSuitePlan; 88 89 /** 90 * Util method to inject build attributes into supplied {@link IBuildInfo} 91 * @param buildInfo 92 */ injectBuildAttributes(IBuildInfo buildInfo)93 private void injectBuildAttributes(IBuildInfo buildInfo) { 94 for (Map.Entry<String, String> entry : mBuildAttributes.entrySet()) { 95 buildInfo.addBuildAttribute(entry.getKey(), entry.getValue()); 96 } 97 } 98 99 /** 100 * {@inheritDoc} 101 */ 102 @Override getBuild()103 public IBuildInfo getBuild() { 104 // Create a blank BuildInfo which will get populated later. 105 String version = null; 106 if (mBuildId != null) { 107 version = mBuildId; 108 } else { 109 version = getSuiteInfoBuildNumber(); 110 if (version == null) { 111 version = IBuildInfo.UNKNOWN_BUILD_ID; 112 } 113 } 114 IBuildInfo ctsBuild = new BuildInfo(version, mTestTag); 115 if (mBranch != null) { 116 ctsBuild.setBuildBranch(mBranch); 117 } 118 if (mBuildFlavor != null) { 119 ctsBuild.setBuildFlavor(mBuildFlavor); 120 } 121 injectBuildAttributes(ctsBuild); 122 addCompatibilitySuiteInfo(ctsBuild); 123 return ctsBuild; 124 } 125 126 /** 127 * {@inheritDoc} 128 */ 129 @Override getBuild(ITestDevice device)130 public IBuildInfo getBuild(ITestDevice device) 131 throws BuildRetrievalError, DeviceNotAvailableException { 132 if (!mUseDeviceBuildInfo) { 133 // return a regular build info without extracting device attributes into standard 134 // build info fields 135 return getBuild(); 136 } else { 137 String buildId = device.getBuildId(); 138 String buildFlavor = device.getBuildFlavor(); 139 IBuildInfo info = new DeviceBuildInfo(buildId, mTestTag); 140 if (mBranch == null) { 141 // if branch is not specified via param, make a pseudo branch name based on platform 142 // version and product info from device 143 mBranch = String.format("%s-%s-%s-%s", 144 device.getProperty("ro.product.brand"), 145 device.getProperty("ro.product.name"), 146 device.getProductVariant(), 147 device.getProperty("ro.build.version.release")); 148 } 149 info.setBuildBranch(mBranch); 150 info.setBuildFlavor(buildFlavor); 151 String buildAlias = device.getBuildAlias(); 152 if (RELEASE_BUILD.matcher(buildAlias).matches()) { 153 info.addBuildAttribute("build_alias", buildAlias); 154 } 155 injectBuildAttributes(info); 156 addCompatibilitySuiteInfo(info); 157 return info; 158 } 159 } 160 161 /** 162 * {@inheritDoc} 163 */ 164 @Override buildNotTested(IBuildInfo info)165 public void buildNotTested(IBuildInfo info) { 166 // ignore 167 } 168 169 /** 170 * {@inheritDoc} 171 */ 172 @Override cleanUp(IBuildInfo info)173 public void cleanUp(IBuildInfo info) { 174 // ignore 175 } 176 addCompatibilitySuiteInfo(IBuildInfo info)177 private void addCompatibilitySuiteInfo(IBuildInfo info) { 178 long startTimeMs = System.currentTimeMillis(); 179 info.addBuildAttribute(SUITE_BUILD, getSuiteInfoBuildNumber()); 180 info.addBuildAttribute(SUITE_NAME, getSuiteInfoName()); 181 info.addBuildAttribute(SUITE_FULL_NAME, getSuiteInfoFullname()); 182 info.addBuildAttribute(SUITE_VERSION, getSuiteInfoVersion()); 183 info.addBuildAttribute(SUITE_PLAN, mSuitePlan); 184 info.addBuildAttribute(START_TIME_MS, Long.toString(startTimeMs)); 185 info.addBuildAttribute(RESULT_DIR, getDirSuffix(startTimeMs)); 186 String rootDirPath = getRootDirPath(); 187 if (rootDirPath == null || rootDirPath.trim().equals("")) { 188 throw new IllegalArgumentException( 189 String.format("Missing install path property %s_ROOT", getSuiteInfoName())); 190 } 191 File rootDir = new File(rootDirPath); 192 if (!rootDir.exists()) { 193 throw new IllegalArgumentException( 194 String.format("Root directory doesn't exist %s", rootDir.getAbsolutePath())); 195 } 196 info.addBuildAttribute(ROOT_DIR, rootDir.getAbsolutePath()); 197 // For DeviceBuildInfo we populate the testsDir folder of the build info. 198 if (info instanceof IDeviceBuildInfo) { 199 File testDir = new File(rootDir, String.format("android-%s/testcases/", 200 getSuiteInfoName().toLowerCase())); 201 ((IDeviceBuildInfo) info).setTestsDir(testDir, "0"); 202 } 203 if (mURL != null && !mURL.isEmpty()) { 204 info.addBuildAttribute(DYNAMIC_CONFIG_OVERRIDE_URL, 205 mURL.replace("{suite-name}", getSuiteInfoName())); 206 } 207 } 208 209 /** 210 * Returns the CTS_ROOT variable that the harness was started with. 211 */ 212 @VisibleForTesting getRootDirPath()213 String getRootDirPath() { 214 return System.getProperty(String.format("%s_ROOT", getSuiteInfoName())); 215 } 216 217 /** 218 * Return the SuiteInfo name generated at build time. Exposed for testing. 219 */ getSuiteInfoName()220 protected String getSuiteInfoName() { 221 return SuiteInfo.NAME; 222 } 223 224 /** 225 * Return the SuiteInfo build number generated at build time. Exposed for testing. 226 */ getSuiteInfoBuildNumber()227 protected String getSuiteInfoBuildNumber() { 228 return SuiteInfo.BUILD_NUMBER; 229 } 230 231 /** 232 * Return the SuiteInfo fullname generated at build time. Exposed for testing. 233 */ getSuiteInfoFullname()234 protected String getSuiteInfoFullname() { 235 return SuiteInfo.FULLNAME; 236 } 237 238 /** 239 * Return the SuiteInfo version generated at build time. Exposed for testing. 240 */ getSuiteInfoVersion()241 protected String getSuiteInfoVersion() { 242 return SuiteInfo.VERSION; 243 } 244 245 /** 246 * @return a {@link String} to use for directory suffixes created from the given time. 247 */ getDirSuffix(long millis)248 private String getDirSuffix(long millis) { 249 return new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss").format(new Date(millis)); 250 } 251 } 252