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 |