Index: tools/code_coverage/coverage_posix.py |
diff --git a/tools/code_coverage/coverage_posix.py b/tools/code_coverage/coverage_posix.py |
deleted file mode 100755 |
index f4fa56caa10d8b1777c5b3817f6e599c0e7d83a7..0000000000000000000000000000000000000000 |
--- a/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()) |