- Revision
- 112437
- Author
- [email protected]
- Date
- 2012-03-28 13:59:06 -0700 (Wed, 28 Mar 2012)
Log Message
test-webkitpy should support files, directories, and packages as command line args
https://bugs.webkit.org/show_bug.cgi?id=76765
Reviewed by Adam Barth.
This patch adds support for specifying files, directories, and
packages to test-webkitpy along with the already existing
support for modules, test classes, and individual test names.
Also, fix a bug in filesystem_mock where we wouldn't normalize a
path containing a reference to the current directory properly,
for example, '/foo/./bar.py'.
* Scripts/webkitpy/common/system/filesystem_mock.py:
(MockFileSystem.normpath):
* Scripts/webkitpy/test/main.py:
(Tester._configure_logging):
(Tester._run_tests):
* Scripts/webkitpy/test/test_finder.py:
(TestDirectoryTree.find_modules):
(TestDirectoryTree.subpath):
(TestFinder.is_dotted_name):
(TestFinder.find_names):
(TestFinder):
(TestFinder._find_names_for_arg):
(TestFinder._find_in_trees):
(TestFinder._default_names):
* Scripts/webkitpy/test/test_finder_unittest.py:
(TestFinderTest.setUp):
(TestFinderTest.tearDown):
(TestFinderTest.check_names):
(TestFinderTest.test_default_names):
(TestFinderTest):
(TestFinderTest.test_paths):
Modified Paths
Diff
Modified: trunk/Tools/ChangeLog (112436 => 112437)
--- trunk/Tools/ChangeLog 2012-03-28 20:42:19 UTC (rev 112436)
+++ trunk/Tools/ChangeLog 2012-03-28 20:59:06 UTC (rev 112437)
@@ -1,3 +1,40 @@
+2012-03-28 Dirk Pranke <[email protected]>
+
+ test-webkitpy should support files, directories, and packages as command line args
+ https://bugs.webkit.org/show_bug.cgi?id=76765
+
+ Reviewed by Adam Barth.
+
+ This patch adds support for specifying files, directories, and
+ packages to test-webkitpy along with the already existing
+ support for modules, test classes, and individual test names.
+
+ Also, fix a bug in filesystem_mock where we wouldn't normalize a
+ path containing a reference to the current directory properly,
+ for example, '/foo/./bar.py'.
+
+ * Scripts/webkitpy/common/system/filesystem_mock.py:
+ (MockFileSystem.normpath):
+ * Scripts/webkitpy/test/main.py:
+ (Tester._configure_logging):
+ (Tester._run_tests):
+ * Scripts/webkitpy/test/test_finder.py:
+ (TestDirectoryTree.find_modules):
+ (TestDirectoryTree.subpath):
+ (TestFinder.is_dotted_name):
+ (TestFinder.find_names):
+ (TestFinder):
+ (TestFinder._find_names_for_arg):
+ (TestFinder._find_in_trees):
+ (TestFinder._default_names):
+ * Scripts/webkitpy/test/test_finder_unittest.py:
+ (TestFinderTest.setUp):
+ (TestFinderTest.tearDown):
+ (TestFinderTest.check_names):
+ (TestFinderTest.test_default_names):
+ (TestFinderTest):
+ (TestFinderTest.test_paths):
+
2012-03-28 Simon Fraser <[email protected]>
Fix inspector tests when running in internal builds.
Modified: trunk/Tools/Scripts/webkitpy/common/system/filesystem_mock.py (112436 => 112437)
--- trunk/Tools/Scripts/webkitpy/common/system/filesystem_mock.py 2012-03-28 20:42:19 UTC (rev 112436)
+++ trunk/Tools/Scripts/webkitpy/common/system/filesystem_mock.py 2012-03-28 20:59:06 UTC (rev 112437)
@@ -278,7 +278,7 @@
def normpath(self, path):
# This function is called a lot, so we try to optimize the common cases
# instead of always calling _slow_but_correct_normpath(), above.
- if '..' in path:
+ if '..' in path or '/./' in path:
# This doesn't happen very often; don't bother trying to optimize it.
return self._slow_but_correct_normpath(path)
if not path:
Modified: trunk/Tools/Scripts/webkitpy/test/main.py (112436 => 112437)
--- trunk/Tools/Scripts/webkitpy/test/main.py 2012-03-28 20:42:19 UTC (rev 112436)
+++ trunk/Tools/Scripts/webkitpy/test/main.py 2012-03-28 20:59:06 UTC (rev 112437)
@@ -24,7 +24,6 @@
import logging
import optparse
-import os
import StringIO
import sys
import traceback
@@ -102,6 +101,7 @@
# Modifying the handler, then, is less intrusive and less likely to
# interfere with modifications made by other modules (e.g. in unit
# tests).
+ handler.name = __name__
handler.setLevel(log_level)
formatter = logging.Formatter("%(message)s")
handler.setFormatter(formatter)
Modified: trunk/Tools/Scripts/webkitpy/test/test_finder.py (112436 => 112437)
--- trunk/Tools/Scripts/webkitpy/test/test_finder.py 2012-03-28 20:42:19 UTC (rev 112436)
+++ trunk/Tools/Scripts/webkitpy/test/test_finder.py 2012-03-28 20:59:06 UTC (rev 112437)
@@ -24,6 +24,7 @@
"""this module is responsible for finding python tests."""
import logging
+import re
import sys
@@ -40,17 +41,29 @@
self.top_package = starting_subdirectory.replace(filesystem.sep, '.') + '.'
self.search_directory = filesystem.join(self.top_directory, starting_subdirectory)
- def find_modules(self, suffixes):
+ def find_modules(self, suffixes, sub_directory=None):
+ if sub_directory:
+ search_directory = self.filesystem.join(self.top_directory, sub_directory)
+ else:
+ search_directory = self.search_directory
def file_filter(filesystem, dirname, basename):
return any(basename.endswith(suffix) for suffix in suffixes)
- filenames = self.filesystem.files_under(self.search_directory, file_filter=file_filter)
+ filenames = self.filesystem.files_under(search_directory, file_filter=file_filter)
return [self.to_module(filename) for filename in filenames]
def to_module(self, path):
return path.replace(self.top_directory + self.filesystem.sep, '').replace(self.filesystem.sep, '.')[:-3]
+ def subpath(self, path):
+ """Returns the relative path from the top of the tree to the path, or None if the path is not under the top of the tree."""
+ realpath = self.filesystem.realpath(self.filesystem.join(self.top_directory, path))
+ if realpath.startswith(self.top_directory + self.filesystem.sep):
+ return realpath.replace(self.top_directory + self.filesystem.sep, '')
+ return None
+
+
def clean(self):
"""Delete all .pyc files in the tree that have no matching .py file."""
_log.debug("Cleaning orphaned *.pyc files from: %s" % self.search_directory)
@@ -80,6 +93,9 @@
relpath = name.replace('.', self.filesystem.sep) + '.py'
return any(self.filesystem.exists(self.filesystem.join(tree.top_directory, relpath)) for tree in self.trees)
+ def is_dotted_name(self, name):
+ return re.match(r'[a-zA-Z.][a-zA-Z0-9_.]*', name)
+
def to_module(self, path):
for tree in self.trees:
if path.startswith(tree.top_directory):
@@ -87,13 +103,50 @@
return None
def find_names(self, args, skip_integrationtests, find_all):
- if args:
- return args
-
suffixes = ['_unittest.py']
if not skip_integrationtests:
suffixes.append('_integrationtest.py')
+ if args:
+ names = []
+ for arg in args:
+ names.extend(self._find_names_for_arg(arg, suffixes))
+ return names
+
+ return self._default_names(suffixes, find_all)
+
+ def _find_names_for_arg(self, arg, suffixes):
+ realpath = self.filesystem.realpath(arg)
+ if self.filesystem.exists(realpath):
+ names = self._find_in_trees(realpath, suffixes)
+ if not names:
+ _log.error("%s is not in one of the test trees." % arg)
+ return names
+
+ # See if it's a python package in a tree (or a relative path from the top of a tree).
+ names = self._find_in_trees(arg.replace('.', self.filesystem.sep), suffixes)
+ if names:
+ return names
+
+ if self.is_dotted_name(arg):
+ # The name may not exist, but that's okay; we'll find out later.
+ return [arg]
+
+ _log.error("%s is not a python name or an existing file or directory." % arg)
+ return []
+
+ def _find_in_trees(self, path, suffixes):
+ for tree in self.trees:
+ relpath = tree.subpath(path)
+ if not relpath:
+ continue
+ if self.filesystem.isfile(path):
+ return [tree.to_module(path)]
+ else:
+ return tree.find_modules(suffixes, path)
+ return []
+
+ def _default_names(self, suffixes, find_all):
modules = []
for tree in self.trees:
modules.extend(tree.find_modules(suffixes))
Modified: trunk/Tools/Scripts/webkitpy/test/test_finder_unittest.py (112436 => 112437)
--- trunk/Tools/Scripts/webkitpy/test/test_finder_unittest.py 2012-03-28 20:42:19 UTC (rev 112436)
+++ trunk/Tools/Scripts/webkitpy/test/test_finder_unittest.py 2012-03-28 20:59:06 UTC (rev 112437)
@@ -24,6 +24,7 @@
import unittest
from webkitpy.common.system.filesystem_mock import MockFileSystem
+from webkitpy.common.system.outputcapture import OutputCapture
from webkitpy.test.test_finder import TestFinder
@@ -36,17 +37,28 @@
'/foo2/bar2/baz2.pyc': '',
'/foo2/bar2/baz2_integrationtest.py': '',
'/foo2/bar2/missing.pyc': '',
+ '/tmp/another_unittest.py': '',
}
self.fs = MockFileSystem(files)
self.finder = TestFinder(self.fs)
self.finder.add_tree('/foo', 'bar')
self.finder.add_tree('/foo2')
+
+ # Here we have to jump through a hoop to make sure test-webkitpy doesn't log
+ # any messages from these tests :(.
self.root_logger = logging.getLogger()
- self.log_level = self.root_logger.level
- self.root_logger.setLevel(logging.WARNING)
+ self.log_handler = None
+ for h in self.root_logger.handlers:
+ if getattr(h, 'name', None) == 'webkitpy.test.main':
+ self.log_handler = h
+ break
+ if self.log_handler:
+ self.log_level = self.log_handler.level
+ self.log_handler.level = logging.CRITICAL
def tearDown(self):
- self.root_logger.setLevel(self.log_level)
+ if self.log_handler:
+ self.log_handler.setLevel(self.log_level)
def test_additional_system_paths(self):
self.assertEquals(self.finder.additional_paths(['/usr']),
@@ -70,19 +82,53 @@
self.finder.clean_trees()
self.assertFalse(self.fs.exists('/foo2/bar2/missing.pyc'))
- def test_find_names(self):
- self.assertEquals(self.finder.find_names([], skip_integrationtests=False, find_all=True),
- ['bar.baz_unittest', 'bar2.baz2_integrationtest'])
+ def check_names(self, names, expected_names, skip_integrationtests=False, find_all=False):
+ self.assertEquals(self.finder.find_names(names, skip_integrationtests, find_all),
+ expected_names)
- self.assertEquals(self.finder.find_names([], skip_integrationtests=True, find_all=True),
- ['bar.baz_unittest'])
- self.assertEquals(self.finder.find_names([], skip_integrationtests=True, find_all=False),
- ['bar.baz_unittest'])
+ def test_default_names(self):
+ self.check_names([], ['bar.baz_unittest', 'bar2.baz2_integrationtest'])
+ self.check_names([], ['bar.baz_unittest'], skip_integrationtests=True, find_all=True)
+ self.check_names([], ['bar.baz_unittest'], skip_integrationtests=True, find_all=False)
# Should return the names given it, even if they don't exist.
- self.assertEquals(self.finder.find_names(['foobar'], skip_integrationtests=True, find_all=True),
- ['foobar'])
+ self.check_names(['foobar'], ['foobar'], skip_integrationtests=True, find_all=False)
+ def test_paths(self):
+ self.fs.chdir('/foo/bar')
+ self.check_names(['baz_unittest.py'], ['bar.baz_unittest'])
+ self.check_names(['./baz_unittest.py'], ['bar.baz_unittest'])
+ self.check_names(['/foo/bar/baz_unittest.py'], ['bar.baz_unittest'])
+ self.check_names(['.'], ['bar.baz_unittest'])
+ self.check_names(['../../foo2/bar2'], ['bar2.baz2_integrationtest'])
+ self.fs.chdir('/')
+ self.check_names(['bar'], ['bar.baz_unittest'])
+ self.check_names(['/foo/bar/'], ['bar.baz_unittest'])
+
+ # This works 'by accident' since it maps onto a package.
+ self.check_names(['bar/'], ['bar.baz_unittest'])
+
+ # This should log an error, since it's outside the trees.
+ oc = OutputCapture()
+ oc.set_log_level(logging.ERROR)
+ oc.capture_output()
+ try:
+ self.check_names(['/tmp/another_unittest.py'], [])
+ finally:
+ _, _, logs = oc.restore_output()
+ self.assertTrue('another_unittest.py' in logs)
+
+ # Paths that don't exist are errors.
+ oc.capture_output()
+ try:
+ self.check_names(['/foo/bar/notexist_unittest.py'], [])
+ finally:
+ _, _, logs = oc.restore_output()
+ self.assertTrue('notexist_unittest.py' in logs)
+
+ # Names that don't exist are caught later, at load time.
+ self.check_names(['bar.notexist_unittest'], ['bar.notexist_unittest'])
+
if __name__ == '__main__':
unittest.main()