Changeset 104768 in webkit
- Timestamp:
- Jan 11, 2012 4:58:52 PM (12 years ago)
- Location:
- trunk/Tools
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Tools/ChangeLog
r104764 r104768 1 2012-01-10 Dirk Pranke <dpranke@chromium.org> 2 3 test-webkitpy: push more logic into webkitpy.test.main, clean up code 4 https://bugs.webkit.org/show_bug.cgi?id=76021 5 6 Reviewed by Eric Seidel. 7 8 I plan to add more functionality to test-webkitpy, but it is 9 difficult to hack on now; this patch is the first of two that 10 brings test-webkitpy more inline with current coding style by 11 pushing more logic into the webkitpy.test.main.Tester class (so 12 that it will be testable itself). 13 14 There should be no functional changes in this patch. 15 16 * Scripts/test-webkitpy: 17 (_path_from_webkit_root): 18 * Scripts/webkitpy/test/main.py: 19 (Tester): 20 (Tester.init): 21 (Tester.configure_logging): 22 (Tester.configure_logging.filter): 23 (Tester.clean_packages): 24 (Tester.run_tests): 25 1 26 2012-01-11 Wei Jia <wjia@chromium.org> 2 27 -
trunk/Tools/Scripts/test-webkitpy
r104495 r104768 33 33 import sys 34 34 35 # We strictly limit what is imported from webkitpy until we get a chance 36 # to delete any stray *.pyc files. 37 import webkitpy.common.version_check 35 # NOTE: We intentionally limit imports from webkitpy here to minimize the 36 # chances of breaking test-webkitpy itself. 37 from webkitpy.common import version_check 38 from webkitpy.test import main 39 38 40 39 41 _log = logging.getLogger("test-webkitpy") 40 42 41 43 42 # Verbose logging is useful for debugging test-webkitpy code that runs 43 # before the actual unit tests -- things like autoinstall downloading and 44 # unit-test auto-detection logic. This is different from verbose logging 45 # of the unit tests themselves (i.e. the unittest module's --verbose flag). 46 def configure_logging(is_verbose_logging): 47 """Configure the root logger. 44 if __name__ == "__main__": 45 webkit_root = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) 48 46 49 Configure the root logger not to log any messages from webkitpy -- 50 except for messages from the autoinstall module. Also set the 51 logging level as described below. 47 tester = main.Tester() 48 tester.init(sys.argv[1:]) 52 49 53 Args:54 is_verbose_logging: A boolean value of whether logging should be55 verbose. If this parameter is true, the logging56 level for the handler on the root logger is set to57 logging.DEBUG. Otherwise, it is set to logging.INFO.50 # FIXME: We should probably test each package separately to avoid naming conflicts. 51 dirs = [ 52 os.path.join(webkit_root, 'Tools', 'Scripts', 'webkitpy'), 53 os.path.join(webkit_root, 'Source', 'WebKit2', 'Scripts', 'webkit2'), 54 ] 58 55 59 """ 60 if is_verbose_logging: 61 logging_level = logging.DEBUG 62 else: 63 logging_level = logging.INFO 56 # FIXME: Make this work on windows as well? 57 appengine_sdk_path = '/usr/local/google_appengine' 58 if os.path.exists(appengine_sdk_path) and not appengine_sdk_path in sys.path: 59 sys.path.append(appengine_sdk_path) 60 try: 61 import google.appengine 62 dirs.append(os.path.join(webkit_root, 'Tools', 'QueueStatusServer')) 63 except ImportError: 64 _log.info('Skipping QueueStatusServer tests; the Google AppEngine Python SDK is not installed.') 64 65 65 handler = logging.StreamHandler(sys.stderr) 66 # We constrain the level on the handler rather than on the root 67 # logger itself. This is probably better because the handler is 68 # configured and known only to this module, whereas the root logger 69 # is an object shared (and potentially modified) by many modules. 70 # Modifying the handler, then, is less intrusive and less likely to 71 # interfere with modifications made by other modules (e.g. in unit 72 # tests). 73 handler.setLevel(logging_level) 74 formatter = logging.Formatter("%(name)s: %(levelname)-8s %(message)s") 75 handler.setFormatter(formatter) 76 77 logger = logging.getLogger() 78 logger.addHandler(handler) 79 logger.setLevel(logging.NOTSET) 80 81 # Filter out most webkitpy messages. 82 # 83 # Messages can be selectively re-enabled for this script by updating 84 # this method accordingly. 85 def filter(record): 86 """Filter out autoinstall and non-third-party webkitpy messages.""" 87 # FIXME: Figure out a way not to use strings here, for example by 88 # using syntax like webkitpy.test.__name__. We want to be 89 # sure not to import any non-Python 2.4 code, though, until 90 # after the version-checking code has executed. 91 if (record.name.startswith("webkitpy.common.system.autoinstall") or 92 record.name.startswith("webkitpy.test")): 93 return True 94 if record.name.startswith("webkitpy"): 95 return False 96 return True 97 98 testing_filter = logging.Filter() 99 testing_filter.filter = filter 100 101 # Display a message so developers are not mystified as to why 102 # logging does not work in the unit tests. 103 _log.info("Suppressing most webkitpy logging while running unit tests.") 104 handler.addFilter(testing_filter) 105 106 107 def _clean_pyc_files(dir_to_clean): 108 """Delete from under a directory all .pyc files that have no .py file.""" 109 _log.debug("Cleaning orphaned *.pyc files from: %s" % dir_to_clean) 110 for dir_path, dir_names, file_names in os.walk(dir_to_clean): 111 for file_name in file_names: 112 if file_name.endswith(".pyc") and file_name[:-1] not in file_names: 113 file_path = os.path.join(dir_path, file_name) 114 _log.info("Deleting orphan *.pyc file: %s" % file_path) 115 os.remove(file_path) 116 117 118 def _clean_packages(external_package_paths): 119 webkitpy_dir = os.path.join(os.path.dirname(__file__), "webkitpy") 120 package_paths = [webkitpy_dir] + external_package_paths 121 for path in package_paths: 122 _clean_pyc_files(path) 123 124 125 def init(command_args, external_package_paths): 126 """Execute code prior to importing from webkitpy.unittests. 127 128 Args: 129 command_args: The list of command-line arguments -- usually 130 sys.argv[1:]. 131 132 """ 133 verbose_logging_flag = "--verbose-logging" 134 is_verbose_logging = verbose_logging_flag in command_args 135 if is_verbose_logging: 136 # Remove the flag so it doesn't cause unittest.main() to error out. 137 # 138 # FIXME: Get documentation for the --verbose-logging flag to show 139 # up in the usage instructions, which are currently generated 140 # by unittest.main(). It's possible that this will require 141 # re-implementing the option parser for unittest.main() 142 # since there may not be an easy way to modify its existing 143 # option parser. 144 sys.argv.remove(verbose_logging_flag) 145 146 configure_logging(is_verbose_logging) 147 _log.debug("Verbose WebKit logging enabled.") 148 149 # We clean orphaned *.pyc files from the packages prior to importing from 150 # them to make sure that no import statements falsely succeed. 151 # This helps to check that import statements have been updated correctly 152 # after any file moves. Otherwise, incorrect import statements can 153 # be masked. 154 # 155 # For example, if webkitpy/common/host.py were moved to a 156 # different location without changing any import statements, and if 157 # the corresponding .pyc file were left behind without deleting it, 158 # then "import webkitpy.common.host" would continue to succeed 159 # even though it would fail for someone checking out a fresh copy 160 # of the source tree. This is because of a Python feature: 161 # 162 # "It is possible to have a file called spam.pyc (or spam.pyo when -O 163 # is used) without a file spam.py for the same module. This can be used 164 # to distribute a library of Python code in a form that is moderately 165 # hard to reverse engineer." 166 # 167 # ( http://docs.python.org/tutorial/modules.html#compiled-python-files ) 168 # 169 # Deleting the orphaned .pyc file prior to importing, however, would 170 # cause an ImportError to occur on import as desired. 171 _clean_packages(external_package_paths) 172 173 174 def _path_from_webkit_root(*components): 175 webkit_root = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) 176 return os.path.join(webkit_root, *components) 177 178 179 def _test_import(module_path): 180 try: 181 sys.path.append(os.path.dirname(module_path)) 182 module_name = os.path.basename(module_path) 183 __import__(module_name) 184 return True 185 except Exception, e: 186 message = "Skipping tests in %s due to failure (%s)." % (module_path, e) 187 if module_name.endswith("QueueStatusServer"): 188 message += " This module is optional. The failure is likely due to a missing Google AppEngine install. (http://code.google.com/appengine/downloads.html)" 189 _log.warn(message) 190 return False 191 192 if __name__ == "__main__": 193 # FIXME: We should probably test each package separately to avoid naming conflicts. 194 external_package_paths = [ 195 _path_from_webkit_root('Source', 'WebKit2', 'Scripts', 'webkit2'), 196 _path_from_webkit_root('Tools', 'QueueStatusServer'), 197 ] 198 init(sys.argv[1:], external_package_paths) 199 200 # We import the unit test code after init() to ensure that any 201 # Python version warnings are displayed in case an error occurs 202 # while interpreting webkitpy.unittests. This also allows 203 # logging to be configured prior to importing -- for example to 204 # enable the display of autoinstall logging.log messages while 205 # running the unit tests. 206 from webkitpy.test.main import Tester 207 208 external_package_paths = filter(_test_import, external_package_paths) 209 210 Tester().run_tests(sys.argv, external_package_paths) 66 tester.clean_packages(dirs) 67 tester.run_tests(sys.argv, dirs) -
trunk/Tools/Scripts/webkitpy/test/main.py
r104740 r104768 21 21 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 22 23 """ Contains the entry method for test-webkitpy."""23 """unit testing code for webkitpy.""" 24 24 25 25 import logging … … 28 28 import unittest 29 29 30 import webkitpy 31 30 # NOTE: We intentionally do not depend on anything else in webkitpy here to avoid breaking test-webkitpy. 32 31 33 32 _log = logging.getLogger(__name__) … … 35 34 36 35 class Tester(object): 37 38 """Discovers and runs webkitpy unit tests.""" 39 40 def _find_test_files(self, webkitpy_dir, suffix): 41 """Return a list of paths to all unit-test files.""" 42 unittest_paths = [] # Return value. 43 44 for dir_path, dir_names, file_names in os.walk(webkitpy_dir): 36 """webkitpy unit tests driver (finds and runs tests).""" 37 38 def init(self, command_args): 39 """Execute code prior to importing from webkitpy.unittests. 40 41 Args: 42 command_args: The list of command-line arguments -- usually 43 sys.argv[1:]. 44 45 """ 46 verbose_logging_flag = "--verbose-logging" 47 is_verbose_logging = verbose_logging_flag in command_args 48 if is_verbose_logging: 49 # Remove the flag so it doesn't cause unittest.main() to error out. 50 # 51 # FIXME: Get documentation for the --verbose-logging flag to show 52 # up in the usage instructions, which are currently generated 53 # by unittest.main(). It's possible that this will require 54 # re-implementing the option parser for unittest.main() 55 # since there may not be an easy way to modify its existing 56 # option parser. 57 sys.argv.remove(verbose_logging_flag) 58 59 if is_verbose_logging: 60 self.configure_logging(logging.DEBUG) 61 _log.debug("Verbose WebKit logging enabled.") 62 else: 63 self.configure_logging(logging.INFO) 64 65 # Verbose logging is useful for debugging test-webkitpy code that runs 66 # before the actual unit tests -- things like autoinstall downloading and 67 # unit-test auto-detection logic. This is different from verbose logging 68 # of the unit tests themselves (i.e. the unittest module's --verbose flag). 69 def configure_logging(self, log_level): 70 """Configure the root logger. 71 72 Configure the root logger not to log any messages from webkitpy -- 73 except for messages from the autoinstall module. Also set the 74 logging level as described below. 75 """ 76 handler = logging.StreamHandler(sys.stderr) 77 # We constrain the level on the handler rather than on the root 78 # logger itself. This is probably better because the handler is 79 # configured and known only to this module, whereas the root logger 80 # is an object shared (and potentially modified) by many modules. 81 # Modifying the handler, then, is less intrusive and less likely to 82 # interfere with modifications made by other modules (e.g. in unit 83 # tests). 84 handler.setLevel(log_level) 85 formatter = logging.Formatter("%(message)s") 86 handler.setFormatter(formatter) 87 88 logger = logging.getLogger() 89 logger.addHandler(handler) 90 logger.setLevel(logging.NOTSET) 91 92 # Filter out most webkitpy messages. 93 # 94 # Messages can be selectively re-enabled for this script by updating 95 # this method accordingly. 96 def filter(record): 97 """Filter out autoinstall and non-third-party webkitpy messages.""" 98 # FIXME: Figure out a way not to use strings here, for example by 99 # using syntax like webkitpy.test.__name__. We want to be 100 # sure not to import any non-Python 2.4 code, though, until 101 # after the version-checking code has executed. 102 if (record.name.startswith("webkitpy.common.system.autoinstall") or 103 record.name.startswith("webkitpy.test")): 104 return True 105 if record.name.startswith("webkitpy"): 106 return False 107 return True 108 109 testing_filter = logging.Filter() 110 testing_filter.filter = filter 111 112 # Display a message so developers are not mystified as to why 113 # logging does not work in the unit tests. 114 _log.info("Suppressing most webkitpy logging while running unit tests.") 115 handler.addFilter(testing_filter) 116 117 def clean_packages(self, dirs): 118 """Delete all .pyc files under dirs that have no .py file.""" 119 # We clean orphaned *.pyc files from the packages prior to importing from 120 # them to make sure that no import statements falsely succeed. 121 # This helps to check that import statements have been updated correctly 122 # after any file moves. Otherwise, incorrect import statements can 123 # be masked. 124 # 125 # For example, if webkitpy/common/host.py were moved to a 126 # different location without changing any import statements, and if 127 # the corresponding .pyc file were left behind without deleting it, 128 # then "import webkitpy.common.host" would continue to succeed 129 # even though it would fail for someone checking out a fresh copy 130 # of the source tree. This is because of a Python feature: 131 # 132 # "It is possible to have a file called spam.pyc (or spam.pyo when -O 133 # is used) without a file spam.py for the same module. This can be used 134 # to distribute a library of Python code in a form that is moderately 135 # hard to reverse engineer." 136 # 137 # ( http://docs.python.org/tutorial/modules.html#compiled-python-files ) 138 # 139 # Deleting the orphaned .pyc file prior to importing, however, would 140 # cause an ImportError to occur on import as desired. 141 for dir_to_clean in dirs: 142 _log.debug("Cleaning orphaned *.pyc files from: %s" % dir_to_clean) 143 for dir_path, dir_names, file_names in os.walk(dir_to_clean): 144 for file_name in file_names: 145 if file_name.endswith(".pyc") and file_name[:-1] not in file_names: 146 file_path = os.path.join(dir_path, file_name) 147 _log.info("Deleting orphan *.pyc file: %s" % file_path) 148 os.remove(file_path) 149 150 def _find_under(self, dir_to_search, suffix): 151 """Return a list of paths to all files under dir_to_search ending in suffix.""" 152 paths = [] 153 for dir_path, dir_names, file_names in os.walk(dir_to_search): 45 154 for file_name in file_names: 46 if not file_name.endswith(suffix): 47 continue 48 unittest_path = os.path.join(dir_path, file_name) 49 unittest_paths.append(unittest_path) 50 51 return unittest_paths 155 if file_name.endswith(suffix): 156 paths.append(os.path.join(dir_path, file_name)) 157 return paths 52 158 53 159 def _modules_from_paths(self, package_root, paths): … … 94 200 ] 95 201 96 def run_tests(self, sys_argv, external_package_paths=None): 97 """Run the unit tests in all *_unittest.py modules in webkitpy. 98 99 This method excludes "webkitpy.common.checkout.scm.scm_unittest" unless 100 the --all option is the second element of sys_argv. 101 102 Args: 103 sys_argv: A reference to sys.argv. 104 105 """ 106 if external_package_paths is None: 107 external_package_paths = [] 108 else: 109 # FIXME: We should consider moving webkitpy off of using "webkitpy." to prefix 110 # all includes. If we did that, then this would use path instead of dirname(path). 111 # QueueStatusServer.__init__ has a sys.path import hack due to this code. 112 sys.path.extend(set(os.path.dirname(path) for path in external_package_paths)) 113 114 if '--xml' in sys.argv: 115 sys.argv.remove('--xml') 202 def run_tests(self, argv, dirs): 203 """Run all the tests found under dirs.""" 204 # FIXME: We should consider moving webkitpy off of using "webkitpy." to prefix 205 # all includes. If we did that, then this would use path instead of dirname(path). 206 # QueueStatusServer.__init__ has a sys.path import hack due to this code. 207 sys.path.extend(set(os.path.dirname(path) for path in dirs)) 208 209 if '--xml' in argv: 210 argv.remove('--xml') 116 211 from webkitpy.thirdparty.autoinstalled.xmlrunner import XMLTestRunner 117 212 test_runner = XMLTestRunner(output='test-webkitpy-xml-reports') … … 119 214 test_runner = unittest.TextTestRunner 120 215 121 if len( sys_argv) > 1 and not sys_argv[-1].startswith("-"):216 if len(argv) > 1 and not argv[-1].startswith("-"): 122 217 # Then explicit modules or test names were provided, which 123 218 # the unittest module is equipped to handle. 124 unittest.main(argv= sys_argv, module=None, testRunner=test_runner)219 unittest.main(argv=argv, module=None, testRunner=test_runner) 125 220 # No need to return since unitttest.main() exits. 126 221 127 222 # Otherwise, auto-detect all unit tests. 128 223 129 # FIXME: This should be combined with the external_package_paths code above.130 webkitpy_dir = os.path.dirname(webkitpy.__file__)131 132 224 skip_integration_tests = False 133 if len( sys_argv) > 1 and sys.argv[1] == "--skip-integrationtests":134 sys.argv.remove("--skip-integrationtests")225 if len(argv) > 1 and argv[1] == "--skip-integrationtests": 226 argv.remove("--skip-integrationtests") 135 227 skip_integration_tests = True 136 228 137 229 modules = [] 138 for path in [webkitpy_dir] + external_package_paths:139 modules.extend(self._modules_from_paths( path, self._find_test_files(path, "_unittest.py")))230 for dir_to_search in dirs: 231 modules.extend(self._modules_from_paths(dir_to_search, self._find_under(dir_to_search, "_unittest.py"))) 140 232 if not skip_integration_tests: 141 modules.extend(self._modules_from_paths( path, self._find_test_files(path, "_integrationtest.py")))233 modules.extend(self._modules_from_paths(dir_to_search, self._find_under(dir_to_search, "_integrationtest.py"))) 142 234 modules.sort() 143 235 144 # This is a sanity check to ensure that the unit-test discovery 145 # methods are working. 236 # This is a sanity check to ensure that the unit-test discovery methods are working. 146 237 if len(modules) < 1: 147 238 raise Exception("No unit-test modules found.") … … 152 243 # FIXME: This is a hack, but I'm tired of commenting out the test. 153 244 # See https://bugs.webkit.org/show_bug.cgi?id=31818 154 if len( sys_argv) > 1 and sys.argv[1] == "--all":155 sys.argv.remove("--all")245 if len(argv) > 1 and argv[1] == "--all": 246 argv.remove("--all") 156 247 else: 157 248 excluded_module = "webkitpy.common.checkout.scm.scm_unittest" … … 167 258 __import__(module) 168 259 169 sys_argv.extend(modules)260 argv.extend(modules) 170 261 171 262 # We pass None for the module because we do not want the unittest … … 174 265 # this module.) See the loadTestsFromName() method of the 175 266 # unittest.TestLoader class for more details on this parameter. 176 unittest.main(argv= sys_argv, module=None, testRunner=test_runner)267 unittest.main(argv=argv, module=None, testRunner=test_runner)
Note: See TracChangeset
for help on using the changeset viewer.