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