| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """A tool to run a chrome test executable directly, or in isolated mode. | 6 """A tool to run a chrome test executable directly, or in isolated mode. |
| 7 | 7 |
| 8 TODO(maruel): This script technically needs to die and be replaced by running | 8 TODO(maruel): This script technically needs to die and be replaced by running |
| 9 all the tests always isolated even when not run on Swarming. This will take a | 9 all the tests always isolated even when not run on Swarming. This will take a |
| 10 while. | 10 while. |
| 11 """ | 11 """ |
| 12 | 12 |
| 13 import json | |
| 14 import logging | 13 import logging |
| 15 import optparse | 14 import optparse |
| 16 import os | 15 import os |
| 17 import re | |
| 18 import subprocess | 16 import subprocess |
| 19 import sys | 17 import sys |
| 20 | 18 |
| 21 from slave import build_directory | |
| 22 | |
| 23 | 19 |
| 24 USAGE = ('%s [options] /full/path/to/test.exe -- [original test command]' % | 20 USAGE = ('%s [options] /full/path/to/test.exe -- [original test command]' % |
| 25 os.path.basename(sys.argv[0])) | 21 os.path.basename(sys.argv[0])) |
| 26 | 22 |
| 27 LINUX_ISOLATE_ENABLED_TESTS = set(( | 23 LINUX_ISOLATE_ENABLED_TESTS = set(( |
| 28 'base_unittests', | 24 'base_unittests', |
| 29 'browser_tests', | 25 'browser_tests', |
| 30 'interactive_ui_tests', | 26 'interactive_ui_tests', |
| 31 'net_unittests', | 27 'net_unittests', |
| 32 'unit_tests', | 28 'unit_tests', |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 | 77 |
| 82 | 78 |
| 83 def run_command(command): | 79 def run_command(command): |
| 84 """Inspired from chromium_utils.py's RunCommand().""" | 80 """Inspired from chromium_utils.py's RunCommand().""" |
| 85 print '\n' + subprocess.list2cmdline(command) | 81 print '\n' + subprocess.list2cmdline(command) |
| 86 sys.stdout.flush() | 82 sys.stdout.flush() |
| 87 sys.stderr.flush() | 83 sys.stderr.flush() |
| 88 return subprocess.call(command) | 84 return subprocess.call(command) |
| 89 | 85 |
| 90 | 86 |
| 91 def sanitize_build_dir(s, build_dir_basename): | |
| 92 """Replaces references to build directory in s with references to build_dir""" | |
| 93 return re.sub(r'\b(?:out|build|xcodebuild)([\\/](?:Debug|Release))', | |
| 94 build_dir_basename + r'\1', s) | |
| 95 | |
| 96 | |
| 97 def sanitize_isolated_file(isolated_file, build_dir_basename): | |
| 98 """Crack open .isolated file and fix embedded paths, if necessary. | |
| 99 | |
| 100 isolates assume that they can embed the build directory at build time and | |
| 101 still used that directory at test time. With a builder/tester setup, this | |
| 102 isn't generally true, so rewrite the paths in the isolated file. See | |
| 103 http://crbug.com/311622 for details. This can go away once all bots using | |
| 104 isolates are using ninja. | |
| 105 | |
| 106 TODO(maruel): Do not forget to delete this code once the Windows incremental | |
| 107 builder is switched to ninja. | |
| 108 """ | |
| 109 # See the isolates file format description at: | |
| 110 # https://code.google.com/p/swarming/wiki/IsolatedDesign#.isolated_file_format | |
| 111 with open(isolated_file) as f: | |
| 112 isolated_data = json.load(f) | |
| 113 | |
| 114 # 1. check version | |
| 115 if isolated_data['version'].split('.', 1)[0] != '1': | |
| 116 logging.error('Unexpected isolate version %s', isolated_data['version']) | |
| 117 return 1 | |
| 118 | |
| 119 # 2. fix command, print it | |
| 120 for i in range(len(isolated_data['command'])): | |
| 121 arg = isolated_data['command'][i] | |
| 122 isolated_data['command'][i] = sanitize_build_dir(arg, build_dir_basename) | |
| 123 | |
| 124 # 3. fix files | |
| 125 sanitized_files = {} | |
| 126 for key, value in isolated_data['files'].iteritems(): | |
| 127 # a) fix key | |
| 128 key = sanitize_build_dir(key, build_dir_basename) | |
| 129 sanitized_files[key] = value | |
| 130 # b) fix 'l' entry | |
| 131 if 'l' in value: | |
| 132 value['l'] = sanitize_build_dir(value['l'], build_dir_basename) | |
| 133 isolated_data['files'] = sanitized_files | |
| 134 | |
| 135 # 4. Fix variables->PRODUCT_DIR if necessary (only present in the .state file) | |
| 136 for name in ('path_variables', 'variables'): | |
| 137 variables = isolated_data.get(name, {}) | |
| 138 if 'PRODUCT_DIR' in variables: | |
| 139 variables['PRODUCT_DIR'] = sanitize_build_dir(variables['PRODUCT_DIR'], | |
| 140 build_dir_basename) | |
| 141 | |
| 142 # TODO(thakis): fix 'includes' if necessary. | |
| 143 | |
| 144 with open(isolated_file, 'w') as f: | |
| 145 json.dump(isolated_data, f) | |
| 146 | |
| 147 | |
| 148 def run_test_isolated(isolate_script, test_exe, original_command): | 87 def run_test_isolated(isolate_script, test_exe, original_command): |
| 149 """Runs the test under isolate.py run. | 88 """Runs the test under isolate.py run. |
| 150 | 89 |
| 151 It compensates for discrepancies between sharding_supervisor.py arguments and | 90 It compensates for discrepancies between sharding_supervisor.py arguments and |
| 152 run_test_cases.py arguments. | 91 run_test_cases.py arguments. |
| 153 | 92 |
| 154 The isolated file must be alongside the test executable, with the same | 93 The isolated file must be alongside the test executable, with the same |
| 155 name and the .isolated extension. | 94 name and the .isolated extension. |
| 156 """ | 95 """ |
| 157 isolated_file = os.path.splitext(test_exe)[0] + '.isolated' | 96 isolated_file = os.path.splitext(test_exe)[0] + '.isolated' |
| 158 | 97 |
| 159 if not os.path.exists(isolated_file): | 98 if not os.path.exists(isolated_file): |
| 160 logging.error('No isolate file %s', isolated_file) | 99 logging.error('No isolate file %s', isolated_file) |
| 161 return 1 | 100 return 1 |
| 162 | 101 |
| 163 # '/path/to/src/out' -> 'out' | |
| 164 build_dir_basename = os.path.basename( | |
| 165 build_directory.GetBuildOutputDirectory()) | |
| 166 sanitize_isolated_file(isolated_file, build_dir_basename) | |
| 167 | |
| 168 # Update the .isolated.state cache too. | |
| 169 cache_file = isolated_file + '.state' | |
| 170 if os.path.exists(cache_file): | |
| 171 sanitize_isolated_file(cache_file, build_dir_basename) | |
| 172 | |
| 173 isolate_command = [sys.executable, isolate_script, | 102 isolate_command = [sys.executable, isolate_script, |
| 174 'run', '--isolated', isolated_file, | 103 'run', '--isolated', isolated_file, |
| 175 # Print info log lines, so isolate.py prints the path to | 104 # Print info log lines, so isolate.py prints the path to |
| 176 # the binary it's about to run, http://crbug.com/311625 | 105 # the binary it's about to run, http://crbug.com/311625 |
| 177 '-v'] | 106 '-v'] |
| 178 | 107 |
| 179 # Start setting the test specific options. | 108 # Start setting the test specific options. |
| 180 isolate_command.append('--') | 109 isolate_command.append('--') |
| 181 isolate_command.append('--no-cr') | 110 isolate_command.append('--no-cr') |
| 182 original_command = original_command[:] | 111 original_command = original_command[:] |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 isolate_script = os.path.join(options.checkout_dir, 'src', 'tools', | 164 isolate_script = os.path.join(options.checkout_dir, 'src', 'tools', |
| 236 'swarm_client', 'isolate.py') | 165 'swarm_client', 'isolate.py') |
| 237 return run_test_isolated(isolate_script, test_exe, original_command) | 166 return run_test_isolated(isolate_script, test_exe, original_command) |
| 238 else: | 167 else: |
| 239 logging.info('Running test normally') | 168 logging.info('Running test normally') |
| 240 return run_command(original_command) | 169 return run_command(original_command) |
| 241 | 170 |
| 242 | 171 |
| 243 if '__main__' == __name__: | 172 if '__main__' == __name__: |
| 244 sys.exit(main(None)) | 173 sys.exit(main(None)) |
| OLD | NEW |