1#!/usr/bin/env python
2# Copyright 2013 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Run Manual Test Bisect Tool
7
8An example usage:
9tools/run-bisect-manual-test.py -g 201281 -b 201290
10
11On Linux platform, follow the instructions in this document
12https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment
13to setup the sandbox manually before running the script. Otherwise the script
14fails to launch Chrome and exits with an error.
15
16This script serves a similar function to bisect-builds.py, except it uses
17the bisect_perf_regression.py. This means that that it can obtain builds of
18Chromium for revisions where builds aren't available in cloud storage.
19"""
20
21import os
22import subprocess
23import sys
24
25CROS_BOARD_ENV = 'BISECT_CROS_BOARD'
26CROS_IP_ENV = 'BISECT_CROS_IP'
27_TOOLS_DIR = os.path.abspath(os.path.dirname(__file__))
28_BISECT_SCRIPT_PATH = os.path.join(
29    _TOOLS_DIR, 'auto_bisect', 'bisect_perf_regression.py')
30
31sys.path.append(os.path.join(_TOOLS_DIR, 'telemetry'))
32from telemetry.core import browser_options
33
34
35def _RunBisectionScript(options):
36  """Attempts to execute the bisect script (bisect_perf_regression.py).
37
38  Args:
39    options: The configuration options to pass to the bisect script.
40
41  Returns:
42    An exit code; 0 for success, 1 for failure.
43  """
44  test_command = ('python %s --browser=%s --chrome-root=.' %
45                  (os.path.join(_TOOLS_DIR, 'bisect-manual-test.py'),
46                   options.browser_type))
47
48  cmd = ['python', _BISECT_SCRIPT_PATH,
49         '-c', test_command,
50         '-g', options.good_revision,
51         '-b', options.bad_revision,
52         '-m', 'manual_test/manual_test',
53         '-r', '1',
54         '--working_directory', options.working_directory,
55         '--build_preference', 'ninja',
56         '--use_goma',
57         '--no_custom_deps']
58
59  if options.extra_src:
60    cmd.extend(['--extra_src', options.extra_src])
61
62  if 'cros' in options.browser_type:
63    cmd.extend(['--target_platform', 'cros'])
64
65    if os.environ[CROS_BOARD_ENV] and os.environ[CROS_IP_ENV]:
66      cmd.extend(['--cros_board', os.environ[CROS_BOARD_ENV]])
67      cmd.extend(['--cros_remote_ip', os.environ[CROS_IP_ENV]])
68    else:
69      print ('Error: Cros build selected, but BISECT_CROS_IP or'
70             'BISECT_CROS_BOARD undefined.\n')
71      return 1
72  elif 'android-chrome' in options.browser_type:
73    cmd.extend(['--target_platform', 'android-chrome'])
74  elif 'android' in options.browser_type:
75    cmd.extend(['--target_platform', 'android'])
76  elif not options.target_build_type:
77    cmd.extend(['--target_build_type', options.browser_type.title()])
78
79  if options.target_build_type:
80    cmd.extend(['--target_build_type', options.target_build_type])
81
82  cmd = [str(c) for c in cmd]
83
84  return_code = subprocess.call(cmd)
85
86  if return_code:
87    print 'Error: bisect_perf_regression.py had exit code %d.' % return_code
88    print
89
90  return return_code
91
92
93def main():
94  """Does a bisect based on the command-line arguments passed in.
95
96  The user will be prompted to classify each revision as good or bad.
97  """
98  usage = ('%prog [options]\n'
99           'Used to run the bisection script with a manual test.')
100
101  options = browser_options.BrowserFinderOptions('release')
102  parser = options.CreateParser(usage)
103
104  parser.add_option('-b', '--bad_revision',
105                    type='str',
106                    help='A bad revision to start bisection. ' +
107                    'Must be later than good revision. May be either a git' +
108                    ' or svn revision.')
109  parser.add_option('-g', '--good_revision',
110                    type='str',
111                    help='A revision to start bisection where performance' +
112                    ' test is known to pass. Must be earlier than the ' +
113                    'bad revision. May be either a git or svn revision.')
114  parser.add_option('-w', '--working_directory',
115                    type='str',
116                    default='..',
117                    help='A working directory to supply to the bisection '
118                    'script, which will use it as the location to checkout '
119                    'a copy of the chromium depot.')
120  parser.add_option('--extra_src',
121                    type='str',
122                    help='Path to extra source file. If this is supplied, '
123                    'bisect script will use this to override default behavior.')
124  parser.add_option('--target_build_type',
125                     type='choice',
126                     choices=['Release', 'Debug'],
127                     help='The target build type. Choices are "Release" '
128                     'or "Debug".')
129  options, _ = parser.parse_args()
130  error_msg = ''
131  if not options.good_revision:
132    error_msg += 'Error: missing required parameter: --good_revision\n'
133  if not options.bad_revision:
134    error_msg += 'Error: missing required parameter: --bad_revision\n'
135
136  if error_msg:
137    print error_msg
138    parser.print_help()
139    return 1
140
141  if 'android' not in options.browser_type and sys.platform.startswith('linux'):
142    if not os.environ.get('CHROME_DEVEL_SANDBOX'):
143      print 'SUID sandbox has not been setup.'\
144            ' See https://code.google.com/p/chromium/wiki/'\
145            'LinuxSUIDSandboxDevelopment for more information.'
146      return 1
147
148  return _RunBisectionScript(options)
149
150
151if __name__ == '__main__':
152  sys.exit(main())
153