summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/chrome_tests.gypi116
-rwxr-xr-xtools/code_coverage/coverage_posix.py31
-rwxr-xr-xtools/code_coverage/coverage_posix_unittest.py58
3 files changed, 179 insertions, 26 deletions
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index ceaa7e2..a9c0dec 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2320,17 +2320,56 @@
}, # target 'pyautolib'
] # targets
}],
+ # To enable the coverage targets, do
+ # GYP_DEFINES='coverage=1' gclient sync
+ # To match the coverage buildbot more closely, do this:
+ # GYP_DEFINES='coverage=1 enable_svg=0 fastbuild=1' gclient sync
+ # (and, on MacOS, be sure to switch your SDK from "Base SDK" to "Mac OS X 10.6")
['coverage!=0',
{ 'targets': [
{
+ ### Coverage BUILD AND RUN.
+ ### Not named coverage_build_and_run for historical reasons.
'target_name': 'coverage',
+ 'dependencies': [ 'coverage_build', 'coverage_run' ],
+ # do NOT place this in the 'all' list; most won't want it.
+ # In gyp, booleans are 0/1 not True/False.
+ 'suppress_wildcard': 1,
+ 'type': 'none',
+ 'actions': [
+ {
+ 'message': 'Coverage is now complete.',
+ # MSVS must have an input file and an output file.
+ 'inputs': [ '<(PRODUCT_DIR)/coverage.info' ],
+ 'outputs': [ '<(PRODUCT_DIR)/coverage-build-and-run.stamp' ],
+ 'action_name': 'coverage',
+ # Wish gyp had some basic builtin commands (e.g. 'touch').
+ 'action': [ 'python', '-c',
+ 'import os; ' +
+ 'open(' +
+ '\'<(PRODUCT_DIR)\' + os.path.sep + ' +
+ '\'coverage-build-and-run.stamp\'' +
+ ', \'w\').close()' ],
+ # Use outputs of this action as inputs for the main target build.
+ # Seems as a misnomer but makes this happy on Linux (scons).
+ 'process_outputs_as_sources': 1,
+ },
+ ], # 'actions'
+ },
+ ### Coverage BUILD. Compile only; does not run the bundles.
+ ### Intended as the build phase for our coverage bots.
+ ###
+ ### Builds unit test bundles needed for coverage.
+ ### Outputs this list of bundles into coverage_bundles.py.
+ ###
+ ### If you want to both build and run coverage from your IDE,
+ ### use the 'coverage' target.
+ {
+ 'target_name': 'coverage_build',
# do NOT place this in the 'all' list; most won't want it.
# In gyp, booleans are 0/1 not True/False.
'suppress_wildcard': 1,
'type': 'none',
- # Cross platform test bundles. If you add new tests you may
- # need to update the croc configs. For example, see the
- # first regexp in build/(linux|mac|win)/chrome_*.croc.
'dependencies': [
'automated_ui_tests',
'../app/app.gyp:app_unittests',
@@ -2347,49 +2386,78 @@
# investigate why.
# 'ui_tests',
'unit_tests',
- ],
- # Platform specific unit test bundles. Unless staging
- # a checkin, please add a comment describing why your test is
- # in here and is not cross-platform.
+ ], # 'dependencies'
'conditions': [
['OS=="win"', {
- 'dependencies': [
+ 'coverage_bundles': [
# Courgette has not been ported from Windows.
# Note build/win/chrome_win.croc uniquely has the
# courgette source directory in an include path.
'../courgette/courgette.gyp:courgette_unittests',
- ],
- }],
+ ]}],
['OS=="linux"', {
- 'dependencies': [
- # Placeholder; empty for now.
- ],
- }],
+ 'coverage_bundles': [
+ # Placeholder; empty for now.
+ ]}],
['OS=="mac"', {
- 'dependencies': [
- # Placeholder; empty for now.
- ],
- }],
- ],
-
+ 'coverage_bundles': [
+ # Placeholder; empty for now.
+ ]}],
+ ], # 'conditions'
'actions': [
{
# 'message' for Linux/scons in particular. Scons
# requires the 'coverage' target be run from within
# src/chrome.
- 'message': 'Running coverage_posix.py to generate coverage numbers',
+ 'message': 'Compiling coverage bundles.',
# MSVS must have an input file and an output file.
'inputs': [ '../tools/code_coverage/coverage_posix.py' ],
+ 'outputs': [ '<(PRODUCT_DIR)/coverage_bundles.py' ],
+ 'action_name': 'coverage_build',
+ 'action': [ 'python', '-c',
+ 'import os; '
+ 'f = open(' +
+ '\'<(PRODUCT_DIR)\' + os.path.sep + ' +
+ '\'coverage_bundles.py\'' +
+ ', \'w\'); ' +
+ 'deplist = \'' + '<@(_dependencies)' + '\'.split(\' \'); ' +
+ 'f.write(str(deplist)); ' +
+ 'f.close()'],
+ # Use outputs of this action as inputs for the main target build.
+ # Seems as a misnomer but makes this happy on Linux (scons).
+ 'process_outputs_as_sources': 1,
+ },
+ ], # 'actions'
+ },
+ ### Coverage RUN. Does not compile the bundles. Mirrors the
+ ### run_coverage_bundles buildbot phase. If you update this
+ ### command update the mirror in
+ ### $BUILDBOT/scripts/master/factory/chromium_commands.py.
+ ### If you want both build and run, use the 'coverage' target.
+ {
+ 'target_name': 'coverage_run',
+ # do NOT place this in the 'all' list; most won't want it.
+ # In gyp, booleans are 0/1 not True/False.
+ 'suppress_wildcard': 1,
+ 'type': 'none',
+ 'actions': [
+ {
+ # 'message' for Linux/scons in particular. Scons
+ # requires the 'coverage' target be run from within
+ # src/chrome.
+ 'message': 'Running the coverage script. NOT building anything.',
+ # MSVS must have an input file and an output file.
+ 'inputs': [ '<(PRODUCT_DIR)/coverage_bundles.py' ],
'outputs': [ '<(PRODUCT_DIR)/coverage.info' ],
- 'action_name': 'coverage',
+ 'action_name': 'coverage_run',
'action': [ 'python',
'../tools/code_coverage/coverage_posix.py',
'--directory',
'<(PRODUCT_DIR)',
'--src_root',
'..',
- '--',
- '<@(_dependencies)'],
+ '--bundles',
+ '<(PRODUCT_DIR)/coverage_bundles.py'],
# Use outputs of this action as inputs for the main target build.
# Seems as a misnomer but makes this happy on Linux (scons).
'process_outputs_as_sources': 1,
diff --git a/tools/code_coverage/coverage_posix.py b/tools/code_coverage/coverage_posix.py
index 340199d..b018ae4 100755
--- a/tools/code_coverage/coverage_posix.py
+++ b/tools/code_coverage/coverage_posix.py
@@ -48,6 +48,11 @@ Linux:
--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. E.g.
+ ['../base/base.gyp:base_unittests']
+ This is used as part of the coverage bot.
+
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
@@ -235,9 +240,28 @@ class Coverage(object):
if self.options.all_unittests:
self.tests += glob.glob(os.path.join(self.directory, '*_unittests'))
+ # Tests can come in as args or as a file of bundles.
+ all_testnames = self.args[:] # Copy since we might modify
+ 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 self.args:
+ for testname in all_testnames:
if ':' in testname:
self.tests += [os.path.join(self.directory, testname.split(':')[1])]
else:
@@ -582,6 +606,11 @@ def CoverageOptionParser():
default=9.9 * 60.0,
help='Timeout before bailing if a subprocess has no output.'
' Default is a hair under 10min (Buildbot is 10min.)')
+ parser.add_option('-B',
+ '--bundles',
+ dest='bundles',
+ default=None,
+ help='Filename of bundles for coverage.')
return parser
diff --git a/tools/code_coverage/coverage_posix_unittest.py b/tools/code_coverage/coverage_posix_unittest.py
index e7ae155..9eee129 100755
--- a/tools/code_coverage/coverage_posix_unittest.py
+++ b/tools/code_coverage/coverage_posix_unittest.py
@@ -3,16 +3,52 @@
# 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."""
+"""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."""
@@ -67,6 +103,26 @@ class CoveragePosixTest(unittest.TestCase):
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)
+
if __name__ == '__main__':
unittest.main()