1 /* 2 * Copyright (C) 2011 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.command; 17 18 import com.android.tradefed.config.ConfigurationException; 19 import com.android.tradefed.config.Option; 20 import com.android.tradefed.config.Option.Importance; 21 import com.android.tradefed.config.OptionCopier; 22 import com.android.tradefed.config.OptionUpdateRule; 23 import com.android.tradefed.log.LogUtil.CLog; 24 import com.android.tradefed.util.UniqueMultiMap; 25 26 /** 27 * Implementation of {@link ICommandOptions}. 28 */ 29 public class CommandOptions implements ICommandOptions { 30 31 @Option(name = "help", description = 32 "display the help text for the most important/critical options.", 33 importance = Importance.ALWAYS) 34 private boolean mHelpMode = false; 35 36 @Option(name = "help-all", description = "display the full help text for all options.", 37 importance = Importance.ALWAYS) 38 private boolean mFullHelpMode = false; 39 40 @Option(name = "json-help", description = "display the full help in json format.") 41 private boolean mJsonHelpMode = false; 42 43 public static final String DRY_RUN_OPTION = "dry-run"; 44 45 @Option( 46 name = DRY_RUN_OPTION, 47 description = 48 "build but don't actually run the command. Intended as a quick check " 49 + "to ensure that a command is runnable.", 50 importance = Importance.ALWAYS 51 ) 52 private boolean mDryRunMode = false; 53 54 @Option(name = "noisy-dry-run", 55 description = "build but don't actually run the command. This version prints the " + 56 "command to the console. Intended for cmdfile debugging.", 57 importance = Importance.ALWAYS) 58 private boolean mNoisyDryRunMode = false; 59 60 @Option(name = "min-loop-time", description = 61 "the minimum invocation time in ms when in loop mode.") 62 private Long mMinLoopTime = 10L * 60L * 1000L; 63 64 @Option(name = "max-random-loop-time", description = 65 "the maximum time to wait between invocation attempts when in loop mode. " + 66 "when set, the actual value will be a random number between min-loop-time and this " + 67 "number.", 68 updateRule = OptionUpdateRule.LEAST) 69 private Long mMaxRandomLoopTime = null; 70 71 @Option(name = "test-tag", description = "Identifier for the invocation during reporting.") 72 private String mTestTag = "stub"; 73 74 @Option(name = "test-tag-suffix", description = "suffix for test-tag. appended to test-tag to " 75 + "represents some variants of one test.") 76 private String mTestTagSuffix = null; 77 78 @Option(name = "loop", description = "keep running continuously.", 79 importance = Importance.ALWAYS) 80 private boolean mLoopMode = false; 81 82 @Option(name = "all-devices", description = 83 "fork this command to run on all connected devices.") 84 private boolean mAllDevices = false; 85 86 @Option(name = "bugreport-on-invocation-ended", description = 87 "take a bugreport when the test invocation has ended") 88 private boolean mTakeBugreportOnInvocationEnded = false; 89 90 @Option(name = "bugreportz-on-invocation-ended", description = "Attempt to take a bugreportz " 91 + "instead of bugreport during the test invocation final bugreport.") 92 private boolean mTakeBugreportzOnInvocationEnded = false; 93 94 @Option(name = "invocation-timeout", description = 95 "the maximum time to wait for an invocation to terminate before attempting to force" 96 + "stop it.", isTimeVal = true) 97 private long mInvocationTimeout = 0; 98 99 @Option(name = "shard-count", description = 100 "the number of total shards to run. Without --shard-index option, this will cause " + 101 "the command to spawn multiple shards in the current TF instance. With --shard-index " + 102 "option, it will cause the command to run a single shard of tests only.") 103 private Integer mShardCount; 104 105 @Option(name = "shard-index", description = 106 "the index of shard to run. Only set if shard-count > 1 and the value is in range " + 107 "[0, shard-count)") 108 private Integer mShardIndex; 109 110 @Option( 111 name = "skip-pre-device-setup", 112 description = 113 "allow TestInvocation to skip calling device.preInvocationSetup. This is for " 114 + "delaying device setup when the test runs with VersionedTfLauncher." 115 ) 116 private boolean mSkipPreDeviceSetup = false; 117 118 @Option( 119 name = "dynamic-sharding", 120 description = 121 "Allow to dynamically move IRemoteTest from one shard to another. Only for local " 122 + "sharding." 123 ) 124 private boolean mDynamicSharding = true; 125 126 @Option( 127 name = "invocation-data", 128 description = 129 "A map of values that describe the invocation, these values will be added to the " 130 + "invocation context." 131 ) 132 private UniqueMultiMap<String, String> mInvocationData = new UniqueMultiMap<>(); 133 134 @Option( 135 name = "disable-strict-sharding", 136 description = "Temporary option to disable the new sharding logic while being tested." 137 ) 138 private boolean mUseTfSharding = false; 139 140 /** 141 * Set the help mode for the config. 142 * <p/> 143 * Exposed for testing. 144 */ 145 void setHelpMode(boolean helpMode) { 146 mHelpMode = helpMode; 147 } 148 149 /** 150 * {@inheritDoc} 151 */ 152 @Override 153 public boolean isHelpMode() { 154 return mHelpMode; 155 } 156 157 /** 158 * {@inheritDoc} 159 */ 160 @Override 161 public boolean isFullHelpMode() { 162 return mFullHelpMode; 163 } 164 165 /** 166 * Set the json help mode for the config. 167 * <p/> 168 * Exposed for testing. 169 */ 170 void setJsonHelpMode(boolean jsonHelpMode) { 171 mJsonHelpMode = jsonHelpMode; 172 } 173 174 /** 175 * {@inheritDoc} 176 */ 177 @Override 178 public boolean isJsonHelpMode() { 179 return mJsonHelpMode; 180 } 181 182 /** 183 * Set the dry run mode for the config. 184 * <p/> 185 * Exposed for testing. 186 */ 187 void setDryRunMode(boolean dryRunMode) { 188 mDryRunMode = dryRunMode; 189 } 190 191 /** 192 * {@inheritDoc} 193 */ 194 @Override 195 public boolean isDryRunMode() { 196 return mDryRunMode || mNoisyDryRunMode; 197 } 198 199 /** 200 * {@inheritDoc} 201 */ 202 @Override 203 public boolean isNoisyDryRunMode() { 204 return mNoisyDryRunMode; 205 } 206 207 /** 208 * Set the loop mode for the config. 209 */ 210 @Override 211 public void setLoopMode(boolean loopMode) { 212 mLoopMode = loopMode; 213 } 214 215 /** 216 * {@inheritDoc} 217 */ 218 @Override 219 public boolean isLoopMode() { 220 return mLoopMode; 221 } 222 223 /** 224 * Set the min loop time for the config. 225 * <p/> 226 * Exposed for testing. 227 */ 228 void setMinLoopTime(long loopTime) { 229 mMinLoopTime = loopTime; 230 } 231 232 /** 233 * {@inheritDoc} 234 * @deprecated use {@link #getLoopTime()} instead 235 */ 236 @Deprecated 237 @Override 238 public long getMinLoopTime() { 239 return mMinLoopTime; 240 } 241 242 /** 243 * {@inheritDoc} 244 */ 245 @Override 246 public long getLoopTime() { 247 if (mMaxRandomLoopTime != null) { 248 long randomizedValue = mMaxRandomLoopTime - mMinLoopTime; 249 if (randomizedValue > 0) { 250 return mMinLoopTime + Math.round(randomizedValue * Math.random()); 251 } else { 252 CLog.e("max loop time %d is less than min loop time %d", mMaxRandomLoopTime, 253 mMinLoopTime); 254 } 255 } 256 return mMinLoopTime; 257 } 258 259 260 @Override 261 public ICommandOptions clone() { 262 CommandOptions clone = new CommandOptions(); 263 try { 264 OptionCopier.copyOptions(this, clone); 265 } catch (ConfigurationException e) { 266 CLog.e("failed to clone command options: %s", e.getMessage()); 267 } 268 return clone; 269 } 270 271 /** 272 * {@inheritDoc} 273 */ 274 @Override 275 public boolean runOnAllDevices() { 276 return mAllDevices; 277 } 278 279 /** 280 * {@inheritDoc} 281 */ 282 @Override 283 public boolean takeBugreportOnInvocationEnded() { 284 return mTakeBugreportOnInvocationEnded; 285 } 286 287 /** 288 * {@inheritDoc} 289 */ 290 @Override 291 public boolean takeBugreportzOnInvocationEnded() { 292 return mTakeBugreportzOnInvocationEnded; 293 } 294 295 /** 296 * {@inheritDoc} 297 */ 298 @Override 299 public long getInvocationTimeout() { 300 return mInvocationTimeout; 301 } 302 303 /** 304 * {@inheritDoc} 305 */ 306 @Override 307 public void setInvocationTimeout(Long invocationTimeout) { 308 mInvocationTimeout = invocationTimeout; 309 } 310 311 /** 312 * {@inheritDoc} 313 */ 314 @Override 315 public Integer getShardCount() { 316 return mShardCount; 317 } 318 319 /** 320 * {@inheritDoc} 321 */ 322 @Override 323 public void setShardCount(Integer shardCount) { 324 mShardCount = shardCount; 325 } 326 327 /** 328 * {@inheritDoc} 329 */ 330 @Override 331 public Integer getShardIndex() { 332 return mShardIndex; 333 } 334 335 /** 336 * {@inheritDoc} 337 */ 338 @Override 339 public void setShardIndex(Integer shardIndex) { 340 mShardIndex = shardIndex; 341 } 342 343 /** 344 * {@inheritDoc} 345 */ 346 @Override 347 public void setTestTag(String testTag) { 348 mTestTag = testTag; 349 } 350 351 /** 352 * {@inheritDoc} 353 */ 354 @Override 355 public String getTestTag() { 356 return mTestTag; 357 } 358 359 /** 360 * {@inheritDoc} 361 */ 362 @Override 363 public String getTestTagSuffix() { 364 return mTestTagSuffix; 365 } 366 367 /** {@inheritDoc} */ 368 @Override 369 370 public boolean shouldSkipPreDeviceSetup() { 371 return mSkipPreDeviceSetup; 372 } 373 374 /** {@inheritDoc} */ 375 @Override 376 public boolean shouldUseDynamicSharding() { 377 return mDynamicSharding; 378 } 379 380 /** {@inheritDoc} */ 381 @Override 382 public UniqueMultiMap<String, String> getInvocationData() { 383 return mInvocationData; 384 } 385 386 /** {@inheritDoc} */ 387 @Override 388 public boolean shouldUseTfSharding() { 389 return mUseTfSharding; 390 } 391 } 392