browser_options.py revision ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16
1# Copyright (c) 2012 The Chromium 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
5import copy
6import logging
7import optparse
8import os
9import shlex
10import sys
11
12from telemetry.core import browser_finder
13from telemetry.core import profile_types
14from telemetry.core import repeat_options
15from telemetry.core import util
16from telemetry.core import wpr_modes
17from telemetry.core.platform.profiler import profiler_finder
18
19class BrowserOptions(optparse.Values):
20  """Options to be used for discovering and launching a browser."""
21
22  def __init__(self, browser_type=None):
23    optparse.Values.__init__(self)
24
25    self.browser_type = browser_type
26    self.browser_executable = None
27    self.chrome_root = None
28    self.android_device = None
29    self.cros_ssh_identity = None
30
31    # When set to True, the browser will use the default profile.  Telemetry
32    # will not provide an alternate profile directory.
33    self.dont_override_profile = False
34    self.profile_dir = None
35    self.profile_type = None
36    self.extra_browser_args = []
37    self.extra_wpr_args = []
38    self.show_stdout = False
39    self.extensions_to_load = []
40    self.clear_sytem_cache_for_browser_and_profile_on_start = False
41
42    self.cros_remote = None
43    self.wpr_mode = wpr_modes.WPR_OFF
44
45    self.browser_user_agent_type = None
46
47    self.profiler = None
48    self.verbosity = 0
49
50    self.page_filter = None
51    self.page_filter_exclude = None
52
53    self.no_proxy_server = False
54
55    self.repeat_options = repeat_options.RepeatOptions()
56    self.output_file = None
57
58  def Copy(self):
59    return copy.deepcopy(self)
60
61  def CreateParser(self, *args, **kwargs):
62    parser = optparse.OptionParser(*args, **kwargs)
63
64    # Selection group
65    group = optparse.OptionGroup(parser, 'Which browser to use')
66    group.add_option('--browser',
67        dest='browser_type',
68        default=None,
69        help='Browser type to run, '
70             'in order of priority. Supported values: list,%s' %
71             browser_finder.ALL_BROWSER_TYPES)
72    group.add_option('--browser-executable',
73        dest='browser_executable',
74        help='The exact browser to run.')
75    group.add_option('--chrome-root',
76        dest='chrome_root',
77        help='Where to look for chrome builds.'
78             'Defaults to searching parent dirs by default.')
79    group.add_option('--device',
80        dest='android_device',
81        help='The android device ID to use'
82             'If not specified, only 0 or 1 connected devcies are supported.')
83    group.add_option('--keep_test_server_ports', action='store_true',
84        help='Indicates the test server ports must be '
85             'kept. When this is run via a sharder '
86             'the test server ports should be kept and '
87             'should not be reset.')
88    group.add_option(
89        '--remote',
90        dest='cros_remote',
91        help='The IP address of a remote ChromeOS device to use.')
92    identity = None
93    testing_rsa = os.path.join(
94        util.GetChromiumSrcDir(),
95        'third_party', 'chromite', 'ssh_keys', 'testing_rsa')
96    if os.path.exists(testing_rsa):
97      identity = testing_rsa
98    group.add_option('--identity',
99        dest='cros_ssh_identity',
100        default=identity,
101        help='The identity file to use when ssh\'ing into the ChromeOS device')
102    parser.add_option_group(group)
103
104    # Browser options
105    group = optparse.OptionGroup(parser, 'Browser options')
106    profile_choices = profile_types.GetProfileTypes()
107    group.add_option('--profile-type',
108        dest='profile_type',
109        type='choice',
110        default='clean',
111        choices=profile_choices,
112        help=('The user profile to use. A clean profile is used by default. '
113              'Supported values: ' + ', '.join(profile_choices)))
114    group.add_option('--profile-dir',
115        dest='profile_dir',
116        help='Profile directory to launch the browser with. '
117             'A clean profile is used by default')
118    group.add_option('--extra-browser-args',
119        dest='extra_browser_args_as_string',
120        help='Additional arguments to pass to the browser when it starts')
121    group.add_option('--extra-wpr-args',
122        dest='extra_wpr_args_as_string',
123        help=('Additional arguments to pass to Web Page Replay. '
124              'See third_party/webpagereplay/replay.py for usage.'))
125    group.add_option('--show-stdout',
126        action='store_true',
127        help='When possible, will display the stdout of the process')
128    parser.add_option_group(group)
129
130    # Page set options
131    group = optparse.OptionGroup(parser, 'Page set options')
132    group.add_option('--pageset-shuffle', action='store_true',
133        dest='pageset_shuffle',
134        help='Shuffle the order of pages within a pageset.')
135    group.add_option('--pageset-shuffle-order-file',
136        dest='pageset_shuffle_order_file', default=None,
137        help='Filename of an output of a previously run test on the current ' +
138        'pageset. The tests will run in the same order again, overriding ' +
139        'what is specified by --page-repeat and --pageset-repeat.')
140    parser.add_option_group(group)
141
142    group = optparse.OptionGroup(parser, 'Web Page Replay options')
143    group.add_option('--allow-live-sites',
144        dest='allow_live_sites', action='store_true',
145        help='Run against live sites if the Web Page Replay archives don\'t '
146             'exist. Without this flag, the test will just fail instead '
147             'of running against live sites.')
148    parser.add_option_group(group)
149
150    # Debugging options
151    group = optparse.OptionGroup(parser, 'When things go wrong')
152    profiler_choices = profiler_finder.GetAllAvailableProfilers(None)
153    group.add_option(
154      '--profiler', default=None, type='choice',
155      choices=profiler_choices,
156      help=('Record profiling data using this tool. Supported values: ' +
157            ', '.join(profiler_choices)))
158    group.add_option(
159      '-v', '--verbose', action='count', dest='verbosity',
160      help='Increase verbosity level (repeat as needed)')
161    group.add_option('--print-bootstrap-deps',
162                     action='store_true',
163                     help='Output bootstrap deps list.')
164    parser.add_option_group(group)
165
166    # Platform options
167    group = optparse.OptionGroup(parser, 'Platform options')
168    group.add_option('--no-performance-mode', action='store_true',
169        help='Some platforms run on "full performance mode" where the '
170        'test is executed at maximum CPU speed in order to minimize noise '
171        '(specially important for dashboards / continuous builds). '
172        'This option prevents Telemetry from tweaking such platform settings.')
173    parser.add_option_group(group)
174
175    # Repeat options
176    repeat_options.RepeatOptions.AddCommandLineOptions(parser)
177
178    real_parse = parser.parse_args
179    def ParseArgs(args=None):
180      defaults = parser.get_default_values()
181      for k, v in defaults.__dict__.items():
182        if k in self.__dict__ and self.__dict__[k] != None:
183          continue
184        self.__dict__[k] = v
185      ret = real_parse(args, self) # pylint: disable=E1121
186
187      if self.verbosity >= 2:
188        logging.basicConfig(level=logging.DEBUG)
189      elif self.verbosity:
190        logging.basicConfig(level=logging.INFO)
191      else:
192        logging.basicConfig(level=logging.WARNING)
193
194      if self.browser_executable and not self.browser_type:
195        self.browser_type = 'exact'
196      if self.browser_type == 'list':
197        try:
198          types = browser_finder.GetAllAvailableBrowserTypes(self)
199        except browser_finder.BrowserFinderException, ex:
200          sys.stderr.write('ERROR: ' + str(ex))
201          sys.exit(1)
202        sys.stdout.write('Available browsers:\n')
203        sys.stdout.write('  %s\n' % '\n  '.join(types))
204        sys.exit(0)
205      if self.extra_browser_args_as_string: # pylint: disable=E1101
206        tmp = shlex.split(
207          self.extra_browser_args_as_string) # pylint: disable=E1101
208        self.extra_browser_args.extend(tmp)
209        delattr(self, 'extra_browser_args_as_string')
210      if self.extra_wpr_args_as_string: # pylint: disable=E1101
211        tmp = shlex.split(
212          self.extra_wpr_args_as_string) # pylint: disable=E1101
213        self.extra_wpr_args.extend(tmp)
214        delattr(self, 'extra_wpr_args_as_string')
215      if self.profile_type == 'default':
216        self.dont_override_profile = True
217
218      if ((hasattr(self, 'output_format') and self.output_format == 'html') and
219          (not hasattr(self, 'output_file') or not self.output_file)):
220        self.output_file = os.path.join(util.GetBaseDir(), 'results.html')
221
222      # Parse repeat options
223      self.repeat_options.UpdateFromParseResults(self, parser)
224
225      # TODO(jeremy): I'm in the process of adding explicit knowledge of profile
226      # directories to Telemetry. As part of this work profile_type needs to be
227      # reworked to not override profile_dir.
228      if not self.profile_dir:
229        self.profile_dir = profile_types.GetProfileDir(self.profile_type)
230
231      return ret
232    parser.parse_args = ParseArgs
233    return parser
234
235  def AppendExtraBrowserArg(self, arg):
236    if arg not in self.extra_browser_args:
237      self.extra_browser_args.append(arg)
238
239  def MergeDefaultValues(self, defaults):
240    for k, v in defaults.__dict__.items():
241      self.ensure_value(k, v)
242