Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(309)

Side by Side Diff: Tools/Scripts/webkitpy/bindings/main.py

Issue 169743005: Faster run-bindings-tests (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Changes from CR Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/bindings/scripts/__init__.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (C) 2011 Google Inc. All rights reserved. 1 # Copyright (C) 2011 Google Inc. All rights reserved.
2 # 2 #
3 # Redistribution and use in source and binary forms, with or without 3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions 4 # modification, are permitted provided that the following conditions
5 # are met: 5 # are met:
6 # 1. Redistributions of source code must retain the above copyright 6 # 1. Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer. 7 # notice, this list of conditions and the following disclaimer.
8 # 2. Redistributions in binary form must reproduce the above copyright 8 # 2. Redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the 9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution. 10 # documentation and/or other materials provided with the distribution.
11 # 11 #
12 # THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 12 # THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
13 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 13 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 14 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
15 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 15 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
16 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 16 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
17 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 17 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
18 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 18 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
19 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 19 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
20 # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 21 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 # 23 #
24 24
25 import fnmatch 25 import fnmatch
26 import os 26 import os
27 import cPickle as pickle
28 import shutil 27 import shutil
28 import sys
29 import tempfile 29 import tempfile
30 30
31 from webkitpy.common.checkout.scm.detection import detect_scm_system 31 from webkitpy.common.checkout.scm.detection import detect_scm_system
32 from webkitpy.common.system import executive 32 from webkitpy.common.system import executive
33 from webkitpy.common.system.executive import ScriptError 33 from webkitpy.common.system.executive import ScriptError
34 34
35 # Add Source path to PYTHONPATH to support function calls to bindings/scripts
36 # for compute_dependencies and idl_compiler
Nils Barth (inactive) 2014/03/17 02:06:14 Could you update this to: "compute_interfaces_info
terry 2014/03/17 16:36:38 Done.
37 module_path = os.path.dirname(__file__)
38 source_path = os.path.normpath(os.path.join(module_path, os.pardir,
Nils Barth (inactive) 2014/03/17 02:06:14 Could you wrap the line slightly tighter? It fits
terry 2014/03/17 16:36:38 Done.
39 os.pardir, os.pardir, os.pardir,
40 'Source'))
41 sys.path.append(source_path)
42
43 from bindings.scripts.compute_interfaces_info import compute_interfaces_info, in terfaces_info
44 from bindings.scripts.idl_compiler import IdlCompilerV8
45
46
35 PASS_MESSAGE = 'All tests PASS!' 47 PASS_MESSAGE = 'All tests PASS!'
36 FAIL_MESSAGE = """Some tests FAIL! 48 FAIL_MESSAGE = """Some tests FAIL!
37 To update the reference files, execute: 49 To update the reference files, execute:
38 run-bindings-tests --reset-results 50 run-bindings-tests --reset-results
39 51
40 If the failures are not due to your changes, test results may be out of sync; 52 If the failures are not due to your changes, test results may be out of sync;
41 please rebaseline them in a separate CL, after checking that tests fail in ToT. 53 please rebaseline them in a separate CL, after checking that tests fail in ToT.
42 In CL, please set: 54 In CL, please set:
43 NOTRY=true 55 NOTRY=true
44 TBR=(someone in Source/bindings/OWNERS or WATCHLISTS:bindings) 56 TBR=(someone in Source/bindings/OWNERS or WATCHLISTS:bindings)
45 """ 57 """
46 58
47 DEPENDENCY_IDL_FILES = set([ 59 DEPENDENCY_IDL_FILES = set([
48 'SupportTestPartialInterface.idl', 60 'SupportTestPartialInterface.idl',
49 'TestImplements.idl', 61 'TestImplements.idl',
50 'TestImplements2.idl', 62 'TestImplements2.idl',
51 'TestImplements3.idl', 63 'TestImplements3.idl',
52 'TestPartialInterface.idl', 64 'TestPartialInterface.idl',
53 'TestPartialInterfacePython.idl', 65 'TestPartialInterfacePython.idl',
54 'TestPartialInterfacePython2.idl', 66 'TestPartialInterfacePython2.idl',
55 ]) 67 ])
56 68
69
70 EXTENDED_ATTRIBUTES_FILE = 'bindings/IDLExtendedAttributes.txt'
71
57 all_input_directory = '.' # Relative to Source/ 72 all_input_directory = '.' # Relative to Source/
58 test_input_directory = os.path.join('bindings', 'tests', 'idls') 73 test_input_directory = os.path.join('bindings', 'tests', 'idls')
59 reference_directory = os.path.join('bindings', 'tests', 'results') 74 reference_directory = os.path.join('bindings', 'tests', 'results')
60 75
61 76
62 class ScopedTempFileProvider(object): 77 class ScopedTempFileProvider(object):
63 def __init__(self): 78 def __init__(self):
64 self.file_handles = [] 79 self.file_handles = []
65 self.file_paths = [] 80 self.file_paths = []
66 self.dir_paths = [] 81 self.dir_paths = []
(...skipping 22 matching lines...) Expand all
89 self.dir_paths.append(dir_path) 104 self.dir_paths.append(dir_path)
90 return dir_path 105 return dir_path
91 106
92 107
93 class BindingsTests(object): 108 class BindingsTests(object):
94 def __init__(self, reset_results, verbose, provider): 109 def __init__(self, reset_results, verbose, provider):
95 self.reset_results = reset_results 110 self.reset_results = reset_results
96 self.verbose = verbose 111 self.verbose = verbose
97 self.executive = executive.Executive() 112 self.executive = executive.Executive()
98 self.provider = provider 113 self.provider = provider
99 _, self.interfaces_info_filename = provider.new_temp_file() 114 self.idl_compiler = None
100 # Generate output into the reference directory if resetting results, or 115 # Generate output into the reference directory if resetting results, or
101 # a temp directory if not. 116 # a temp directory if not.
102 if reset_results: 117 if reset_results:
103 self.output_directory = reference_directory 118 self.output_directory = reference_directory
104 else: 119 else:
105 self.output_directory = provider.new_temp_dir() 120 self.output_directory = provider.new_temp_dir()
106 121
107 def run_command(self, cmd): 122 def run_command(self, cmd):
108 output = self.executive.run_command(cmd) 123 output = self.executive.run_command(cmd)
109 if output: 124 if output:
110 print output 125 print output
111 126
112 def generate_from_idl(self, idl_file): 127 def generate_from_idl(self, idl_file):
113 cmd = ['python',
114 'bindings/scripts/idl_compiler.py',
115 '--output-dir', self.output_directory,
116 '--idl-attributes-file', 'bindings/IDLExtendedAttributes.txt',
117 '--interfaces-info-file', self.interfaces_info_filename,
118 idl_file]
119 try: 128 try:
120 self.run_command(cmd) 129 idl_file_fullpath = os.path.realpath(idl_file)
Nils Barth (inactive) 2014/03/17 02:06:14 Could you move this before the try statement?
terry 2014/03/17 16:36:38 Done.
130 self.idl_compiler.compile_file(idl_file_fullpath)
121 except ScriptError, e: 131 except ScriptError, e:
Nils Barth (inactive) 2014/03/17 02:06:14 We need to update this catch clause, since we're n
terry 2014/03/17 16:36:38 Done.
122 print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file) 132 print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file)
123 print e.output 133 print e.output
Nils Barth (inactive) 2014/03/17 02:06:14 This can then just be: print err
terry 2014/03/17 16:36:38 Done.
124 return e.exit_code 134 return e.exit_code
Nils Barth (inactive) 2014/03/17 02:06:14 ...and then: return 1
terry 2014/03/17 16:36:38 Done.
135
125 return 0 136 return 0
126 137
127 def generate_interface_dependencies(self): 138 def generate_interface_dependencies(self):
128 def idl_paths(directory): 139 def idl_paths(directory):
129 return [os.path.join(directory, input_file) 140 return [os.path.join(directory, input_file)
130 for input_file in os.listdir(directory) 141 for input_file in os.listdir(directory)
131 if input_file.endswith('.idl')] 142 if input_file.endswith('.idl')]
132 143
133 def idl_paths_recursive(directory): 144 def idl_paths_recursive(directory):
134 idl_paths = [] 145 idl_paths = []
135 for dirpath, _, files in os.walk(directory): 146 for dirpath, _, files in os.walk(directory):
136 idl_paths.extend(os.path.join(dirpath, filename) 147 idl_paths.extend(os.path.join(dirpath, filename)
137 for filename in fnmatch.filter(files, '*.idl')) 148 for filename in fnmatch.filter(files, '*.idl'))
138 return idl_paths 149 return idl_paths
139 150
140 def write_list_file(idl_paths): 151 def write_list_file(idl_paths):
141 list_file, list_filename = self.provider.new_temp_file() 152 list_file, list_filename = self.provider.new_temp_file()
142 list_contents = ''.join(idl_path + '\n' 153 list_contents = ''.join(idl_path + '\n'
143 for idl_path in idl_paths) 154 for idl_path in idl_paths)
144 os.write(list_file, list_contents) 155 os.write(list_file, list_contents)
145 return list_filename 156 return list_filename
146 157
147 def compute_interfaces_info(idl_files_list_filename):
148 cmd = ['python',
149 'bindings/scripts/compute_interfaces_info.py',
150 '--idl-files-list', idl_files_list_filename,
151 '--interfaces-info-file', self.interfaces_info_filename,
152 '--write-file-only-if-changed', '0']
153 self.run_command(cmd)
154
155 # We compute interfaces info for *all* IDL files, not just test IDL 158 # We compute interfaces info for *all* IDL files, not just test IDL
156 # files, as code generator output depends on inheritance (both ancestor 159 # files, as code generator output depends on inheritance (both ancestor
157 # chain and inherited extended attributes), and some real interfaces 160 # chain and inherited extended attributes), and some real interfaces
158 # are special-cased, such as Node. 161 # are special-cased, such as Node.
159 # 162 #
160 # For example, when testing the behavior of interfaces that inherit 163 # For example, when testing the behavior of interfaces that inherit
161 # from Node, we also need to know that these inherit from EventTarget, 164 # from Node, we also need to know that these inherit from EventTarget,
162 # since this is also special-cased and Node inherits from EventTarget, 165 # since this is also special-cased and Node inherits from EventTarget,
163 # but this inheritance information requires computing dependencies for 166 # but this inheritance information requires computing dependencies for
164 # the real Node.idl file. 167 # the real Node.idl file.
165 all_idl_files_list_filename = write_list_file(idl_paths_recursive(all_in put_directory))
166 try: 168 try:
167 compute_interfaces_info(all_idl_files_list_filename) 169 compute_interfaces_info(idl_paths_recursive(all_input_directory))
170
168 except ScriptError, e: 171 except ScriptError, e:
Nils Barth (inactive) 2014/03/17 02:06:14 Could you update this catch clause as described ab
terry 2014/03/17 16:36:38 Done.
169 print 'ERROR: compute_interfaces_info.py' 172 print 'ERROR: compute_interfaces_info.py'
170 print e.output 173 print e.output
171 return e.exit_code 174 return e.exit_code
175
172 return 0 176 return 0
173 177
174 def delete_cache_files(self): 178 def delete_cache_files(self):
175 # FIXME: Instead of deleting cache files, don't generate them. 179 # FIXME: Instead of deleting cache files, don't generate them.
176 cache_files = [os.path.join(self.output_directory, output_file) 180 cache_files = [os.path.join(self.output_directory, output_file)
177 for output_file in os.listdir(self.output_directory) 181 for output_file in os.listdir(self.output_directory)
178 if (output_file in ('lextab.py', # PLY lex 182 if (output_file in ('lextab.py', # PLY lex
179 'lextab.pyc', 183 'lextab.pyc',
180 'parsetab.pickle') or # PLY yacc 184 'parsetab.pickle') or # PLY yacc
181 output_file.endswith('.cache'))] # Jinja 185 output_file.endswith('.cache'))] # Jinja
182 for cache_file in cache_files: 186 for cache_file in cache_files:
183 os.remove(cache_file) 187 os.remove(cache_file)
184 188
185 def identical_file(self, reference_filename, output_filename): 189 def identical_file(self, reference_filename, output_filename):
186 reference_basename = os.path.basename(reference_filename) 190 reference_basename = os.path.basename(reference_filename)
187 cmd = ['diff', 191 cmd = ['diff',
188 '-u', 192 '-u',
189 '-N', 193 '-N',
190 reference_filename, 194 reference_filename,
191 output_filename] 195 output_filename]
192 try: 196 try:
193 self.run_command(cmd) 197 self.run_command(cmd)
194 except ScriptError, e: 198 except ScriptError, e:
Nils Barth (inactive) 2014/03/17 02:06:14 BTW, could you update this to: except ScriptError
terry 2014/03/17 16:36:38 Done.
195 # run_command throws an exception on diff (b/c non-zero exit code) 199 # run_command throws an exception on diff (b/c non-zero exit code)
196 print 'FAIL: %s' % reference_basename 200 print 'FAIL: %s' % reference_basename
197 print e.output 201 print e.output
198 return False 202 return False
199 203
200 if self.verbose: 204 if self.verbose:
201 print 'PASS: %s' % reference_basename 205 print 'PASS: %s' % reference_basename
202 return True 206 return True
203 207
204 def identical_output_files(self): 208 def identical_output_files(self):
(...skipping 14 matching lines...) Expand all
219 '(probably cruft from renaming or deleting):\n' + 223 '(probably cruft from renaming or deleting):\n' +
220 '\n'.join(excess_files)) 224 '\n'.join(excess_files))
221 return False 225 return False
222 return True 226 return True
223 227
224 def run_tests(self): 228 def run_tests(self):
225 # Generate output, immediately dying on failure 229 # Generate output, immediately dying on failure
226 if self.generate_interface_dependencies(): 230 if self.generate_interface_dependencies():
227 return False 231 return False
228 232
233 self.idl_compiler = IdlCompilerV8(self.output_directory,
Nils Barth (inactive) 2014/03/17 02:06:14 Could you move this up into the __init__?
terry 2014/03/17 16:36:38 I don't think so the interfaces_info isn't compute
Nils Barth (inactive) 2014/03/18 09:23:16 Got it, thanks! (I think we could simplify r-b-t b
234 EXTENDED_ATTRIBUTES_FILE,
235 interfaces_info=interfaces_info,
236 only_if_changed=True)
237
229 for input_filename in os.listdir(test_input_directory): 238 for input_filename in os.listdir(test_input_directory):
230 if not input_filename.endswith('.idl'): 239 if not input_filename.endswith('.idl'):
231 continue 240 continue
232 if input_filename in DEPENDENCY_IDL_FILES: 241 if input_filename in DEPENDENCY_IDL_FILES:
233 # Dependencies aren't built (they are used by the dependent) 242 # Dependencies aren't built (they are used by the dependent)
234 if self.verbose: 243 if self.verbose:
235 print 'DEPENDENCY: %s' % input_filename 244 print 'DEPENDENCY: %s' % input_filename
236 continue 245 continue
237 246
238 idl_path = os.path.join(test_input_directory, input_filename) 247 idl_path = os.path.join(test_input_directory, input_filename)
(...skipping 14 matching lines...) Expand all
253 os.chdir(os.path.join(current_scm.checkout_root, 'Source')) 262 os.chdir(os.path.join(current_scm.checkout_root, 'Source'))
254 263
255 all_tests_passed = self.run_tests() 264 all_tests_passed = self.run_tests()
256 if all_tests_passed: 265 if all_tests_passed:
257 if self.verbose: 266 if self.verbose:
258 print 267 print
259 print PASS_MESSAGE 268 print PASS_MESSAGE
260 return 0 269 return 0
261 print 270 print
262 print FAIL_MESSAGE 271 print FAIL_MESSAGE
263 return -1 272 return -1
Nils Barth (inactive) 2014/03/17 02:06:14 Also, could we update this to return 1 ? (Exit sta
terry 2014/03/17 16:36:38 Done.
264 273
265 274
266 def run_bindings_tests(reset_results, verbose): 275 def run_bindings_tests(reset_results, verbose):
267 with ScopedTempFileProvider() as provider: 276 with ScopedTempFileProvider() as provider:
268 return BindingsTests(reset_results, verbose, provider).main() 277 return BindingsTests(reset_results, verbose, provider).main()
OLDNEW
« no previous file with comments | « Source/bindings/scripts/__init__.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698