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

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: Integrated CL comments 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_interfaces_info and idl_compiler
37 module_path = os.path.dirname(__file__)
38 source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir,
39 os.pardir, os.pardir, 'Source'))
40 sys.path.append(source_path)
41
42 from bindings.scripts.compute_interfaces_info import compute_interfaces_info, in terfaces_info
43 from bindings.scripts.idl_compiler import IdlCompilerV8
44
45
35 PASS_MESSAGE = 'All tests PASS!' 46 PASS_MESSAGE = 'All tests PASS!'
36 FAIL_MESSAGE = """Some tests FAIL! 47 FAIL_MESSAGE = """Some tests FAIL!
37 To update the reference files, execute: 48 To update the reference files, execute:
38 run-bindings-tests --reset-results 49 run-bindings-tests --reset-results
39 50
40 If the failures are not due to your changes, test results may be out of sync; 51 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. 52 please rebaseline them in a separate CL, after checking that tests fail in ToT.
42 In CL, please set: 53 In CL, please set:
43 NOTRY=true 54 NOTRY=true
44 TBR=(someone in Source/bindings/OWNERS or WATCHLISTS:bindings) 55 TBR=(someone in Source/bindings/OWNERS or WATCHLISTS:bindings)
45 """ 56 """
46 57
47 DEPENDENCY_IDL_FILES = set([ 58 DEPENDENCY_IDL_FILES = set([
48 'SupportTestPartialInterface.idl', 59 'SupportTestPartialInterface.idl',
49 'TestImplements.idl', 60 'TestImplements.idl',
50 'TestImplements2.idl', 61 'TestImplements2.idl',
51 'TestImplements3.idl', 62 'TestImplements3.idl',
52 'TestPartialInterface.idl', 63 'TestPartialInterface.idl',
53 'TestPartialInterfacePython.idl', 64 'TestPartialInterfacePython.idl',
54 'TestPartialInterfacePython2.idl', 65 'TestPartialInterfacePython2.idl',
55 ]) 66 ])
56 67
68
69 EXTENDED_ATTRIBUTES_FILE = 'bindings/IDLExtendedAttributes.txt'
70
57 all_input_directory = '.' # Relative to Source/ 71 all_input_directory = '.' # Relative to Source/
58 test_input_directory = os.path.join('bindings', 'tests', 'idls') 72 test_input_directory = os.path.join('bindings', 'tests', 'idls')
59 reference_directory = os.path.join('bindings', 'tests', 'results') 73 reference_directory = os.path.join('bindings', 'tests', 'results')
60 74
61 75
62 class ScopedTempFileProvider(object): 76 class ScopedTempFileProvider(object):
63 def __init__(self): 77 def __init__(self):
64 self.file_handles = [] 78 self.file_handles = []
65 self.file_paths = [] 79 self.file_paths = []
66 self.dir_paths = [] 80 self.dir_paths = []
(...skipping 22 matching lines...) Expand all
89 self.dir_paths.append(dir_path) 103 self.dir_paths.append(dir_path)
90 return dir_path 104 return dir_path
91 105
92 106
93 class BindingsTests(object): 107 class BindingsTests(object):
94 def __init__(self, reset_results, verbose, provider): 108 def __init__(self, reset_results, verbose, provider):
95 self.reset_results = reset_results 109 self.reset_results = reset_results
96 self.verbose = verbose 110 self.verbose = verbose
97 self.executive = executive.Executive() 111 self.executive = executive.Executive()
98 self.provider = provider 112 self.provider = provider
99 _, self.interfaces_info_filename = provider.new_temp_file() 113 self.idl_compiler = None
100 # Generate output into the reference directory if resetting results, or 114 # Generate output into the reference directory if resetting results, or
101 # a temp directory if not. 115 # a temp directory if not.
102 if reset_results: 116 if reset_results:
103 self.output_directory = reference_directory 117 self.output_directory = reference_directory
104 else: 118 else:
105 self.output_directory = provider.new_temp_dir() 119 self.output_directory = provider.new_temp_dir()
106 120
107 def run_command(self, cmd): 121 def run_command(self, cmd):
108 output = self.executive.run_command(cmd) 122 output = self.executive.run_command(cmd)
109 if output: 123 if output:
110 print output 124 print output
111 125
112 def generate_from_idl(self, idl_file): 126 def generate_from_idl(self, idl_file):
113 cmd = ['python', 127 idl_file_fullpath = os.path.realpath(idl_file)
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 self.idl_compiler.compile_file(idl_file_fullpath)
121 except ScriptError, e: 130 except Exception as err:
122 print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file) 131 print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file)
123 print e.output 132 print err
124 return e.exit_code 133 return 1
134
125 return 0 135 return 0
126 136
127 def generate_interface_dependencies(self): 137 def generate_interface_dependencies(self):
128 def idl_paths(directory): 138 def idl_paths(directory):
129 return [os.path.join(directory, input_file) 139 return [os.path.join(directory, input_file)
130 for input_file in os.listdir(directory) 140 for input_file in os.listdir(directory)
131 if input_file.endswith('.idl')] 141 if input_file.endswith('.idl')]
132 142
133 def idl_paths_recursive(directory): 143 def idl_paths_recursive(directory):
134 idl_paths = [] 144 idl_paths = []
135 for dirpath, _, files in os.walk(directory): 145 for dirpath, _, files in os.walk(directory):
136 idl_paths.extend(os.path.join(dirpath, filename) 146 idl_paths.extend(os.path.join(dirpath, filename)
137 for filename in fnmatch.filter(files, '*.idl')) 147 for filename in fnmatch.filter(files, '*.idl'))
138 return idl_paths 148 return idl_paths
139 149
140 def write_list_file(idl_paths): 150 def write_list_file(idl_paths):
141 list_file, list_filename = self.provider.new_temp_file() 151 list_file, list_filename = self.provider.new_temp_file()
142 list_contents = ''.join(idl_path + '\n' 152 list_contents = ''.join(idl_path + '\n'
143 for idl_path in idl_paths) 153 for idl_path in idl_paths)
144 os.write(list_file, list_contents) 154 os.write(list_file, list_contents)
145 return list_filename 155 return list_filename
146 156
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 157 # We compute interfaces info for *all* IDL files, not just test IDL
156 # files, as code generator output depends on inheritance (both ancestor 158 # files, as code generator output depends on inheritance (both ancestor
157 # chain and inherited extended attributes), and some real interfaces 159 # chain and inherited extended attributes), and some real interfaces
158 # are special-cased, such as Node. 160 # are special-cased, such as Node.
159 # 161 #
160 # For example, when testing the behavior of interfaces that inherit 162 # For example, when testing the behavior of interfaces that inherit
161 # from Node, we also need to know that these inherit from EventTarget, 163 # from Node, we also need to know that these inherit from EventTarget,
162 # since this is also special-cased and Node inherits from EventTarget, 164 # since this is also special-cased and Node inherits from EventTarget,
163 # but this inheritance information requires computing dependencies for 165 # but this inheritance information requires computing dependencies for
164 # the real Node.idl file. 166 # the real Node.idl file.
165 all_idl_files_list_filename = write_list_file(idl_paths_recursive(all_in put_directory))
166 try: 167 try:
167 compute_interfaces_info(all_idl_files_list_filename) 168 compute_interfaces_info(idl_paths_recursive(all_input_directory))
168 except ScriptError, e: 169 except Exception as err:
169 print 'ERROR: compute_interfaces_info.py' 170 print 'ERROR: compute_interfaces_info.py'
170 print e.output 171 print err
171 return e.exit_code 172 return 1
173
172 return 0 174 return 0
173 175
174 def delete_cache_files(self): 176 def delete_cache_files(self):
175 # FIXME: Instead of deleting cache files, don't generate them. 177 # FIXME: Instead of deleting cache files, don't generate them.
176 cache_files = [os.path.join(self.output_directory, output_file) 178 cache_files = [os.path.join(self.output_directory, output_file)
177 for output_file in os.listdir(self.output_directory) 179 for output_file in os.listdir(self.output_directory)
178 if (output_file in ('lextab.py', # PLY lex 180 if (output_file in ('lextab.py', # PLY lex
179 'lextab.pyc', 181 'lextab.pyc',
180 'parsetab.pickle') or # PLY yacc 182 'parsetab.pickle') or # PLY yacc
181 output_file.endswith('.cache'))] # Jinja 183 output_file.endswith('.cache'))] # Jinja
182 for cache_file in cache_files: 184 for cache_file in cache_files:
183 os.remove(cache_file) 185 os.remove(cache_file)
184 186
185 def identical_file(self, reference_filename, output_filename): 187 def identical_file(self, reference_filename, output_filename):
186 reference_basename = os.path.basename(reference_filename) 188 reference_basename = os.path.basename(reference_filename)
187 cmd = ['diff', 189 cmd = ['diff',
188 '-u', 190 '-u',
189 '-N', 191 '-N',
190 reference_filename, 192 reference_filename,
191 output_filename] 193 output_filename]
192 try: 194 try:
193 self.run_command(cmd) 195 self.run_command(cmd)
194 except ScriptError, e: 196 except ScriptError as err:
195 # run_command throws an exception on diff (b/c non-zero exit code) 197 # run_command throws an exception on diff (b/c non-zero exit code)
196 print 'FAIL: %s' % reference_basename 198 print 'FAIL: %s' % reference_basename
197 print e.output 199 print err.output
198 return False 200 return False
199 201
200 if self.verbose: 202 if self.verbose:
201 print 'PASS: %s' % reference_basename 203 print 'PASS: %s' % reference_basename
202 return True 204 return True
203 205
204 def identical_output_files(self): 206 def identical_output_files(self):
205 file_pairs = [(os.path.join(reference_directory, output_file), 207 file_pairs = [(os.path.join(reference_directory, output_file),
206 os.path.join(self.output_directory, output_file)) 208 os.path.join(self.output_directory, output_file))
207 for output_file in os.listdir(self.output_directory)] 209 for output_file in os.listdir(self.output_directory)]
(...skipping 11 matching lines...) Expand all
219 '(probably cruft from renaming or deleting):\n' + 221 '(probably cruft from renaming or deleting):\n' +
220 '\n'.join(excess_files)) 222 '\n'.join(excess_files))
221 return False 223 return False
222 return True 224 return True
223 225
224 def run_tests(self): 226 def run_tests(self):
225 # Generate output, immediately dying on failure 227 # Generate output, immediately dying on failure
226 if self.generate_interface_dependencies(): 228 if self.generate_interface_dependencies():
227 return False 229 return False
228 230
231 self.idl_compiler = IdlCompilerV8(self.output_directory,
232 EXTENDED_ATTRIBUTES_FILE,
233 interfaces_info=interfaces_info,
234 only_if_changed=True)
235
229 for input_filename in os.listdir(test_input_directory): 236 for input_filename in os.listdir(test_input_directory):
230 if not input_filename.endswith('.idl'): 237 if not input_filename.endswith('.idl'):
231 continue 238 continue
232 if input_filename in DEPENDENCY_IDL_FILES: 239 if input_filename in DEPENDENCY_IDL_FILES:
233 # Dependencies aren't built (they are used by the dependent) 240 # Dependencies aren't built (they are used by the dependent)
234 if self.verbose: 241 if self.verbose:
235 print 'DEPENDENCY: %s' % input_filename 242 print 'DEPENDENCY: %s' % input_filename
236 continue 243 continue
237 244
238 idl_path = os.path.join(test_input_directory, input_filename) 245 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')) 260 os.chdir(os.path.join(current_scm.checkout_root, 'Source'))
254 261
255 all_tests_passed = self.run_tests() 262 all_tests_passed = self.run_tests()
256 if all_tests_passed: 263 if all_tests_passed:
257 if self.verbose: 264 if self.verbose:
258 print 265 print
259 print PASS_MESSAGE 266 print PASS_MESSAGE
260 return 0 267 return 0
261 print 268 print
262 print FAIL_MESSAGE 269 print FAIL_MESSAGE
263 return -1 270 return 1
264 271
265 272
266 def run_bindings_tests(reset_results, verbose): 273 def run_bindings_tests(reset_results, verbose):
267 with ScopedTempFileProvider() as provider: 274 with ScopedTempFileProvider() as provider:
268 return BindingsTests(reset_results, verbose, provider).main() 275 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