1# Copyright 2018 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Parse & Validate CLI arguments for run_suite_skylab.py."""
6
7from __future__ import absolute_import
8from __future__ import division
9from __future__ import print_function
10
11import argparse
12import ast
13import sys
14
15from lucifer import autotest
16from skylab_suite import cros_suite
17from skylab_suite import swarming_lib
18
19
20def make_parser():
21    """Make ArgumentParser instance for run_suite_skylab.py."""
22    parser = argparse.ArgumentParser(prog='run_suite_skylab',
23                                     description="Run a test suite in Skylab.")
24
25    # Suite-related parameters.
26    parser.add_argument('--board', required=True)
27    parser.add_argument(
28            '--model', default=None,
29            help=('The device model to run tests against. For non-unified '
30                  'builds, model and board are synonymous, but board is more '
31                  'accurate in some cases. Only pass this option if your build '
32                  'is a unified build.'))
33    # Allow customized pool label temporarily for crbug.com/913623.
34    parser.add_argument(
35        '--pool', default='suites',
36        help=('Specify the pool of DUTs to run this suite. Default: suites. '
37              'If you want no pool, you can specify it with --pool="". '
38              'USE WITH CARE.'))
39    parser.add_argument(
40        '--suite_name', required=True,
41        help='Specify the suite to run.')
42    parser.add_argument(
43        '--build', required=True,
44        help='Specify the build to run the suite with.')
45    parser.add_argument(
46        '--cheets_build', default=None,
47        help='ChromeOS Android build to be installed on dut.')
48    parser.add_argument(
49        '--firmware_rw_build', default=None,
50        help='Firmware build to be installed in dut RW firmware.')
51    parser.add_argument(
52        '--firmware_ro_build', default=None,
53        help='Firmware build to be installed in dut RO firmware.')
54    parser.add_argument(
55        '--test_source_build', default=None,
56        help=('Build that contains the test code. It can be the value '
57              'of arguments "--build", "--firmware_rw_build" or '
58              '"--firmware_ro_build". Default is to use test code from '
59              'the "--build" version (CrOS image)'))
60    parser.add_argument(
61        '--priority', type=int,
62        default=swarming_lib.SKYLAB_HWTEST_PRIORITIES_MAP['Default'],
63        choices=[value for name, value in
64                 swarming_lib.SORTED_SKYLAB_HWTEST_PRIORITY],
65        help=('The priority to run the suite. A high value means this suite '
66              'will be executed in a low priority, e.g. being delayed to '
67              'execute. Each numerical value represents: '+ ', '.join([
68                  '(%s: %d)' % (name, value) for name, value in
69                  swarming_lib.SORTED_SKYLAB_HWTEST_PRIORITY])))
70    parser.add_argument(
71        "--suite_args", type=ast.literal_eval, default=None,
72        action="store",
73        help="A dict of args passed to the suite control file.")
74    parser.add_argument(
75        "--job_keyvals", type=ast.literal_eval, default={},
76        action="store",
77        help="A dict of job keyvals to be passed to child jobs.")
78    parser.add_argument(
79        "--minimum_duts", type=int, default=1, action="store",
80        help="A minimum required numbers of DUTs to run this suite.")
81    parser.add_argument(
82        '--quota_account', default=None, action='store',
83        help=("Quota account to be used for this suite's jobs, if applicable. "
84              "Only relevant for jobs running in a quota scheduler pool "
85              "(e.g. quota-metered)."))
86    parser.add_argument(
87        '--swarming_auth_json', default=swarming_lib.DEFAULT_SERVICE_ACCOUNT,
88        action='store', help="Path to swarming service account json creds. "
89        "Specify '' to omit. Otherwise, defaults to bot's default creds.")
90
91    # TODO(ayatane): Make sure no callers pass --use_fallback before removing.
92    parser.add_argument(
93            "--use_fallback", action="store_true", help='Deprecated')
94
95    # Swarming-related parameters.
96    parser.add_argument(
97        '--execution_timeout_seconds', type=int, default=30,
98        help='Seconds to allow a task to complete, once execution beings.')
99
100    # logic-related parameters.
101    parser.add_argument(
102        '--create_and_return', action='store_true',
103        help='Create the child jobs of a suite, then finish immediately.')
104    parser.add_argument(
105        '--suite_id', default=None,
106        help='A suite ID, wait for whose child tests to finish.')
107    parser.add_argument(
108        '--test_retry', default=False, action='store_true',
109        help='Enable test-level retry.')
110    parser.add_argument(
111        '--max_retries', default=0, type=int, action='store',
112        help='Maximum retries allowed at suite level. No retry if it is 0.')
113    parser.add_argument(
114        '--timeout_mins', default=90, type=int, action='store',
115        help='Maximum minutes to wait for a suite to finish.')
116    parser.add_argument(
117        '--passed_mins', default=0, type=int, action='store',
118        help='The minutes that this suite already runs for.')
119    parser.add_argument(
120        '--run_prod_code', action='store_true', default=False,
121        help='Run the test code that lives in prod aka the test '
122        'code currently on the lab servers.')
123    parser.add_argument(
124        '--dry_run', action='store_true',
125        help=('Used for kicking off a run of suite with fake commands.'))
126    parser.add_argument(
127        '--pre_check', action='store_true',
128        help=('Used for checking whether a same suite is already kicked off'
129              'to Skylab.'))
130    parser.add_argument(
131        '--do_nothing', action='store_true',
132        help=('Used for monitoring purposes, to measure no-op swarming proxy '
133              'latency or create a dummy run_suite_skylab run.'))
134
135    # Abort-related parameters.
136    parser.add_argument(
137        '--abort_limit', default=sys.maxint, type=int, action='store',
138        help=('Only abort first N parent tasks which fulfill the search '
139              'requirements.'))
140    parser.add_argument(
141        '--suite_task_ids', nargs='*', default=[],
142        help=('Specify the parent swarming task id to abort.'))
143
144    return parser
145
146
147def verify_and_clean_options(options):
148    """Validate options."""
149    if options.suite_args is None:
150        options.suite_args = {}
151
152    return True
153
154
155def parse_suite_spec(options):
156    """Parse options to suite_spec."""
157    suite_common = autotest.load('server.cros.dynamic_suite.suite_common')
158    builds = suite_common.make_builds_from_options(options)
159    return cros_suite.SuiteSpec(
160            builds=builds,
161            suite_name=options.suite_name,
162            suite_file_name=suite_common.canonicalize_suite_name(
163                    options.suite_name),
164            test_source_build=suite_common.get_test_source_build(
165                    builds, test_source_build=options.test_source_build),
166            suite_args=options.suite_args,
167            priority=options.priority,
168            board=options.board,
169            model=options.model,
170            pool=options.pool,
171            job_keyvals=options.job_keyvals,
172            minimum_duts=options.minimum_duts,
173            timeout_mins=options.timeout_mins,
174            quota_account=options.quota_account,
175    )
176