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

Side by Side Diff: tools/code_coverage/coverage.py

Issue 8157: Fixed a crash in the coverage script.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | 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 #!/bin/env python 1 #!/bin/env python
2 # Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2006-2008 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 6
7 """Module to setup and generate code coverage data 7 """Module to setup and generate code coverage data
8 8
9 This module first sets up the environment for code coverage, instruments the 9 This module first sets up the environment for code coverage, instruments the
10 binaries, runs the tests and collects the code coverage data. 10 binaries, runs the tests and collects the code coverage data.
(...skipping 12 matching lines...) Expand all
23 import shutil 23 import shutil
24 import subprocess 24 import subprocess
25 import sys 25 import sys
26 import tempfile 26 import tempfile
27 27
28 import google.logging_utils 28 import google.logging_utils
29 import google.process_utils as proc 29 import google.process_utils as proc
30 30
31 31
32 # The list of binaries that will be instrumented for code coverage 32 # The list of binaries that will be instrumented for code coverage
33 windows_binaries = ['unit_tests.exe', 33 windows_binaries = ['base_unittests.exe',
34 'unit_tests.exe',
35 'automated_ui_tests.exe',
34 'ui_tests.exe', 36 'ui_tests.exe',
37 'installer_unittests.exe',
35 'ipc_tests.exe', 38 'ipc_tests.exe',
36 'memory_test.exe', 39 'memory_test.exe',
37 'net_perftests.exe', 40 'net_perftests.exe',
38 'net_unittests.exe', 41 'net_unittests.exe',
39 'page_cycler_tests.exe', 42 'page_cycler_tests.exe',
40 'perf_tests.exe', 43 'perf_tests.exe',
41 'plugin_tests.exe', 44 'plugin_tests.exe',
45 'security_tests.dll',
42 'selenium_tests.exe', 46 'selenium_tests.exe',
47 'startup_tests.exe',
43 'tab_switching_test.exe', 48 'tab_switching_test.exe',
44 'test_shell_tests.exe', 49 'test_shell_tests.exe',
45 'test_shell.exe', 50 'test_shell.exe',
46 'activex_test_control.dll'] 51 'activex_test_control.dll']
47 52
48 # The list of tests that will be run 53 # The list of tests that will be run
49 windows_tests = ['unit_tests.exe', 54 windows_tests = ['unit_tests.exe',
55 'base_unittests.exe',
56 'automated_ui_tests.exe',
50 'ui_tests.exe', 57 'ui_tests.exe',
58 'installer_unittests.exe',
51 'ipc_tests.exe', 59 'ipc_tests.exe',
52 'net_perftests.exe', 60 'net_perftests.exe',
53 'net_unittests.exe', 61 'net_unittests.exe',
54 'plugin_tests.exe', 62 'plugin_tests.exe',
63 'startup_tests.exe',
55 'tab_switching_test.exe', 64 'tab_switching_test.exe',
56 'test_shell_tests.exe'] 65 'test_shell_tests.exe']
57 66
58 67
59 def IsWindows(): 68 def IsWindows():
60 """Checks if the current platform is Windows. 69 """Checks if the current platform is Windows.
61 """ 70 """
62 return sys.platform[:3] == 'win' 71 return sys.platform[:3] == 'win'
63 72
64 73
(...skipping 17 matching lines...) Expand all
82 Args: 91 Args:
83 revision: Revision number of the Chromium source tree. 92 revision: Revision number of the Chromium source tree.
84 src_path: Location of the Chromium source base. 93 src_path: Location of the Chromium source base.
85 tools_path: Location of the Visual Studio Team Tools. (Win32 only) 94 tools_path: Location of the Visual Studio Team Tools. (Win32 only)
86 """ 95 """
87 google.logging_utils.config_root() 96 google.logging_utils.config_root()
88 self.revision = revision 97 self.revision = revision
89 self.instrumented = False 98 self.instrumented = False
90 self.tools_path = tools_path 99 self.tools_path = tools_path
91 self.src_path = src_path 100 self.src_path = src_path
92 self._dir = None 101 self._dir = tempfile.mkdtemp()
93 102
94 103
95 def SetUp(self, binaries): 104 def SetUp(self, binaries):
96 """Set up the platform specific environment and instrument the binaries for 105 """Set up the platform specific environment and instrument the binaries for
97 coverage. 106 coverage.
98 107
99 This method sets up the environment, instruments all the compiled binaries 108 This method sets up the environment, instruments all the compiled binaries
100 and sets up the code coverage counters. 109 and sets up the code coverage counters.
101 110
102 Args: 111 Args:
103 binaries: List of binaries that need to be instrumented. 112 binaries: List of binaries that need to be instrumented.
104 113
105 Returns: 114 Returns:
106 Path of the file containing code coverage data on successful 115 True on success.
107 instrumentation. 116 False on error.
108 None on error.
109 """ 117 """
110 if self.instrumented: 118 if self.instrumented:
111 logging.error('Binaries already instrumented') 119 logging.error('Binaries already instrumented')
112 return None 120 return False
113 coverage_file = None
114 if IsWindows(): 121 if IsWindows():
115 # Stop all previous instance of VSPerfMon counters 122 # Stop all previous instance of VSPerfMon counters
116 counters_command = ('%s -shutdown' % 123 counters_command = ('%s -shutdown' %
117 (os.path.join(self.tools_path, 'vsperfcmd.exe'))) 124 (os.path.join(self.tools_path, 'vsperfcmd.exe')))
118 (retcode, output) = proc.RunCommandFull(counters_command, 125 (retcode, output) = proc.RunCommandFull(counters_command,
119 collect_output=True) 126 collect_output=True)
120 # TODO(niranjan): Add a check that to verify that the binaries were built 127 # TODO(niranjan): Add a check that to verify that the binaries were built
121 # using the /PROFILE linker flag. 128 # using the /PROFILE linker flag.
122 if self.tools_path == None: 129 if self.tools_path == None:
123 logging.error('Could not locate Visual Studio Team Server tools') 130 logging.error('Could not locate Visual Studio Team Server tools')
124 return None 131 return False
125 # Remove trailing slashes 132 # Remove trailing slashes
126 self.tools_path = self.tools_path.rstrip('\\') 133 self.tools_path = self.tools_path.rstrip('\\')
127 instrument_command = '%s /COVERAGE ' % (os.path.join(self.tools_path, 134 instrument_command = '%s /COVERAGE ' % (os.path.join(self.tools_path,
128 'vsinstr.exe')) 135 'vsinstr.exe'))
129 for binary in binaries: 136 for binary in binaries:
130 logging.info('binary = %s' % (binary)) 137 logging.info('binary = %s' % (binary))
131 logging.info('instrument_command = %s' % (instrument_command)) 138 logging.info('instrument_command = %s' % (instrument_command))
132 # Instrument each binary in the list 139 # Instrument each binary in the list
133 binary = os.path.join(self.src_path, 'chrome', 'Release', binary) 140 binary = os.path.join(self.src_path, 'chrome', 'Release', binary)
134 (retcode, output) = proc.RunCommandFull(instrument_command + binary, 141 (retcode, output) = proc.RunCommandFull(instrument_command + binary,
135 collect_output=True) 142 collect_output=True)
136 # Check if the file has been instrumented correctly. 143 # Check if the file has been instrumented correctly.
137 if output.pop().rfind('Successfully instrumented') == -1: 144 if output.pop().rfind('Successfully instrumented') == -1:
138 logging.error('Error instrumenting %s' % (binary)) 145 logging.error('Error instrumenting %s' % (binary))
139 return None 146 return False
140
141 # Generate the file name for the coverage results
142 self._dir = tempfile.mkdtemp()
143 coverage_file = os.path.join(self._dir, 'chrome_win32_%s.coverage' %
144 (self.revision))
145 logging.info('.coverage file: %s' % (coverage_file))
146
147 # After all the binaries have been instrumented, we start the counters.
148 counters_command = ('%s -start:coverage -output:%s' %
149 (os.path.join(self.tools_path, 'vsperfcmd.exe'),
150 coverage_file))
151 # Here we use subprocess.call() instead of the RunCommandFull because the
152 # VSPerfCmd spawns another process before terminating and this confuses
153 # the subprocess.Popen() used by RunCommandFull.
154 retcode = subprocess.call(counters_command)
155 # TODO(niranjan): Check whether the counters have been started
156 # successfully.
157
158 # We are now ready to run tests and measure code coverage. 147 # We are now ready to run tests and measure code coverage.
159 self.instrumented = True 148 self.instrumented = True
160 else: 149 return True
161 return None
162 return coverage_file
163 150
164 151
165 def TearDown(self): 152 def TearDown(self):
166 """Tear down method. 153 """Tear down method.
167 154
168 This method shuts down the counters, and cleans up all the intermediate 155 This method shuts down the counters, and cleans up all the intermediate
169 artifacts. 156 artifacts.
170 """ 157 """
171 if self.instrumented == False: 158 if self.instrumented == False:
172 return 159 return
(...skipping 10 matching lines...) Expand all
183 else: 170 else:
184 return 171 return
185 # Delete all the temp files and folders 172 # Delete all the temp files and folders
186 if self._dir != None: 173 if self._dir != None:
187 shutil.rmtree(self._dir, ignore_errors=True) 174 shutil.rmtree(self._dir, ignore_errors=True)
188 logging.info('Cleaned up temporary files and folders') 175 logging.info('Cleaned up temporary files and folders')
189 # Reset the instrumented flag. 176 # Reset the instrumented flag.
190 self.instrumented = False 177 self.instrumented = False
191 178
192 179
193 def Upload(self, coverage_file, upload_path, sym_path=None, src_root=None): 180 def RunTest(self, test):
181 """Run tests and collect the .coverage file
182
183 Args:
184 test: Path to the test to be run.
185
186 Returns:
187 Path of the intermediate .coverage file on success.
188 None on error.
189 """
190 # Generate the intermediate file name for the coverage results
191 testname = os.path.split(test)[1].strip('.exe')
192 coverage_file = os.path.join(self._dir, '%s_win32_%s.coverage' %
193 (testname, self.revision))
194 logging.info('.coverage file for test %s: %s' % (test, coverage_file))
195
196 # After all the binaries have been instrumented, we start the counters.
197 counters_command = ('%s -start:coverage -output:%s' %
198 (os.path.join(self.tools_path, 'vsperfcmd.exe'),
199 coverage_file))
200 # Here we use subprocess.call() instead of the RunCommandFull because the
201 # VSPerfCmd spawns another process before terminating and this confuses
202 # the subprocess.Popen() used by RunCommandFull.
203 retcode = subprocess.call(counters_command)
204
205 # Run the test binary
206 logging.info('Executing test %s: ' % test)
207 (retcode, output) = proc.RunCommandFull(test, collect_output=True)
208 if retcode != 0: # Return error if the tests fail
209 logging.error('One or more tests failed in %s.' % test)
210 return None
211
212 # Stop the counters
213 counters_command = ('%s -shutdown' %
214 (os.path.join(self.tools_path, 'vsperfcmd.exe')))
215 (retcode, output) = proc.RunCommandFull(counters_command,
216 collect_output=True)
217 logging.info('Counters shut down: %s' % (output))
218 # Return the intermediate .coverage file
219 return coverage_file
220
221
222 def Upload(self, list_coverage, upload_path, sym_path=None, src_root=None):
194 """Upload the results to the dashboard. 223 """Upload the results to the dashboard.
195 224
196 This method uploads the coverage data to a dashboard where it will be 225 This method uploads the coverage data to a dashboard where it will be
197 processed. On Windows, this method will first convert the .coverage file to 226 processed. On Windows, this method will first convert the .coverage file to
198 the lcov format. This method needs to be called before the TearDown method. 227 the lcov format. This method needs to be called before the TearDown method.
199 228
200 Args: 229 Args:
201 coverage_file: The coverage data file to upload. 230 list_coverage: The list of coverage data files to consoliate and upload.
202 upload_path: Destination where the coverage data will be processed. 231 upload_path: Destination where the coverage data will be processed.
203 sym_path: Symbol path for the build (Win32 only) 232 sym_path: Symbol path for the build (Win32 only)
204 src_root: Root folder of the source tree (Win32 only) 233 src_root: Root folder of the source tree (Win32 only)
205 234
206 Returns: 235 Returns:
207 True on success. 236 True on success.
208 False on failure. 237 False on failure.
209 """ 238 """
210 if IsWindows(): 239 if IsWindows():
211 # Stop counters 240 # Stop counters
212 counters_command = ('%s -shutdown' % 241 counters_command = ('%s -shutdown' %
213 (os.path.join(self.tools_path, 'vsperfcmd.exe'))) 242 (os.path.join(self.tools_path, 'vsperfcmd.exe')))
214 (retcode, output) = proc.RunCommandFull(counters_command, 243 (retcode, output) = proc.RunCommandFull(counters_command,
215 collect_output=True) 244 collect_output=True)
216 logging.info('Counters shut down: %s' % (output)) 245 logging.info('Counters shut down: %s' % (output))
217 # Convert the .coverage file to lcov format 246 lcov_file = os.path.join(upload_path, 'chrome_win32_%s.lcov' %
218 if self.tools_path == None: 247 (self.revision))
219 logging.error('Lcov converter tool not found') 248 lcov = open(lcov_file, 'w')
220 return False 249 for coverage_file in list_coverage:
221 self.tools_path = self.tools_path.rstrip('\\') 250
222 convert_command = ('%s -sym_path=%s -src_root=%s %s' % 251 # Convert the intermediate .coverage file to lcov format
223 (os.path.join(self.tools_path, 252 if self.tools_path == None:
224 'coverage_analyzer.exe'), 253 logging.error('Lcov converter tool not found')
225 sym_path, 254 return False
226 src_root, 255 self.tools_path = self.tools_path.rstrip('\\')
227 coverage_file)) 256 convert_command = ('%s -sym_path=%s -src_root=%s %s' %
228 (retcode, output) = proc.RunCommandFull(convert_command, 257 (os.path.join(self.tools_path,
229 collect_output=True) 258 'coverage_analyzer.exe'),
230 if output != 0: 259 sym_path,
231 logging.error('Conversion to LCOV failed. Exiting.') 260 src_root,
232 sys.exit(1) 261 coverage_file))
233 lcov_file = coverage_file + '.lcov' 262 (retcode, output) = proc.RunCommandFull(convert_command,
234 logging.info('Conversion to lcov complete') 263 collect_output=True)
235 shutil.copy(lcov_file, upload_path) 264 if output != 0:
265 logging.error('Conversion to LCOV failed. Exiting.')
266 sys.exit(1)
267 tmp_lcov_file = coverage_file + '.lcov'
268 logging.info('Conversion to lcov complete for %s' % (coverage_file))
269 # Now append this .lcov file to the cumulative lcov file
270 logging.info('Consolidating LCOV file: %s' % (tmp_lcov_file))
271 tmp_lcov = open(tmp_lcov_file, 'r')
272 lcov.write(tmp_lcov.read())
273 tmp_lcov.close()
274 lcov.close()
275 # Finally upload the LCOV file
236 logging.info('LCOV file uploaded to %s' % (upload_path)) 276 logging.info('LCOV file uploaded to %s' % (upload_path))
237 277
238 278
239 def main(): 279 def main():
240 # Command line parsing 280 # Command line parsing
241 parser = optparse.OptionParser() 281 parser = optparse.OptionParser()
242 # Path where the .coverage to .lcov converter tools are stored. 282 # Path where the .coverage to .lcov converter tools are stored.
243 parser.add_option('-t', 283 parser.add_option('-t',
244 '--tools_path', 284 '--tools_path',
245 dest='tools_path', 285 dest='tools_path',
(...skipping 26 matching lines...) Expand all
272 if options.src_root == None: 312 if options.src_root == None:
273 parser.error('Source root not specified') 313 parser.error('Source root not specified')
274 if options.upload_path == None: 314 if options.upload_path == None:
275 parser.error('Upload path not specified') 315 parser.error('Upload path not specified')
276 316
277 if IsWindows(): 317 if IsWindows():
278 # Initialize coverage 318 # Initialize coverage
279 cov = Coverage(options.revision, 319 cov = Coverage(options.revision,
280 options.src_root, 320 options.src_root,
281 options.tools_path) 321 options.tools_path)
322 list_coverage = []
282 # Instrument the binaries 323 # Instrument the binaries
283 coverage_file = cov.SetUp(windows_binaries) 324 if cov.SetUp(windows_binaries):
284 if coverage_file != None:
285 # Run all the tests 325 # Run all the tests
286 for test in windows_tests: 326 for test in windows_tests:
287 test = os.path.join(options.src_root, 'chrome', 'Release', test) 327 test = os.path.join(options.src_root, 'chrome', 'Release', test)
288 logging.info('Executing test %s: ' % test) 328 coverage = cov.RunTest(test)
289 (retcode, output) = proc.RunCommandFull(test, collect_output=True) 329 if coverage == None: # Indicate failure to the buildbots.
290 if retcode != 0: # Die if the tests fail 330 return 1
291 logging.error('One or more tests failed in %s. Exiting.' % test) 331 # Collect the intermediate file
292 sys.exit(retcode) 332 list_coverage.append(coverage)
293 else: 333 else:
294 logging.error('Error during instrumentation.') 334 logging.error('Error during instrumentation.')
295 sys.exit(1) 335 sys.exit(1)
296 336
297 cov.Upload(coverage_file, 337 cov.Upload(list_coverage,
298 options.upload_path, 338 options.upload_path,
299 os.path.join(options.src_root, 'chrome', 'Release'), 339 os.path.join(options.src_root, 'chrome', 'Release'),
300 options.src_root) 340 options.src_root)
301 cov.TearDown() 341 cov.TearDown()
302 342
303 343
304 if __name__ == '__main__': 344 if __name__ == '__main__':
305 sys.exit(main()) 345 sys.exit(main())
306 346
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698