diff options
author | Andras Becsi <andras.becsi@digia.com> | 2014-03-18 13:16:26 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-03-20 15:55:39 +0100 |
commit | 3f0f86b0caed75241fa71c95a5d73bc0164348c5 (patch) | |
tree | 92b9fb00f2e9e90b0be2262093876d4f43b6cd13 /chromium/tools/code_coverage | |
parent | e90d7c4b152c56919d963987e2503f9909a666d2 (diff) | |
download | qtwebengine-chromium-3f0f86b0caed75241fa71c95a5d73bc0164348c5.tar.gz |
Update to new stable branch 1750
This also includes an updated ninja and chromium dependencies
needed on Windows.
Change-Id: Icd597d80ed3fa4425933c9f1334c3c2e31291c42
Reviewed-by: Zoltan Arvai <zarvai@inf.u-szeged.hu>
Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
Diffstat (limited to 'chromium/tools/code_coverage')
-rwxr-xr-x | chromium/tools/code_coverage/coverage.py | 359 | ||||
-rwxr-xr-x | chromium/tools/code_coverage/coverage_posix.py | 1266 | ||||
-rwxr-xr-x | chromium/tools/code_coverage/coverage_posix_unittest.py | 142 | ||||
-rwxr-xr-x | chromium/tools/code_coverage/process_coverage.py | 413 |
4 files changed, 0 insertions, 2180 deletions
diff --git a/chromium/tools/code_coverage/coverage.py b/chromium/tools/code_coverage/coverage.py deleted file mode 100755 index a1496d7418d..00000000000 --- a/chromium/tools/code_coverage/coverage.py +++ /dev/null @@ -1,359 +0,0 @@ -#!/bin/env python -# Copyright (c) 2011 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - - -"""Module to setup and generate code coverage data - -This module first sets up the environment for code coverage, instruments the -binaries, runs the tests and collects the code coverage data. - - -Usage: - coverage.py --upload=<upload_location> - --revision=<revision_number> - --src_root=<root_of_source_tree> - [--tools_path=<tools_path>] -""" - -import logging -import optparse -import os -import shutil -import subprocess -import sys -import tempfile - -import google.logging_utils -import google.process_utils as proc - - -# The list of binaries that will be instrumented for code coverage -# TODO(niranjan): Re-enable instrumentation of chrome.exe and chrome.dll once we -# resolve the issue where vsinstr.exe is confused while reading symbols. -windows_binaries = [#'chrome.exe', - #'chrome.dll', - 'unit_tests.exe', - 'automated_ui_tests.exe', - 'installer_util_unittests.exe', - 'ipc_tests.exe', - 'memory_test.exe', - 'page_cycler_tests.exe', - 'perf_tests.exe', - 'reliability_tests.exe', - 'security_tests.dll', - 'startup_tests.exe', - 'tab_switching_test.exe', - 'test_shell.exe'] - -# The list of [tests, args] that will be run. -# Failing tests have been commented out. -# TODO(niranjan): Need to add layout tests that excercise the test shell. -windows_tests = [ - ['unit_tests.exe', ''], -# ['automated_ui_tests.exe', ''], - ['installer_util_unittests.exe', ''], - ['ipc_tests.exe', ''], - ['page_cycler_tests.exe', '--gtest_filter=*File --no-sandbox'], - ['reliability_tests.exe', '--no-sandbox'], - ['startup_tests.exe', '--no-sandbox'], - ['tab_switching_test.exe', '--no-sandbox'], - ] - - -def IsWindows(): - """Checks if the current platform is Windows. - """ - return sys.platform[:3] == 'win' - - -class Coverage(object): - """Class to set up and generate code coverage. - - This class contains methods that are useful to set up the environment for - code coverage. - - Attributes: - instrumented: A boolean indicating if all the binaries have been - instrumented. - """ - - def __init__(self, - revision, - src_path = None, - tools_path = None, - archive=None): - """Init method for the Coverage class. - - Args: - revision: Revision number of the Chromium source tree. - src_path: Location of the Chromium source base. - tools_path: Location of the Visual Studio Team Tools. (Win32 only) - archive: Archive location for the intermediate .coverage results. - """ - google.logging_utils.config_root() - self.revision = revision - self.instrumented = False - self.tools_path = tools_path - self.src_path = src_path - self._dir = tempfile.mkdtemp() - self._archive = archive - - def SetUp(self, binaries): - """Set up the platform specific environment and instrument the binaries for - coverage. - - This method sets up the environment, instruments all the compiled binaries - and sets up the code coverage counters. - - Args: - binaries: List of binaries that need to be instrumented. - - Returns: - True on success. - False on error. - """ - if self.instrumented: - logging.error('Binaries already instrumented') - return False - if IsWindows(): - # Stop all previous instance of VSPerfMon counters - counters_command = ('%s -shutdown' % - (os.path.join(self.tools_path, 'vsperfcmd.exe'))) - (retcode, output) = proc.RunCommandFull(counters_command, - collect_output=True) - # TODO(niranjan): Add a check that to verify that the binaries were built - # using the /PROFILE linker flag. - if self.tools_path == None: - logging.error('Could not locate Visual Studio Team Server tools') - return False - # Remove trailing slashes - self.tools_path = self.tools_path.rstrip('\\') - # Add this to the env PATH. - os.environ['PATH'] = os.environ['PATH'] + ';' + self.tools_path - instrument_command = '%s /COVERAGE ' % (os.path.join(self.tools_path, - 'vsinstr.exe')) - for binary in binaries: - logging.info('binary = %s' % (binary)) - logging.info('instrument_command = %s' % (instrument_command)) - # Instrument each binary in the list - binary = os.path.join(self.src_path, 'chrome', 'Release', binary) - (retcode, output) = proc.RunCommandFull(instrument_command + binary, - collect_output=True) - # Check if the file has been instrumented correctly. - if output.pop().rfind('Successfully instrumented') == -1: - logging.error('Error instrumenting %s' % (binary)) - return False - # We are now ready to run tests and measure code coverage. - self.instrumented = True - return True - - def TearDown(self): - """Tear down method. - - This method shuts down the counters, and cleans up all the intermediate - artifacts. - """ - if self.instrumented == False: - return - - if IsWindows(): - # Stop counters - counters_command = ('%s -shutdown' % - (os.path.join(self.tools_path, 'vsperfcmd.exe'))) - (retcode, output) = proc.RunCommandFull(counters_command, - collect_output=True) - logging.info('Counters shut down: %s' % (output)) - # TODO(niranjan): Revert the instrumented binaries to their original - # versions. - else: - return - if self._archive: - shutil.copytree(self._dir, os.path.join(self._archive, self.revision)) - logging.info('Archived the .coverage files') - # Delete all the temp files and folders - if self._dir != None: - shutil.rmtree(self._dir, ignore_errors=True) - logging.info('Cleaned up temporary files and folders') - # Reset the instrumented flag. - self.instrumented = False - - def RunTest(self, src_root, test): - """Run tests and collect the .coverage file - - Args: - src_root: Path to the root of the source. - test: Path to the test to be run. - - Returns: - Path of the intermediate .coverage file on success. - None on error. - """ - # Generate the intermediate file name for the coverage results - test_name = os.path.split(test[0])[1].strip('.exe') - # test_command = binary + args - test_command = '%s %s' % (os.path.join(src_root, - 'chrome', - 'Release', - test[0]), - test[1]) - - coverage_file = os.path.join(self._dir, '%s_win32_%s.coverage' % - (test_name, self.revision)) - logging.info('.coverage file for test %s: %s' % (test_name, coverage_file)) - - # After all the binaries have been instrumented, we start the counters. - counters_command = ('%s -start:coverage -output:%s' % - (os.path.join(self.tools_path, 'vsperfcmd.exe'), - coverage_file)) - # Here we use subprocess.call() instead of the RunCommandFull because the - # VSPerfCmd spawns another process before terminating and this confuses - # the subprocess.Popen() used by RunCommandFull. - retcode = subprocess.call(counters_command) - - # Run the test binary - logging.info('Executing test %s: ' % test_command) - (retcode, output) = proc.RunCommandFull(test_command, collect_output=True) - if retcode != 0: # Return error if the tests fail - logging.error('One or more tests failed in %s.' % test_command) - return None - - # Stop the counters - counters_command = ('%s -shutdown' % - (os.path.join(self.tools_path, 'vsperfcmd.exe'))) - (retcode, output) = proc.RunCommandFull(counters_command, - collect_output=True) - logging.info('Counters shut down: %s' % (output)) - # Return the intermediate .coverage file - return coverage_file - - def Upload(self, list_coverage, upload_path, sym_path=None, src_root=None): - """Upload the results to the dashboard. - - This method uploads the coverage data to a dashboard where it will be - processed. On Windows, this method will first convert the .coverage file to - the lcov format. This method needs to be called before the TearDown method. - - Args: - list_coverage: The list of coverage data files to consoliate and upload. - upload_path: Destination where the coverage data will be processed. - sym_path: Symbol path for the build (Win32 only) - src_root: Root folder of the source tree (Win32 only) - - Returns: - True on success. - False on failure. - """ - if upload_path == None: - logging.info('Upload path not specified. Will not convert to LCOV') - return True - - if IsWindows(): - # Stop counters - counters_command = ('%s -shutdown' % - (os.path.join(self.tools_path, 'vsperfcmd.exe'))) - (retcode, output) = proc.RunCommandFull(counters_command, - collect_output=True) - logging.info('Counters shut down: %s' % (output)) - lcov_file = os.path.join(upload_path, 'chrome_win32_%s.lcov' % - (self.revision)) - lcov = open(lcov_file, 'w') - for coverage_file in list_coverage: - # Convert the intermediate .coverage file to lcov format - if self.tools_path == None: - logging.error('Lcov converter tool not found') - return False - self.tools_path = self.tools_path.rstrip('\\') - convert_command = ('%s -sym_path=%s -src_root=%s %s' % - (os.path.join(self.tools_path, - 'coverage_analyzer.exe'), - sym_path, - src_root, - coverage_file)) - (retcode, output) = proc.RunCommandFull(convert_command, - collect_output=True) - # TODO(niranjan): Fix this to check for the correct return code. -# if output != 0: -# logging.error('Conversion to LCOV failed. Exiting.') - tmp_lcov_file = coverage_file + '.lcov' - logging.info('Conversion to lcov complete for %s' % (coverage_file)) - # Now append this .lcov file to the cumulative lcov file - logging.info('Consolidating LCOV file: %s' % (tmp_lcov_file)) - tmp_lcov = open(tmp_lcov_file, 'r') - lcov.write(tmp_lcov.read()) - tmp_lcov.close() - lcov.close() - logging.info('LCOV file uploaded to %s' % (upload_path)) - - -def main(): - # Command line parsing - parser = optparse.OptionParser() - # Path where the .coverage to .lcov converter tools are stored. - parser.add_option('-t', - '--tools_path', - dest='tools_path', - default=None, - help='Location of the coverage tools (windows only)') - parser.add_option('-u', - '--upload', - dest='upload_path', - default=None, - help='Location where the results should be uploaded') - # We need the revision number so that we can generate the output file of the - # format chrome_<platform>_<revision>.lcov - parser.add_option('-r', - '--revision', - dest='revision', - default=None, - help='Revision number of the Chromium source repo') - # Root of the source tree. Needed for converting the generated .coverage file - # on Windows to the open source lcov format. - parser.add_option('-s', - '--src_root', - dest='src_root', - default=None, - help='Root of the source repository') - parser.add_option('-a', - '--archive', - dest='archive', - default=None, - help='Archive location of the intermediate .coverage data') - - (options, args) = parser.parse_args() - - if options.revision == None: - parser.error('Revision number not specified') - if options.src_root == None: - parser.error('Source root not specified') - - if IsWindows(): - # Initialize coverage - cov = Coverage(options.revision, - options.src_root, - options.tools_path, - options.archive) - list_coverage = [] - # Instrument the binaries - if cov.SetUp(windows_binaries): - # Run all the tests - for test in windows_tests: - coverage = cov.RunTest(options.src_root, test) - if coverage == None: # Indicate failure to the buildbots. - return 1 - # Collect the intermediate file - list_coverage.append(coverage) - else: - logging.error('Error during instrumentation.') - sys.exit(1) - - cov.Upload(list_coverage, - options.upload_path, - os.path.join(options.src_root, 'chrome', 'Release'), - options.src_root) - cov.TearDown() - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/chromium/tools/code_coverage/coverage_posix.py b/chromium/tools/code_coverage/coverage_posix.py deleted file mode 100755 index f4fa56caa10..00000000000 --- a/chromium/tools/code_coverage/coverage_posix.py +++ /dev/null @@ -1,1266 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Generate and process code coverage. - -TODO(jrg): rename this from coverage_posix.py to coverage_all.py! - -Written for and tested on Mac, Linux, and Windows. To use this script -to generate coverage numbers, please run from within a gyp-generated -project. - -All platforms, to set up coverage: - cd ...../chromium ; src/tools/gyp/gyp_dogfood -Dcoverage=1 src/build/all.gyp - -Run coverage on... -Mac: - ( cd src/chrome ; xcodebuild -configuration Debug -target coverage ) -Linux: - ( cd src/chrome ; hammer coverage ) - # In particular, don't try and run 'coverage' from src/build - - ---directory=DIR: specify directory that contains gcda files, and where - a "coverage" directory will be created containing the output html. - Example name: ..../chromium/src/xcodebuild/Debug. - If not specified (e.g. buildbot) we will try and figure it out based on - other options (e.g. --target and --build-dir; see below). - ---genhtml: generate html output. If not specified only lcov is generated. - ---all_unittests: if present, run all files named *_unittests that we - can find. - ---fast_test: make the tests run real fast (just for testing) - ---strict: if a test fails, we continue happily. --strict will cause - us to die immediately. - ---trim=False: by default we trim away tests known to be problematic on - specific platforms. If set to false we do NOT trim out tests. - ---xvfb=True: By default we use Xvfb to make sure DISPLAY is valid - (Linux only). if set to False, do not use Xvfb. TODO(jrg): convert - this script from the compile stage of a builder to a - RunPythonCommandInBuildDir() command to avoid the need for this - step. - ---timeout=SECS: if a subprocess doesn't have output within SECS, - assume it's a hang. Kill it and give up. - ---bundles=BUNDLEFILE: a file containing a python list of coverage - bundles to be eval'd. Example contents of the bundlefile: - ['../base/base.gyp:base_unittests'] - This is used as part of the coverage bot. - If no other bundlefile-finding args are used (--target, - --build-dir), this is assumed to be an absolute path. - If those args are used, find BUNDLEFILE in a way consistent with - other scripts launched by buildbot. Example of another script - launched by buildbot: - http://src.chromium.org/viewvc/chrome/trunk/tools/buildbot/scripts/slave/runtest.py - ---target=NAME: specify the build target (e.g. 'Debug' or 'Release'). - This is used by buildbot scripts to help us find the output directory. - Must be used with --build-dir. - ---build-dir=DIR: According to buildbot comments, this is the name of - the directory within the buildbot working directory in which the - solution, Debug, and Release directories are found. - It's usually "src/build", but on mac it's $DIR/../xcodebuild and on - Linux it's $DIR/out. - This is used by buildbot scripts to help us find the output directory. - Must be used with --target. - ---no_exclusions: Do NOT use the exclusion list. This script keeps a - list of tests known to be problematic under coverage. For example, - ProcessUtilTest.SpawnChild will crash inside __gcov_fork() when - using the MacOS 10.6 SDK. Use of --no_exclusions prevents the use - of this exclusion list. - ---dont-clear-coverage-data: Normally we clear coverage data from - previous runs. If this arg is used we do NOT clear the coverage - data. - -Strings after all options are considered tests to run. Test names -have all text before a ':' stripped to help with gyp compatibility. -For example, ../base/base.gyp:base_unittests is interpreted as a test -named "base_unittests". -""" - -import glob -import logging -import optparse -import os -import Queue -import re -import shutil -import signal -import subprocess -import sys -import tempfile -import threading -import time -import traceback - -"""Global list of child PIDs to kill when we die.""" -gChildPIDs = [] - -"""Exclusion list. Format is - { platform: { testname: (exclusion1, exclusion2, ... ), ... } } - - Platform is a match for sys.platform and can be a list. - Matching code does an 'if sys.platform in (the key):'. - Similarly, matching does an 'if testname in thefulltestname:' - - The Chromium convention has traditionally been to place the - exclusion list in a distinct file. Unlike valgrind (which has - frequent changes when things break and are fixed), the expectation - here is that exclusions remain relatively constant (e.g. OS bugs). - If that changes, revisit the decision to place inclusions in this - script. - - Details: - ProcessUtilTest.SpawnChild: chokes in __gcov_fork on 10.6 - IPCFuzzingTest.MsgBadPayloadArgs: ditto - PanelBrowserNavigatorTest.NavigateFromCrashedPanel: Fails on coverage bot. - WebGLConformanceTests.conformance_attribs_gl_enable_vertex_attrib: Fails - with timeout (45000 ms) exceeded error. crbug.com/143248 - WebGLConformanceTests.conformance_attribs_gl_disabled_vertex_attrib: - ditto. - WebGLConformanceTests.conformance_attribs_gl_vertex_attrib_zero_issues: - ditto. - WebGLConformanceTests.conformance_attribs_gl_vertex_attrib: ditto. - WebGLConformanceTests.conformance_attribs_gl_vertexattribpointer_offsets: - ditto. - WebGLConformanceTests.conformance_attribs_gl_vertexattribpointer: ditto. - WebGLConformanceTests.conformance_buffers_buffer_bind_test: After - disabling WebGLConformanceTests specified above, this test fails when run - on local machine. - WebGLConformanceTests.conformance_buffers_buffer_data_array_buffer: ditto. - WebGLConformanceTests.conformance_buffers_index_validation_copies_indices: - ditto. - WebGLConformanceTests. - conformance_buffers_index_validation_crash_with_buffer_sub_data: ditto. - WebGLConformanceTests. - conformance_buffers_index_validation_verifies_too_many_indices: ditto. - WebGLConformanceTests. - conformance_buffers_index_validation_with_resized_buffer: ditto. - WebGLConformanceTests.conformance_canvas_buffer_offscreen_test: ditto. - WebGLConformanceTests.conformance_canvas_buffer_preserve_test: ditto. - WebGLConformanceTests.conformance_canvas_canvas_test: ditto. - WebGLConformanceTests.conformance_canvas_canvas_zero_size: ditto. - WebGLConformanceTests. - conformance_canvas_drawingbuffer_static_canvas_test: ditto. - WebGLConformanceTests.conformance_canvas_drawingbuffer_test: ditto. - PageCycler*.*: Fails on coverage bot with "Missing test directory - /....../slave/coverage-dbg-linux/build/src/data/page_cycler/moz" error. - *FrameRateCompositingTest.*: Fails with - "FATAL:chrome_content_browser_client.cc(893)] Check failed: - command_line->HasSwitch(switches::kEnableStatsTable)." - *FrameRateNoVsyncCanvasInternalTest.*: ditto. - *FrameRateGpuCanvasInternalTest.*: ditto. - IndexedDBTest.Perf: Fails with 'Timeout reached in WaitUntilCookieValue' - error. - TwoClientPasswordsSyncTest.DeleteAll: Fails on coverage bot. - MigrationTwoClientTest.MigrationHellWithoutNigori: Fails with timeout - (45000 ms) exceeded error. - TwoClientSessionsSyncTest.DeleteActiveSession: ditto. - MultipleClientSessionsSyncTest.EncryptedAndChanged: ditto. - MigrationSingleClientTest.AllTypesIndividuallyTriggerNotification: ditto. - *OldPanelResizeBrowserTest.*: crbug.com/143247 - *OldPanelDragBrowserTest.*: ditto. - *OldPanelBrowserTest.*: ditto. - *OldPanelAndDesktopNotificationTest.*: ditto. - *OldDockedPanelBrowserTest.*: ditto. - *OldDetachedPanelBrowserTest.*: ditto. - PanelDragBrowserTest.AttachWithSqueeze: ditto. - *PanelBrowserTest.*: ditto. - *DockedPanelBrowserTest.*: ditto. - *DetachedPanelBrowserTest.*: ditto. - AutomatedUITest.TheOneAndOnlyTest: crbug.com/143419 - AutomatedUITestBase.DragOut: ditto - -""" -gTestExclusions = { - 'darwin2': { 'base_unittests': ('ProcessUtilTest.SpawnChild',), - 'ipc_tests': ('IPCFuzzingTest.MsgBadPayloadArgs',), }, - 'linux2': { - 'gpu_tests': - ('WebGLConformanceTests.conformance_attribs_gl_enable_vertex_attrib', - 'WebGLConformanceTests.' - 'conformance_attribs_gl_disabled_vertex_attrib', - 'WebGLConformanceTests.' - 'conformance_attribs_gl_vertex_attrib_zero_issues', - 'WebGLConformanceTests.conformance_attribs_gl_vertex_attrib', - 'WebGLConformanceTests.' - 'conformance_attribs_gl_vertexattribpointer_offsets', - 'WebGLConformanceTests.conformance_attribs_gl_vertexattribpointer', - 'WebGLConformanceTests.conformance_buffers_buffer_bind_test', - 'WebGLConformanceTests.' - 'conformance_buffers_buffer_data_array_buffer', - 'WebGLConformanceTests.' - 'conformance_buffers_index_validation_copies_indices', - 'WebGLConformanceTests.' - 'conformance_buffers_index_validation_crash_with_buffer_sub_data', - 'WebGLConformanceTests.' - 'conformance_buffers_index_validation_verifies_too_many_indices', - 'WebGLConformanceTests.' - 'conformance_buffers_index_validation_with_resized_buffer', - 'WebGLConformanceTests.conformance_canvas_buffer_offscreen_test', - 'WebGLConformanceTests.conformance_canvas_buffer_preserve_test', - 'WebGLConformanceTests.conformance_canvas_canvas_test', - 'WebGLConformanceTests.conformance_canvas_canvas_zero_size', - 'WebGLConformanceTests.' - 'conformance_canvas_drawingbuffer_static_canvas_test', - 'WebGLConformanceTests.conformance_canvas_drawingbuffer_test',), - 'performance_ui_tests': - ('*PageCycler*.*', - '*FrameRateCompositingTest.*', - '*FrameRateNoVsyncCanvasInternalTest.*', - '*FrameRateGpuCanvasInternalTest.*', - 'IndexedDBTest.Perf',), - 'sync_integration_tests': - ('TwoClientPasswordsSyncTest.DeleteAll', - 'MigrationTwoClientTest.MigrationHellWithoutNigori', - 'TwoClientSessionsSyncTest.DeleteActiveSession', - 'MultipleClientSessionsSyncTest.EncryptedAndChanged', - 'MigrationSingleClientTest.' - 'AllTypesIndividuallyTriggerNotification',), - 'interactive_ui_tests': - ('*OldPanelResizeBrowserTest.*', - '*OldPanelDragBrowserTest.*', - '*OldPanelBrowserTest.*', - '*OldPanelAndDesktopNotificationTest.*', - '*OldDockedPanelBrowserTest.*', - '*OldDetachedPanelBrowserTest.*', - 'PanelDragBrowserTest.AttachWithSqueeze', - '*PanelBrowserTest.*', - '*DockedPanelBrowserTest.*', - '*DetachedPanelBrowserTest.*',), - 'automated_ui_tests': - ('AutomatedUITest.TheOneAndOnlyTest', - 'AutomatedUITestBase.DragOut',), }, -} - -"""Since random tests are failing/hanging on coverage bot, we are enabling - tests feature by feature. crbug.com/159748 -""" -gTestInclusions = { - 'linux2': { - 'browser_tests': - (# 'src/chrome/browser/downloads' - 'SavePageBrowserTest.*', - 'SavePageAsMHTMLBrowserTest.*', - 'DownloadQueryTest.*', - 'DownloadDangerPromptTest.*', - 'DownloadTest.*', - # 'src/chrome/browser/net' - 'CookiePolicyBrowserTest.*', - 'FtpBrowserTest.*', - 'LoadTimingObserverTest.*', - 'PredictorBrowserTest.*', - 'ProxyBrowserTest.*', - # 'src/chrome/browser/extensions' - 'Extension*.*', - 'WindowOpenPanelDisabledTest.*', - 'WindowOpenPanelTest.*', - 'WebstoreStandalone*.*', - 'CommandLineWebstoreInstall.*', - 'WebViewTest.*', - 'RequirementsCheckerBrowserTest.*', - 'ProcessManagementTest.*', - 'PlatformAppBrowserTest.*', - 'PlatformAppDevToolsBrowserTest.*', - 'LazyBackgroundPageApiTest.*', - 'IsolatedAppTest.*', - 'PanelMessagingTest.*', - 'GeolocationApiTest.*', - 'ClipboardApiTest.*', - 'ExecuteScriptApiTest.*', - 'CalculatorBrowserTest.*', - 'ChromeAppAPITest.*', - 'AppApiTest.*', - 'BlockedAppApiTest.*', - 'AppBackgroundPageApiTest.*', - 'WebNavigationApiTest.*', - 'UsbApiTest.*', - 'TabCaptureApiTest.*', - 'SystemInfo*.*', - 'SyncFileSystemApiTest.*', - 'SocketApiTest.*', - 'SerialApiTest.*', - 'RecordApiTest.*', - 'PushMessagingApiTest.*', - 'ProxySettingsApiTest.*', - 'ExperimentalApiTest.*', - 'OmniboxApiTest.*', - 'OffscreenTabsApiTest.*', - 'NotificationApiTest.*', - 'MediaGalleriesPrivateApiTest.*', - 'PlatformAppMediaGalleriesBrowserTest.*', - 'GetAuthTokenFunctionTest.*', - 'LaunchWebAuthFlowFunctionTest.*', - 'FileSystemApiTest.*', - 'ScriptBadgeApiTest.*', - 'PageAsBrowserActionApiTest.*', - 'PageActionApiTest.*', - 'BrowserActionApiTest.*', - 'DownloadExtensionTest.*', - 'DnsApiTest.*', - 'DeclarativeApiTest.*', - 'BluetoothApiTest.*', - 'AllUrlsApiTest.*', - # 'src/chrome/browser/nacl_host' - 'nacl_host.*', - # 'src/chrome/browser/automation' - 'AutomationMiscBrowserTest.*', - # 'src/chrome/browser/autofill' - 'FormStructureBrowserTest.*', - 'AutofillPopupViewBrowserTest.*', - 'AutofillTest.*', - # 'src/chrome/browser/autocomplete' - 'AutocompleteBrowserTest.*', - # 'src/chrome/browser/captive_portal' - 'CaptivePortalBrowserTest.*', - # 'src/chrome/browser/geolocation' - 'GeolocationAccessTokenStoreTest.*', - 'GeolocationBrowserTest.*', - # 'src/chrome/browser/nacl_host' - 'NaClGdbTest.*', - # 'src/chrome/browser/devtools' - 'DevToolsSanityTest.*', - 'DevToolsExtensionTest.*', - 'DevToolsExperimentalExtensionTest.*', - 'WorkerDevToolsSanityTest.*', - # 'src/chrome/browser/first_run' - 'FirstRunBrowserTest.*', - # 'src/chrome/browser/importer' - 'ToolbarImporterUtilsTest.*', - # 'src/chrome/browser/page_cycler' - 'PageCyclerBrowserTest.*', - 'PageCyclerCachedBrowserTest.*', - # 'src/chrome/browser/performance_monitor' - 'PerformanceMonitorBrowserTest.*', - 'PerformanceMonitorUncleanExitBrowserTest.*', - 'PerformanceMonitorSessionRestoreBrowserTest.*', - # 'src/chrome/browser/prerender' - 'PrerenderBrowserTest.*', - 'PrerenderBrowserTestWithNaCl.*', - 'PrerenderBrowserTestWithExtensions.*', - 'PrefetchBrowserTest.*', - 'PrefetchBrowserTestNoPrefetching.*', ), - }, -} - - -def TerminateSignalHandler(sig, stack): - """When killed, try and kill our child processes.""" - signal.signal(sig, signal.SIG_DFL) - for pid in gChildPIDs: - if 'kill' in os.__all__: # POSIX - os.kill(pid, sig) - else: - subprocess.call(['taskkill.exe', '/PID', str(pid)]) - sys.exit(0) - - -class RunTooLongException(Exception): - """Thrown when a command runs too long without output.""" - pass - -class BadUserInput(Exception): - """Thrown when arguments from the user are incorrectly formatted.""" - pass - - -class RunProgramThread(threading.Thread): - """A thread to run a subprocess. - - We want to print the output of our subprocess in real time, but also - want a timeout if there has been no output for a certain amount of - time. Normal techniques (e.g. loop in select()) aren't cross - platform enough. the function seems simple: "print output of child, kill it - if there is no output by timeout. But it was tricky to get this right - in a x-platform way (see warnings about deadlock on the python - subprocess doc page). - - """ - # Constants in our queue - PROGRESS = 0 - DONE = 1 - - def __init__(self, cmd): - super(RunProgramThread, self).__init__() - self._cmd = cmd - self._process = None - self._queue = Queue.Queue() - self._retcode = None - - def run(self): - if sys.platform in ('win32', 'cygwin'): - return self._run_windows() - else: - self._run_posix() - - def _run_windows(self): - # We need to save stdout to a temporary file because of a bug on the - # windows implementation of python which can deadlock while waiting - # for the IO to complete while writing to the PIPE and the pipe waiting - # on us and us waiting on the child process. - stdout_file = tempfile.TemporaryFile() - try: - self._process = subprocess.Popen(self._cmd, - stdin=subprocess.PIPE, - stdout=stdout_file, - stderr=subprocess.STDOUT) - gChildPIDs.append(self._process.pid) - try: - # To make sure that the buildbot don't kill us if we run too long - # without any activity on the console output, we look for progress in - # the length of the temporary file and we print what was accumulated so - # far to the output console to make the buildbot know we are making some - # progress. - previous_tell = 0 - # We will poll the process until we get a non-None return code. - self._retcode = None - while self._retcode is None: - self._retcode = self._process.poll() - current_tell = stdout_file.tell() - if current_tell > previous_tell: - # Report progress to our main thread so we don't timeout. - self._queue.put(RunProgramThread.PROGRESS) - # And print what was accumulated to far. - stdout_file.seek(previous_tell) - print stdout_file.read(current_tell - previous_tell), - previous_tell = current_tell - # Don't be selfish, let other threads do stuff while we wait for - # the process to complete. - time.sleep(0.5) - # OK, the child process has exited, let's print its output to our - # console to create debugging logs in case they get to be needed. - stdout_file.flush() - stdout_file.seek(previous_tell) - print stdout_file.read(stdout_file.tell() - previous_tell) - except IOError, e: - logging.exception('%s', e) - pass - finally: - stdout_file.close() - - # If we get here the process is done. - gChildPIDs.remove(self._process.pid) - self._queue.put(RunProgramThread.DONE) - - def _run_posix(self): - """No deadlock problem so use the simple answer. The windows solution - appears to add extra buffering which we don't want on other platforms.""" - self._process = subprocess.Popen(self._cmd, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - gChildPIDs.append(self._process.pid) - try: - while True: - line = self._process.stdout.readline() - if not line: # EOF - break - print line, - self._queue.put(RunProgramThread.PROGRESS, True) - except IOError: - pass - # If we get here the process is done. - gChildPIDs.remove(self._process.pid) - self._queue.put(RunProgramThread.DONE) - - def stop(self): - self.kill() - - def kill(self): - """Kill our running process if needed. Wait for kill to complete. - - Should be called in the PARENT thread; we do not self-kill. - Returns the return code of the process. - Safe to call even if the process is dead. - """ - if not self._process: - return self.retcode() - if 'kill' in os.__all__: # POSIX - os.kill(self._process.pid, signal.SIGKILL) - else: - subprocess.call(['taskkill.exe', '/PID', str(self._process.pid)]) - return self.retcode() - - def retcode(self): - """Return the return value of the subprocess. - - Waits for process to die but does NOT kill it explicitly. - """ - if self._retcode == None: # must be none, not 0/False - self._retcode = self._process.wait() - return self._retcode - - def RunUntilCompletion(self, timeout): - """Run thread until completion or timeout (in seconds). - - Start the thread. Let it run until completion, or until we've - spent TIMEOUT without seeing output. On timeout throw - RunTooLongException. - """ - self.start() - while True: - try: - x = self._queue.get(True, timeout) - if x == RunProgramThread.DONE: - return self.retcode() - except Queue.Empty, e: # timed out - logging.info('TIMEOUT (%d seconds exceeded with no output): killing' % - timeout) - self.kill() - raise RunTooLongException() - - -class Coverage(object): - """Doitall class for code coverage.""" - - def __init__(self, options, args): - super(Coverage, self).__init__() - logging.basicConfig(level=logging.DEBUG) - self.directory = options.directory - self.options = options - self.args = args - self.ConfirmDirectory() - self.directory_parent = os.path.dirname(self.directory) - self.output_directory = os.path.join(self.directory, 'coverage') - if not os.path.exists(self.output_directory): - os.mkdir(self.output_directory) - # The "final" lcov-format file - self.coverage_info_file = os.path.join(self.directory, 'coverage.info') - # If needed, an intermediate VSTS-format file - self.vsts_output = os.path.join(self.directory, 'coverage.vsts') - # Needed for Windows. - self.src_root = options.src_root - self.FindPrograms() - self.ConfirmPlatformAndPaths() - self.tests = [] # This can be a list of strings, lists or both. - self.xvfb_pid = 0 - self.test_files = [] # List of files with test specifications. - self.test_filters = {} # Mapping from testname->--gtest_filter arg. - logging.info('self.directory: ' + self.directory) - logging.info('self.directory_parent: ' + self.directory_parent) - - def FindInPath(self, program): - """Find program in our path. Return abs path to it, or None.""" - if not 'PATH' in os.environ: - logging.fatal('No PATH environment variable?') - sys.exit(1) - paths = os.environ['PATH'].split(os.pathsep) - for path in paths: - fullpath = os.path.join(path, program) - if os.path.exists(fullpath): - return fullpath - return None - - def FindPrograms(self): - """Find programs we may want to run.""" - if self.IsPosix(): - self.lcov_directory = os.path.join(sys.path[0], - '../../third_party/lcov/bin') - self.lcov = os.path.join(self.lcov_directory, 'lcov') - self.mcov = os.path.join(self.lcov_directory, 'mcov') - self.genhtml = os.path.join(self.lcov_directory, 'genhtml') - self.programs = [self.lcov, self.mcov, self.genhtml] - else: - # Hack to get the buildbot working. - os.environ['PATH'] += r';c:\coverage\coverage_analyzer' - os.environ['PATH'] += r';c:\coverage\performance_tools' - # (end hack) - commands = ['vsperfcmd.exe', 'vsinstr.exe', 'coverage_analyzer.exe'] - self.perf = self.FindInPath('vsperfcmd.exe') - self.instrument = self.FindInPath('vsinstr.exe') - self.analyzer = self.FindInPath('coverage_analyzer.exe') - if not self.perf or not self.instrument or not self.analyzer: - logging.fatal('Could not find Win performance commands.') - logging.fatal('Commands needed in PATH: ' + str(commands)) - sys.exit(1) - self.programs = [self.perf, self.instrument, self.analyzer] - - def PlatformBuildPrefix(self): - """Return a platform specific build directory prefix. - - This prefix is prepended to the build target (Debug, Release) to - identify output as relative to the build directory. - These values are specific to Chromium's use of gyp. - """ - if self.IsMac(): - return '../xcodebuild' - if self.IsWindows(): - return '' - else: # Linux - return '../out' # assumes make, unlike runtest.py - - def ConfirmDirectory(self): - """Confirm correctness of self.directory. - - If it exists, happiness. If not, try and figure it out in a - manner similar to FindBundlesFile(). The 'figure it out' case - happens with buildbot where the directory isn't specified - explicitly. - """ - if (not self.directory and - not (self.options.target and self.options.build_dir)): - logging.fatal('Must use --directory or (--target and --build-dir)') - sys.exit(1) - - if not self.directory: - self.directory = os.path.join(self.options.build_dir, - self.PlatformBuildPrefix(), - self.options.target) - - if os.path.exists(self.directory): - logging.info('Directory: ' + self.directory) - return - else: - logging.fatal('Directory ' + - self.directory + ' doesn\'t exist') - sys.exit(1) - - - def FindBundlesFile(self): - """Find the bundlesfile. - - The 'bundles' file can be either absolute path, or (if we are run - from buildbot) we need to find it based on other hints (--target, - --build-dir, etc). - """ - # If no bundle file, no problem! - if not self.options.bundles: - return - # If true, we're buildbot. Form a path. - # Else assume absolute. - if self.options.target and self.options.build_dir: - fullpath = os.path.join(self.options.build_dir, - self.PlatformBuildPrefix(), - self.options.target, - self.options.bundles) - self.options.bundles = fullpath - - if os.path.exists(self.options.bundles): - logging.info('BundlesFile: ' + self.options.bundles) - return - else: - logging.fatal('bundlefile ' + - self.options.bundles + ' doesn\'t exist') - sys.exit(1) - - - def FindTests(self): - """Find unit tests to run; set self.tests to this list. - - Assume all non-option items in the arg list are tests to be run. - """ - # Before we begin, find the bundles file if not an absolute path. - self.FindBundlesFile() - - # Small tests: can be run in the "chromium" directory. - # If asked, run all we can find. - if self.options.all_unittests: - self.tests += glob.glob(os.path.join(self.directory, '*_unittests')) - self.tests += glob.glob(os.path.join(self.directory, '*unit_tests')) - elif self.options.all_browsertests: - # Run all tests in browser_tests and content_browsertests. - self.tests += glob.glob(os.path.join(self.directory, 'browser_tests')) - self.tests += glob.glob(os.path.join(self.directory, - 'content_browsertests')) - - # Tests can come in as args directly, indirectly (through a file - # of test lists) or as a file of bundles. - all_testnames = self.args[:] # Copy since we might modify - - for test_file in self.options.test_files: - f = open(test_file) - for line in f: - line = re.sub(r"#.*$", "", line) - line = re.sub(r"\s*", "", line) - if re.match("\s*$"): - continue - all_testnames.append(line) - f.close() - - tests_from_bundles = None - if self.options.bundles: - try: - tests_from_bundles = eval(open(self.options.bundles).read()) - except IOError: - logging.fatal('IO error in bundle file ' + - self.options.bundles + ' (doesn\'t exist?)') - except (NameError, SyntaxError): - logging.fatal('Parse or syntax error in bundle file ' + - self.options.bundles) - if hasattr(tests_from_bundles, '__iter__'): - all_testnames += tests_from_bundles - else: - logging.fatal('Fatal error with bundle file; could not get list from' + - self.options.bundles) - sys.exit(1) - - # If told explicit tests, run those (after stripping the name as - # appropriate) - for testname in all_testnames: - mo = re.search(r"(.*)\[(.*)\]$", testname) - gtest_filter = None - if mo: - gtest_filter = mo.group(2) - testname = mo.group(1) - if ':' in testname: - testname = testname.split(':')[1] - # We need 'pyautolib' to run pyauto tests and 'pyautolib' itself is not an - # executable. So skip this test from adding into coverage_bundles.py. - if testname == 'pyautolib': - continue - self.tests += [os.path.join(self.directory, testname)] - if gtest_filter: - self.test_filters[testname] = gtest_filter - - # Add 'src/test/functional/pyauto_functional.py' to self.tests. - # This file with '-v --suite=CODE_COVERAGE' arguments runs all pyauto tests. - # Pyauto tests are failing randomly on coverage bots. So excluding them. - # self.tests += [['src/chrome/test/functional/pyauto_functional.py', - # '-v', - # '--suite=CODE_COVERAGE']] - - # Medium tests? - # Not sure all of these work yet (e.g. page_cycler_tests) - # self.tests += glob.glob(os.path.join(self.directory, '*_tests')) - - # If needed, append .exe to tests since vsinstr.exe likes it that - # way. - if self.IsWindows(): - for ind in range(len(self.tests)): - test = self.tests[ind] - test_exe = test + '.exe' - if not test.endswith('.exe') and os.path.exists(test_exe): - self.tests[ind] = test_exe - - def TrimTests(self): - """Trim specific tests for each platform.""" - if self.IsWindows(): - return - # TODO(jrg): remove when not needed - inclusion = ['unit_tests'] - keep = [] - for test in self.tests: - for i in inclusion: - if i in test: - keep.append(test) - self.tests = keep - logging.info('After trimming tests we have ' + ' '.join(self.tests)) - return - if self.IsLinux(): - # self.tests = filter(lambda t: t.endswith('base_unittests'), self.tests) - return - if self.IsMac(): - exclusion = ['automated_ui_tests'] - punted = [] - for test in self.tests: - for e in exclusion: - if test.endswith(e): - punted.append(test) - self.tests = filter(lambda t: t not in punted, self.tests) - if punted: - logging.info('Tests trimmed out: ' + str(punted)) - - def ConfirmPlatformAndPaths(self): - """Confirm OS and paths (e.g. lcov).""" - for program in self.programs: - if not os.path.exists(program): - logging.fatal('Program missing: ' + program) - sys.exit(1) - - def Run(self, cmdlist, ignore_error=False, ignore_retcode=None, - explanation=None): - """Run the command list; exit fatally on error. - - Args: - cmdlist: a list of commands (e.g. to pass to subprocess.call) - ignore_error: if True log an error; if False then exit. - ignore_retcode: if retcode is non-zero, exit unless we ignore. - - Returns: process return code. - Throws: RunTooLongException if the process does not produce output - within TIMEOUT seconds; timeout is specified as a command line - option to the Coverage class and is set on init. - """ - logging.info('Running ' + str(cmdlist)) - t = RunProgramThread(cmdlist) - retcode = t.RunUntilCompletion(self.options.timeout) - - if retcode: - if ignore_error or retcode == ignore_retcode: - logging.warning('COVERAGE: %s unhappy but errors ignored %s' % - (str(cmdlist), explanation or '')) - else: - logging.fatal('COVERAGE: %s failed; return code: %d' % - (str(cmdlist), retcode)) - sys.exit(retcode) - return retcode - - def IsPosix(self): - """Return True if we are POSIX.""" - return self.IsMac() or self.IsLinux() - - def IsMac(self): - return sys.platform == 'darwin' - - def IsLinux(self): - return sys.platform.startswith('linux') - - def IsWindows(self): - """Return True if we are Windows.""" - return sys.platform in ('win32', 'cygwin') - - def ClearData(self): - """Clear old gcda files and old coverage info files.""" - if self.options.dont_clear_coverage_data: - print 'Clearing of coverage data NOT performed.' - return - print 'Clearing coverage data from previous runs.' - if os.path.exists(self.coverage_info_file): - os.remove(self.coverage_info_file) - if self.IsPosix(): - subprocess.call([self.lcov, - '--directory', self.directory_parent, - '--zerocounters']) - shutil.rmtree(os.path.join(self.directory, 'coverage')) - if self.options.all_unittests: - if os.path.exists(os.path.join(self.directory, 'unittests_coverage')): - shutil.rmtree(os.path.join(self.directory, 'unittests_coverage')) - elif self.options.all_browsertests: - if os.path.exists(os.path.join(self.directory, - 'browsertests_coverage')): - shutil.rmtree(os.path.join(self.directory, 'browsertests_coverage')) - else: - if os.path.exists(os.path.join(self.directory, 'total_coverage')): - shutil.rmtree(os.path.join(self.directory, 'total_coverage')) - - def BeforeRunOneTest(self, testname): - """Do things before running each test.""" - if not self.IsWindows(): - return - # Stop old counters if needed - cmdlist = [self.perf, '-shutdown'] - self.Run(cmdlist, ignore_error=True) - # Instrument binaries - for fulltest in self.tests: - if os.path.exists(fulltest): - # See http://support.microsoft.com/kb/939818 for details on args - cmdlist = [self.instrument, '/d:ignorecverr', '/COVERAGE', fulltest] - self.Run(cmdlist, ignore_retcode=4, - explanation='OK with a multiple-instrument') - # Start new counters - cmdlist = [self.perf, '-start:coverage', '-output:' + self.vsts_output] - self.Run(cmdlist) - - def BeforeRunAllTests(self): - """Called right before we run all tests.""" - if self.IsLinux() and self.options.xvfb: - self.StartXvfb() - - def GtestFilter(self, fulltest, excl=None): - """Return a --gtest_filter=BLAH for this test. - - Args: - fulltest: full name of test executable - exclusions: the exclusions list. Only set in a unit test; - else uses gTestExclusions. - Returns: - String of the form '--gtest_filter=BLAH', or None. - """ - positive_gfilter_list = [] - negative_gfilter_list = [] - - # Exclude all flaky, failing, disabled and maybe tests; - # they don't count for code coverage. - negative_gfilter_list += ('*.FLAKY_*', '*.FAILS_*', - '*.DISABLED_*', '*.MAYBE_*') - - if not self.options.no_exclusions: - exclusions = excl or gTestExclusions - excldict = exclusions.get(sys.platform) - if excldict: - for test in excldict.keys(): - # example: if base_unittests in ../blah/blah/base_unittests.exe - if test in fulltest: - negative_gfilter_list += excldict[test] - - inclusions = gTestInclusions - include_dict = inclusions.get(sys.platform) - if include_dict: - for test in include_dict.keys(): - if test in fulltest: - positive_gfilter_list += include_dict[test] - - fulltest_basename = os.path.basename(fulltest) - if fulltest_basename in self.test_filters: - specific_test_filters = self.test_filters[fulltest_basename].split('-') - if len(specific_test_filters) > 2: - logging.error('Multiple "-" symbols in filter list: %s' % - self.test_filters[fulltest_basename]) - raise BadUserInput() - if len(specific_test_filters) == 2: - # Remove trailing ':' - specific_test_filters[0] = specific_test_filters[0][:-1] - - if specific_test_filters[0]: # Test for no positive filters. - positive_gfilter_list += specific_test_filters[0].split(':') - if len(specific_test_filters) > 1: - negative_gfilter_list += specific_test_filters[1].split(':') - - if not positive_gfilter_list and not negative_gfilter_list: - return None - - result = '--gtest_filter=' - if positive_gfilter_list: - result += ':'.join(positive_gfilter_list) - if negative_gfilter_list: - if positive_gfilter_list: result += ':' - result += '-' + ':'.join(negative_gfilter_list) - return result - - def RunTests(self): - """Run all unit tests and generate appropriate lcov files.""" - self.BeforeRunAllTests() - for fulltest in self.tests: - if type(fulltest) is str: - if not os.path.exists(fulltest): - logging.info(fulltest + ' does not exist') - if self.options.strict: - sys.exit(2) - else: - logging.info('%s path exists' % fulltest) - cmdlist = [fulltest, '--gtest_print_time'] - - # If asked, make this REAL fast for testing. - if self.options.fast_test: - logging.info('Running as a FAST test for testing') - # cmdlist.append('--gtest_filter=RenderWidgetHost*') - # cmdlist.append('--gtest_filter=CommandLine*') - cmdlist.append('--gtest_filter=C*') - - # Possibly add a test-specific --gtest_filter - filter = self.GtestFilter(fulltest) - if filter: - cmdlist.append(filter) - elif type(fulltest) is list: - cmdlist = fulltest - - self.BeforeRunOneTest(fulltest) - logging.info('Running test ' + str(cmdlist)) - try: - retcode = self.Run(cmdlist, ignore_retcode=True) - except SystemExit: # e.g. sys.exit() was called somewhere in here - raise - except: # can't "except WindowsError" since script runs on non-Windows - logging.info('EXCEPTION while running a unit test') - logging.info(traceback.format_exc()) - retcode = 999 - self.AfterRunOneTest(fulltest) - - if retcode: - logging.info('COVERAGE: test %s failed; return code: %d.' % - (fulltest, retcode)) - if self.options.strict: - logging.fatal('Test failure is fatal.') - sys.exit(retcode) - self.AfterRunAllTests() - - def AfterRunOneTest(self, testname): - """Do things right after running each test.""" - if not self.IsWindows(): - return - # Stop counters - cmdlist = [self.perf, '-shutdown'] - self.Run(cmdlist) - full_output = self.vsts_output + '.coverage' - shutil.move(full_output, self.vsts_output) - # generate lcov! - self.GenerateLcovWindows(testname) - - def AfterRunAllTests(self): - """Do things right after running ALL tests.""" - # On POSIX we can do it all at once without running out of memory. - # This contrasts with Windows where we must do it after each test. - if self.IsPosix(): - self.GenerateLcovPosix() - # Only on Linux do we have the Xvfb step. - if self.IsLinux() and self.options.xvfb: - self.StopXvfb() - - def StartXvfb(self): - """Start Xvfb and set an appropriate DISPLAY environment. Linux only. - - Copied from http://src.chromium.org/viewvc/chrome/trunk/tools/buildbot/ - scripts/slave/slave_utils.py?view=markup - with some simplifications (e.g. no need to use xdisplaycheck, save - pid in var not file, etc) - """ - logging.info('Xvfb: starting') - proc = subprocess.Popen(["Xvfb", ":9", "-screen", "0", "1024x768x24", - "-ac"], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - self.xvfb_pid = proc.pid - if not self.xvfb_pid: - logging.info('Could not start Xvfb') - return - os.environ['DISPLAY'] = ":9" - # Now confirm, giving a chance for it to start if needed. - logging.info('Xvfb: confirming') - for test in range(10): - proc = subprocess.Popen('xdpyinfo >/dev/null', shell=True) - pid, retcode = os.waitpid(proc.pid, 0) - if retcode == 0: - break - time.sleep(0.5) - if retcode != 0: - logging.info('Warning: could not confirm Xvfb happiness') - else: - logging.info('Xvfb: OK') - - def StopXvfb(self): - """Stop Xvfb if needed. Linux only.""" - if self.xvfb_pid: - logging.info('Xvfb: killing') - try: - os.kill(self.xvfb_pid, signal.SIGKILL) - except: - pass - del os.environ['DISPLAY'] - self.xvfb_pid = 0 - - def CopyCoverageFileToDestination(self, coverage_folder): - coverage_dir = os.path.join(self.directory, coverage_folder) - if not os.path.exists(coverage_dir): - os.makedirs(coverage_dir) - shutil.copyfile(self.coverage_info_file, os.path.join(coverage_dir, - 'coverage.info')) - - def GenerateLcovPosix(self): - """Convert profile data to lcov on Mac or Linux.""" - start_dir = os.getcwd() - logging.info('GenerateLcovPosix: start_dir=' + start_dir) - if self.IsLinux(): - # With Linux/make (e.g. the coverage_run target), the current - # directory for this command is .../build/src/chrome but we need - # to be in .../build/src for the relative path of source files - # to be correct. However, when run from buildbot, the current - # directory is .../build. Accommodate. - # On Mac source files are compiled with abs paths so this isn't - # a problem. - # This is a bit of a hack. The best answer is to require this - # script be run in a specific directory for all cases (from - # Makefile or from buildbot). - if start_dir.endswith('chrome'): - logging.info('coverage_posix.py: doing a "cd .." ' - 'to accomodate Linux/make PWD') - os.chdir('..') - elif start_dir.endswith('build'): - logging.info('coverage_posix.py: doing a "cd src" ' - 'to accomodate buildbot PWD') - os.chdir('src') - else: - logging.info('coverage_posix.py: NOT changing directory.') - elif self.IsMac(): - pass - - command = [self.mcov, - '--directory', - os.path.join(start_dir, self.directory_parent), - '--output', - os.path.join(start_dir, self.coverage_info_file)] - logging.info('Assembly command: ' + ' '.join(command)) - retcode = subprocess.call(command) - if retcode: - logging.fatal('COVERAGE: %s failed; return code: %d' % - (command[0], retcode)) - if self.options.strict: - sys.exit(retcode) - if self.IsLinux(): - os.chdir(start_dir) - - # Copy the unittests coverage information to a different folder. - if self.options.all_unittests: - self.CopyCoverageFileToDestination('unittests_coverage') - elif self.options.all_browsertests: - # Save browsertests only coverage information. - self.CopyCoverageFileToDestination('browsertests_coverage') - else: - # Save the overall coverage information. - self.CopyCoverageFileToDestination('total_coverage') - - if not os.path.exists(self.coverage_info_file): - logging.fatal('%s was not created. Coverage run failed.' % - self.coverage_info_file) - sys.exit(1) - - def GenerateLcovWindows(self, testname=None): - """Convert VSTS format to lcov. Appends coverage data to sum file.""" - lcov_file = self.vsts_output + '.lcov' - if os.path.exists(lcov_file): - os.remove(lcov_file) - # generates the file (self.vsts_output + ".lcov") - - cmdlist = [self.analyzer, - '-sym_path=' + self.directory, - '-src_root=' + self.src_root, - '-noxml', - self.vsts_output] - self.Run(cmdlist) - if not os.path.exists(lcov_file): - logging.fatal('Output file %s not created' % lcov_file) - sys.exit(1) - logging.info('Appending lcov for test %s to %s' % - (testname, self.coverage_info_file)) - size_before = 0 - if os.path.exists(self.coverage_info_file): - size_before = os.stat(self.coverage_info_file).st_size - src = open(lcov_file, 'r') - dst = open(self.coverage_info_file, 'a') - dst.write(src.read()) - src.close() - dst.close() - size_after = os.stat(self.coverage_info_file).st_size - logging.info('Lcov file growth for %s: %d --> %d' % - (self.coverage_info_file, size_before, size_after)) - - def GenerateHtml(self): - """Convert lcov to html.""" - # TODO(jrg): This isn't happy when run with unit_tests since V8 has a - # different "base" so V8 includes can't be found in ".". Fix. - command = [self.genhtml, - self.coverage_info_file, - '--output-directory', - self.output_directory] - print >>sys.stderr, 'html generation command: ' + ' '.join(command) - retcode = subprocess.call(command) - if retcode: - logging.fatal('COVERAGE: %s failed; return code: %d' % - (command[0], retcode)) - if self.options.strict: - sys.exit(retcode) - -def CoverageOptionParser(): - """Return an optparse.OptionParser() suitable for Coverage object creation.""" - parser = optparse.OptionParser() - parser.add_option('-d', - '--directory', - dest='directory', - default=None, - help='Directory of unit test files') - parser.add_option('-a', - '--all_unittests', - dest='all_unittests', - default=False, - help='Run all tests we can find (*_unittests)') - parser.add_option('-b', - '--all_browsertests', - dest='all_browsertests', - default=False, - help='Run all tests in browser_tests ' - 'and content_browsertests') - parser.add_option('-g', - '--genhtml', - dest='genhtml', - default=False, - help='Generate html from lcov output') - parser.add_option('-f', - '--fast_test', - dest='fast_test', - default=False, - help='Make the tests run REAL fast by doing little.') - parser.add_option('-s', - '--strict', - dest='strict', - default=False, - help='Be strict and die on test failure.') - parser.add_option('-S', - '--src_root', - dest='src_root', - default='.', - help='Source root (only used on Windows)') - parser.add_option('-t', - '--trim', - dest='trim', - default=True, - help='Trim out tests? Default True.') - parser.add_option('-x', - '--xvfb', - dest='xvfb', - default=True, - help='Use Xvfb for tests? Default True.') - parser.add_option('-T', - '--timeout', - dest='timeout', - default=5.0 * 60.0, - type="int", - help='Timeout before bailing if a subprocess has no output.' - ' Default is 5min (Buildbot is 10min.)') - parser.add_option('-B', - '--bundles', - dest='bundles', - default=None, - help='Filename of bundles for coverage.') - parser.add_option('--build-dir', - dest='build_dir', - default=None, - help=('Working directory for buildbot build.' - 'used for finding bundlefile.')) - parser.add_option('--target', - dest='target', - default=None, - help=('Buildbot build target; ' - 'used for finding bundlefile (e.g. Debug)')) - parser.add_option('--no_exclusions', - dest='no_exclusions', - default=None, - help=('Disable the exclusion list.')) - parser.add_option('--dont-clear-coverage-data', - dest='dont_clear_coverage_data', - default=False, - action='store_true', - help=('Turn off clearing of cov data from a prev run')) - parser.add_option('-F', - '--test-file', - dest="test_files", - default=[], - action='append', - help=('Specify a file from which tests to be run will ' + - 'be extracted')) - return parser - - -def main(): - # Print out the args to help someone do it by hand if needed - print >>sys.stderr, sys.argv - - # Try and clean up nice if we're killed by buildbot, Ctrl-C, ... - signal.signal(signal.SIGINT, TerminateSignalHandler) - signal.signal(signal.SIGTERM, TerminateSignalHandler) - - parser = CoverageOptionParser() - (options, args) = parser.parse_args() - if options.all_unittests and options.all_browsertests: - print 'Error! Can not have all_unittests and all_browsertests together!' - sys.exit(1) - coverage = Coverage(options, args) - coverage.ClearData() - coverage.FindTests() - if options.trim: - coverage.TrimTests() - coverage.RunTests() - if options.genhtml: - coverage.GenerateHtml() - return 0 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/chromium/tools/code_coverage/coverage_posix_unittest.py b/chromium/tools/code_coverage/coverage_posix_unittest.py deleted file mode 100755 index 3164cd3359a..00000000000 --- a/chromium/tools/code_coverage/coverage_posix_unittest.py +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2010 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Unit tests for coverage_posix.py. - -Run a single test with a command such as: - ./coverage_posix_unittest.py CoveragePosixTest.testFindTestsAsArgs - -Waring that running a single test like that may interfere with the arg -parsing tests, since coverage_posix.py uses optparse.OptionParser() -which references globals. -""" - -import coverage_posix as coverage -import os -import sys -import tempfile -import unittest - -class CoveragePosixTest(unittest.TestCase): - - - def setUp(self): - self.parseArgs() - self.sample_test_names = ['zippy_tests', '../base/base.gyp:base_unittests'] - - def confirmSampleTestsArePresent(self, tests): - """Confirm the tests in self.sample_test_names are in some form in 'tests'. - - The Coverage object can munge them (e.g. add .exe to the end as needed. - Helper function for arg parsing, bundle file tests. - - Args: - tests: the parsed tests from a Coverage object. - """ - for simple_test_name in ('zippy_tests', 'base_unittests'): - found = False - for item in tests: - if simple_test_name in item: - found = True - break - self.assertTrue(found) - for not_test_name in ('kablammo', 'not_a_unittest'): - found = False - for item in tests: - if not_test_name in item: - found = True - break - self.assertFalse(found) - - def parseArgs(self): - """Setup and process arg parsing.""" - self.parser = coverage.CoverageOptionParser() - (self.options, self.args) = self.parser.parse_args() - self.options.directory = '.' - - def testSanity(self): - """Sanity check we're able to actually run the tests. - - Simply creating a Coverage instance checks a few things (e.g. on - Windows that the coverage tools can be found).""" - c = coverage.Coverage(self.options, self.args) - - def testRunBasicProcess(self): - """Test a simple run of a subprocess.""" - c = coverage.Coverage(self.options, self.args) - for code in range(2): - retcode = c.Run([sys.executable, '-u', '-c', - 'import sys; sys.exit(%d)' % code], - ignore_error=True) - self.assertEqual(code, retcode) - - def testRunSlowProcess(self): - """Test program which prints slowly but doesn't hit our timeout. - - Overall runtime is longer than the timeout but output lines - trickle in keeping things alive. - """ - self.options.timeout = 2.5 - c = coverage.Coverage(self.options, self.args) - slowscript = ('import sys, time\n' - 'for x in range(10):\n' - ' time.sleep(0.5)\n' - ' print "hi mom"\n' - 'sys.exit(0)\n') - retcode = c.Run([sys.executable, '-u', '-c', slowscript]) - self.assertEqual(0, retcode) - - def testRunExcessivelySlowProcess(self): - """Test program which DOES hit our timeout. - - Initial lines should print but quickly it takes too long and - should be killed. - """ - self.options.timeout = 2.5 - c = coverage.Coverage(self.options, self.args) - slowscript = ('import time\n' - 'for x in range(1,10):\n' - ' print "sleeping for %d" % x\n' - ' time.sleep(x)\n') - self.assertRaises(Exception, - c.Run, - [sys.executable, '-u', '-c', slowscript]) - - def testFindTestsAsArgs(self): - """Test finding of tests passed as args.""" - self.args += '--' - self.args += self.sample_test_names - c = coverage.Coverage(self.options, self.args) - c.FindTests() - self.confirmSampleTestsArePresent(c.tests) - - def testFindTestsFromBundleFile(self): - """Test finding of tests from a bundlefile.""" - (fd, filename) = tempfile.mkstemp() - f = os.fdopen(fd, 'w') - f.write(str(self.sample_test_names)) - f.close() - self.options.bundles = filename - c = coverage.Coverage(self.options, self.args) - c.FindTests() - self.confirmSampleTestsArePresent(c.tests) - os.unlink(filename) - - def testExclusionList(self): - """Test the gtest_filter exclusion list.""" - c = coverage.Coverage(self.options, self.args) - self.assertFalse(c.GtestFilter('doesnotexist_test')) - fake_exclusions = { sys.platform: { 'foobar': - ('a','b'), - 'doesnotexist_test': - ('Evil.Crash','Naughty.Test') } } - self.assertFalse(c.GtestFilter('barfoo')) - filter = c.GtestFilter('doesnotexist_test', fake_exclusions) - self.assertEquals('--gtest_filter=-Evil.Crash:-Naughty.Test', filter) - - - -if __name__ == '__main__': - unittest.main() diff --git a/chromium/tools/code_coverage/process_coverage.py b/chromium/tools/code_coverage/process_coverage.py deleted file mode 100755 index 07d83ac2c35..00000000000 --- a/chromium/tools/code_coverage/process_coverage.py +++ /dev/null @@ -1,413 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2011 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - - -"""Script to clean the lcov files and convert it to HTML - -TODO(niranjan): Add usage information here -""" - - -import optparse -import os -import shutil -import subprocess -import sys -import tempfile -import time -import urllib2 - - -# These are source files that were generated during compile time. We want to -# remove references to these files from the lcov file otherwise genhtml will -# throw an error. -win32_srcs_exclude = ['parse.y', - 'xpathgrammar.cpp', - 'cssgrammar.cpp', - 'csspropertynames.gperf'] - -# Number of lines of a new coverage data set -# to send at a time to the dashboard. -POST_CHUNK_SIZE = 50 - -# Number of post request failures to allow before exiting. -MAX_FAILURES = 5 - -def CleanPathNames(dir): - """Clean the pathnames of the HTML generated by genhtml. - - This method is required only for code coverage on Win32. Due to a known issue - with reading from CIFS shares mounted on Linux, genhtml appends a ^M to every - file name it reads from the Windows share, causing corrupt filenames in - genhtml's output folder. - - Args: - dir: Output folder of the genhtml output. - - Returns: - None - """ - # Stip off the ^M characters that get appended to the file name - for dirpath, dirname, filenames in os.walk(dir): - for file in filenames: - file_clean = file.replace('\r', '') - if file_clean != file: - os.rename(file, file_clean) - - -def GenerateHtml(lcov_path, dash_root): - """Runs genhtml to convert lcov data to human readable HTML. - - This script expects the LCOV file name to be in the format: - chrome_<platform>_<revision#>.lcov. - This method parses the file name and then sets up the correct folder - hierarchy for the coverage data and then runs genhtml to get the actual HTML - formatted coverage data. - - Args: - lcov_path: Path of the lcov data file. - dash_root: Root location of the dashboard. - - Returns: - Code coverage percentage on sucess. - None on failure. - """ - # Parse the LCOV file name. - filename = os.path.basename(lcov_path).split('.')[0] - buffer = filename.split('_') - dash_root = dash_root.rstrip('/') # Remove trailing '/' - - # Set up correct folder hierarchy in the dashboard root - # TODO(niranjan): Check the formatting using a regexp - if len(buffer) >= 3: # Check if filename has right formatting - platform = buffer[len(buffer) - 2] - revision = buffer[len(buffer) - 1] - if os.path.exists(os.path.join(dash_root, platform)) == False: - os.mkdir(os.path.join(dash_root, platform)) - output_dir = os.path.join(dash_root, platform, revision) - os.mkdir(output_dir) - else: - # TODO(niranjan): Add failure logging here. - return None # File not formatted correctly - - # Run genhtml - os.system('/usr/bin/genhtml -o %s %s' % (output_dir, lcov_path)) - # TODO(niranjan): Check the exit status of the genhtml command. - # TODO(niranjan): Parse the stdout and return coverage percentage. - CleanPathNames(output_dir) - return 'dummy' # TODO(niranjan): Return actual percentage. - - -def CleanWin32Lcov(lcov_path, src_root): - """Cleanup the lcov data generated on Windows. - - This method fixes up the paths inside the lcov file from the Win32 specific - paths to the actual paths of the mounted CIFS share. The lcov files generated - on Windows have the following format: - - SF:c:\chrome_src\src\skia\sgl\skscan_antihair.cpp - DA:97,0 - DA:106,0 - DA:107,0 - DA:109,0 - ... - end_of_record - - This method changes the source-file (SF) lines to a format compatible with - genhtml on Linux by fixing paths. This method also removes references to - certain dynamically generated files to be excluded from the code ceverage. - - Args: - lcov_path: Path of the Win32 lcov file to be cleaned. - src_root: Location of the source and symbols dir. - Returns: - None - """ - strip_flag = False - lcov = open(lcov_path, 'r') - loc_csv_file = open(lcov_path + '.csv', 'w') - (tmpfile_id, tmpfile_name) = tempfile.mkstemp() - tmpfile = open(tmpfile_name, 'w') - src_root = src_root.rstrip('/') # Remove trailing '/' - for line in lcov: - if line.startswith('SF'): - # We want to exclude certain auto-generated files otherwise genhtml will - # fail to convert lcov to HTML. - for exp in win32_srcs_exclude: - if line.rfind(exp) != -1: - strip_flag = True # Indicates that we want to remove this section - - # Now we normalize the paths - # e.g. Change SF:c:\foo\src\... to SF:/chrome_src/... - parse_buffer = line.split(':') - buffer = '%s:%s%s' % (parse_buffer[0], - src_root, - parse_buffer[2]) - buffer = buffer.replace('\\', '/') - line = buffer.replace('\r', '') - - # We want an accurate count of the lines of code in a given file so that - # we can estimate the code coverage perscentage accurately. We use a - # third party script cloc.pl which gives that count and then just parse - # its command line output to filter out the other unnecessary data. - # TODO(niranjan): Find out a better way of doing this. - buffer = buffer.lstrip('SF:') - file_for_loc = buffer.replace('\r\n', '') - # TODO(niranjan): Add a check to see if cloc is present on the machine. - command = ["perl", - "cloc.pl", - file_for_loc] - output = subprocess.Popen(command, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT).communicate()[0] - if output.rfind('error:'): - return None - - tmp_buf1 = output.split('=') - tmp_buf2 = tmp_buf1[len(tmp_buf1) - 2].split('x')[0].split(' ') - loc = tmp_buf2[len(tmp_buf2) - 2] - loc_csv_file.write('%s,%s\r\n' % (file_for_loc, loc)) - - # Write to the temp file if the section to write is valid - if strip_flag == False: - # Also write this to the 'clean' LCOV file - tmpfile.write('%s' % (line)) - - # Reset the strip flag - if line.endswith('end_of_record'): - strip_flag = False - - # Close the files and replace the lcov file by the 'clean' tmpfile - tmpfile.close() - lcov.close() - loc_csv_file.close() - shutil.move(tmpfile_name, lcov_path) - - -def ParseCoverageDataForDashboard(lcov_path): - """Parse code coverage data into coverage results per source node. - - Use lcov and linecount data to create a map of source nodes to - corresponding total and tested line counts. - - Args: - lcov_path: File path to lcov coverage data. - - Returns: - List of strings with comma separated source node and coverage. - """ - results = {} - linecount_path = lcov_path + '.csv' - assert(os.path.exists(linecount_path), - 'linecount csv does not exist at: %s' % linecount_path) - csv_file = open(linecount_path, 'r') - linecounts = csv_file.readlines() - csv_file.close() - lcov_file = open(lcov_path, 'r') - srcfile_index = 0 - for line in lcov_file: - line = line.strip() - - # Set the current srcfile name for a new src file declaration. - if line[:len('SF:')] == 'SF:': - instrumented_set = {} - executed_set = {} - srcfile_name = line[len('SF:'):] - - # Mark coverage data points hashlist style for the current src file. - if line[:len('DA:')] == 'DA:': - line_info = line[len('DA:'):].split(',') - assert(len(line_info) == 2, 'DA: line format unexpected - %s' % line) - (line_num, line_was_executed) = line_info - instrumented_set[line_num] = True - # line_was_executed is '0' or '1' - if int(line_was_executed): - executed_set[line_num] = True - - # Update results for the current src file at record end. - if line == 'end_of_record': - instrumented = len(instrumented_set.keys()) - executed = len(executed_set.keys()) - parent_directory = srcfile_name[:srcfile_name.rfind('/') + 1] - linecount_point = linecounts[srcfile_index].strip().split(',') - assert(len(linecount_point) == 2, - 'lintcount format unexpected - %s' % linecounts[srcfile_index]) - (linecount_path, linecount_count) = linecount_point - srcfile_index += 1 - - # Sanity check that path names in the lcov and linecount are lined up. - if linecount_path[-10:] != srcfile_name[-10:]: - print 'NAME MISMATCH: %s :: %s' % (srcfile_name, linecount_path) - if instrumented > int(linecount_count): - linecount_count = instrumented - - # Keep counts the same way that it is done in the genhtml utility. - # Count the coverage of a file towards the file, - # the parent directory, and the source root. - AddResults(results, srcfile_name, int(linecount_count), executed) - AddResults(results, parent_directory, int(linecount_count), executed) - AddResults(results, '/', instrumented, executed) - - lcov_file.close() - keys = results.keys() - keys.sort() - # The first key (sorted) will be the base directory '/' - # but its full path may be '/mnt/chrome_src/src/' - # using this offset will ignore the part '/mnt/chrome_src/src'. - # Offset is the last '/' that isn't the last character for the - # first directory name in results (position 1 in keys). - offset = len(keys[1][:keys[1][:-1].rfind('/')]) - lines = [] - for key in keys: - if len(key) > offset: - node_path = key[offset:] - else: - node_path = key - (total, covered) = results[key] - percent = float(covered) * 100 / total - lines.append('%s,%.2f' % (node_path, percent)) - return lines - - -def AddResults(results, location, lines_total, lines_executed): - """Add resulting line tallies to a location's total. - - Args: - results: Map of node location to corresponding coverage data. - location: Source node string. - lines_total: Number of lines to add to the total count for this node. - lines_executed: Number of lines to add to the executed count for this node. - """ - if results.has_key(location): - (i, e) = results[location] - results[location] = (i + lines_total, e + lines_executed) - else: - results[location] = (lines_total, lines_executed) - - -def PostResultsToDashboard(lcov_path, results, post_url): - """Post coverage results to coverage dashboard. - - Args: - lcov_path: File path for lcov data in the expected format: - <project>_<platform>_<cl#>.coverage.lcov - results: string list in the appropriate posting format. - """ - project_platform_cl = lcov_path.split('.')[0].split('_') - assert(len(project_platform_cl) == 3, - 'lcov_path not in expected format: %s' % lcov_path) - (project, platform, cl_string) = project_platform_cl - project_name = '%s-%s' % (project, platform) - url = '%s/newdata.do?project=%s&cl=%s' % (post_url, project_name, cl_string) - - # Send POSTs of POST_CHUNK_SIZE lines of the result set until - # there is no more data and last_loop is set to True. - last_loop = False - cur_line = 0 - while not last_loop: - body = '\n'.join(results[cur_line:cur_line + POST_CHUNK_SIZE]) - cur_line += POST_CHUNK_SIZE - last_loop = (cur_line >= len(results)) - req = urllib2.Request('%s&last=%s' % (url, str(last_loop)), body) - req.add_header('Content-Type', 'text/plain') - SendPost(req) - - -# Global counter for the current number of request failures. -num_fails = 0 - -def SendPost(req): - """Execute a post request and retry for up to MAX_FAILURES. - - Args: - req: A urllib2 request object. - - Raises: - URLError: If urlopen throws after too many retries. - HTTPError: If urlopen throws after too many retries. - """ - global num_fails - try: - urllib2.urlopen(req) - # Reset failure count. - num_fails = 0 - except (urllib2.URLError, urllib2.HTTPError): - num_fails += 1 - if num_fails < MAX_FAILURES: - print 'fail, retrying (%d)' % num_fails - time.sleep(5) - SendPost(req) - else: - print 'POST request exceeded allowed retries.' - raise - - -def main(): - if not sys.platform.startswith('linux'): - print 'This script is supported only on Linux' - return 0 - - # Command line parsing - parser = optparse.OptionParser() - parser.add_option('-p', - '--platform', - dest='platform', - default=None, - help=('Platform that the locv file was generated on. Must' - 'be one of {win32, linux2, linux3, macosx}')) - parser.add_option('-s', - '--source', - dest='src_dir', - default=None, - help='Path to the source code and symbols') - parser.add_option('-d', - '--dash_root', - dest='dash_root', - default=None, - help='Root directory for the dashboard') - parser.add_option('-l', - '--lcov', - dest='lcov_path', - default=None, - help='Location of the LCOV file to process') - parser.add_option('-u', - '--post_url', - dest='post_url', - default=None, - help='Base URL of the coverage dashboard') - (options, args) = parser.parse_args() - - if options.platform == None: - parser.error('Platform not specified') - if options.lcov_path == None: - parser.error('lcov file path not specified') - if options.src_dir == None: - parser.error('Source directory not specified') - if options.dash_root == None: - parser.error('Dashboard root not specified') - if options.post_url == None: - parser.error('Post URL not specified') - if options.platform == 'win32': - CleanWin32Lcov(options.lcov_path, options.src_dir) - percent = GenerateHtml(options.lcov_path, options.dash_root) - if percent == None: - # TODO(niranjan): Add logging. - print 'Failed to generate code coverage' - return 1 - else: - # TODO(niranjan): Do something with the code coverage numbers - pass - else: - print 'Unsupported platform' - return 1 - - # Prep coverage results for dashboard and post new set. - parsed_data = ParseCoverageDataForDashboard(options.lcov_path) - PostResultsToDashboard(options.lcov_path, parsed_data, options.post_url) - return 0 - - -if __name__ == '__main__': - sys.exit(main()) |