WebKitTools/Scripts/test-webkitpy
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 #!/usr/bin/env python
       
     2 # Copyright (c) 2009 Google Inc. All rights reserved.
       
     3 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
       
     4 #
       
     5 # Redistribution and use in source and binary forms, with or without
       
     6 # modification, are permitted provided that the following conditions are
       
     7 # met:
       
     8 # 
       
     9 #     * Redistributions of source code must retain the above copyright
       
    10 # notice, this list of conditions and the following disclaimer.
       
    11 #     * Redistributions in binary form must reproduce the above
       
    12 # copyright notice, this list of conditions and the following disclaimer
       
    13 # in the documentation and/or other materials provided with the
       
    14 # distribution.
       
    15 #     * Neither the name of Google Inc. nor the names of its
       
    16 # contributors may be used to endorse or promote products derived from
       
    17 # this software without specific prior written permission.
       
    18 # 
       
    19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       
    20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       
    21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       
    22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
       
    23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       
    24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       
    25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       
    26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       
    27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    30 
       
    31 import logging
       
    32 import os
       
    33 import sys
       
    34 
       
    35 # Do not import anything from webkitpy prior to cleaning webkitpy of
       
    36 # orphaned *.pyc files.  This ensures that no orphaned *.pyc files are
       
    37 # accidentally imported during the course of this script.
       
    38 #
       
    39 # Also, do not import or execute any Python code incompatible with
       
    40 # Python 2.4 until after execution of the init() method below.
       
    41 
       
    42 
       
    43 _log = logging.getLogger("test-webkitpy")
       
    44 
       
    45 
       
    46 # Verbose logging is useful for debugging test-webkitpy code that runs
       
    47 # before the actual unit tests -- things like autoinstall downloading and
       
    48 # unit-test auto-detection logic.  This is different from verbose logging
       
    49 # of the unit tests themselves (i.e. the unittest module's --verbose flag).
       
    50 def configure_logging(is_verbose_logging):
       
    51     """Configure the root logger.
       
    52 
       
    53     Configure the root logger not to log any messages from webkitpy --
       
    54     except for messages from the autoinstall module.  Also set the
       
    55     logging level as described below.
       
    56 
       
    57     Args:
       
    58       is_verbose_logging: A boolean value of whether logging should be
       
    59                           verbose.  If this parameter is true, the logging
       
    60                           level for the handler on the root logger is set to
       
    61                           logging.DEBUG.  Otherwise, it is set to logging.INFO.
       
    62 
       
    63     """
       
    64     # Don't use the Python ternary operator here so that this method will
       
    65     # work with Python 2.4.
       
    66     if is_verbose_logging:
       
    67         logging_level = logging.DEBUG
       
    68     else:
       
    69         logging_level = logging.INFO
       
    70 
       
    71     handler = logging.StreamHandler(sys.stderr)
       
    72     # We constrain the level on the handler rather than on the root
       
    73     # logger itself.  This is probably better because the handler is
       
    74     # configured and known only to this module, whereas the root logger
       
    75     # is an object shared (and potentially modified) by many modules.
       
    76     # Modifying the handler, then, is less intrusive and less likely to
       
    77     # interfere with modifications made by other modules (e.g. in unit
       
    78     # tests).
       
    79     handler.setLevel(logging_level)
       
    80     formatter = logging.Formatter("%(name)s: %(levelname)-8s %(message)s")
       
    81     handler.setFormatter(formatter)
       
    82 
       
    83     logger = logging.getLogger()
       
    84     logger.addHandler(handler)
       
    85     logger.setLevel(logging.NOTSET)
       
    86 
       
    87     # Filter out most webkitpy messages.
       
    88     #
       
    89     # Messages can be selectively re-enabled for this script by updating
       
    90     # this method accordingly.
       
    91     def filter(record):
       
    92         """Filter out autoinstall and non-third-party webkitpy messages."""
       
    93         # FIXME: Figure out a way not to use strings here, for example by
       
    94         #        using syntax like webkitpy.test.__name__.  We want to be
       
    95         #        sure not to import any non-Python 2.4 code, though, until
       
    96         #        after the version-checking code has executed.
       
    97         if (record.name.startswith("webkitpy.common.system.autoinstall") or
       
    98             record.name.startswith("webkitpy.test")):
       
    99             return True
       
   100         if record.name.startswith("webkitpy"):
       
   101             return False
       
   102         return True
       
   103 
       
   104     testing_filter = logging.Filter()
       
   105     testing_filter.filter = filter
       
   106 
       
   107     # Display a message so developers are not mystified as to why
       
   108     # logging does not work in the unit tests.
       
   109     _log.info("Suppressing most webkitpy logging while running unit tests.")
       
   110     handler.addFilter(testing_filter)
       
   111 
       
   112 
       
   113 def _clean_pyc_files(dir_to_clean, paths_not_to_log):
       
   114     """Delete from a directory all .pyc files that have no .py file.
       
   115 
       
   116     Args:
       
   117       dir_to_clean: The path to the directory to clean.
       
   118       paths_not_to_log: A list of paths to .pyc files whose deletions should
       
   119                         not be logged.  This list should normally include
       
   120                         only test .pyc files.
       
   121 
       
   122     """
       
   123     _log.debug("Cleaning orphaned *.pyc files from: %s" % dir_to_clean)
       
   124 
       
   125     # Normalize paths not to log.
       
   126     paths_not_to_log = [os.path.abspath(path) for path in paths_not_to_log]
       
   127 
       
   128     for dir_path, dir_names, file_names in os.walk(dir_to_clean):
       
   129         for file_name in file_names:
       
   130             if file_name.endswith(".pyc") and file_name[:-1] not in file_names:
       
   131                 file_path = os.path.join(dir_path, file_name)
       
   132                 if os.path.abspath(file_path) not in paths_not_to_log:
       
   133                     _log.info("Deleting orphan *.pyc file: %s" % file_path)
       
   134                 os.remove(file_path)
       
   135 
       
   136 
       
   137 # As a substitute for a unit test, this method tests _clean_pyc_files()
       
   138 # in addition to calling it.  We chose not to use the unittest module
       
   139 # because _clean_pyc_files() is called only once and is not used elsewhere.
       
   140 def _clean_webkitpy_with_test():
       
   141     webkitpy_dir = os.path.join(os.path.dirname(__file__), "webkitpy")
       
   142 
       
   143     # The test .pyc file is--
       
   144     # webkitpy/python24/TEMP_test-webkitpy_test_pyc_file.pyc.
       
   145     test_path = os.path.join(webkitpy_dir, "python24",
       
   146                              "TEMP_test-webkitpy_test_pyc_file.pyc")
       
   147 
       
   148     test_file = open(test_path, "w")
       
   149     try:
       
   150         test_file.write("Test .pyc file generated by test-webkitpy.")
       
   151     finally:
       
   152         test_file.close()
       
   153 
       
   154     # Confirm that the test file exists so that when we check that it does
       
   155     # not exist, the result is meaningful.
       
   156     if not os.path.exists(test_path):
       
   157         raise Exception("Test .pyc file not created: %s" % test_path)
       
   158 
       
   159     _clean_pyc_files(webkitpy_dir, [test_path])
       
   160 
       
   161     if os.path.exists(test_path):
       
   162         raise Exception("Test .pyc file not deleted: %s" % test_path)
       
   163 
       
   164 
       
   165 def init(command_args):
       
   166     """Execute code prior to importing from webkitpy.unittests.
       
   167 
       
   168     Args:
       
   169         command_args: The list of command-line arguments -- usually
       
   170                       sys.argv[1:].
       
   171 
       
   172     """
       
   173     verbose_logging_flag = "--verbose-logging"
       
   174     is_verbose_logging = verbose_logging_flag in command_args
       
   175     if is_verbose_logging:
       
   176         # Remove the flag so it doesn't cause unittest.main() to error out.
       
   177         #
       
   178         # FIXME: Get documentation for the --verbose-logging flag to show
       
   179         #        up in the usage instructions, which are currently generated
       
   180         #        by unittest.main().  It's possible that this will require
       
   181         #        re-implementing the option parser for unittest.main()
       
   182         #        since there may not be an easy way to modify its existing
       
   183         #        option parser.
       
   184         sys.argv.remove(verbose_logging_flag)
       
   185 
       
   186     configure_logging(is_verbose_logging)
       
   187     _log.debug("Verbose WebKit logging enabled.")
       
   188 
       
   189     # We clean orphaned *.pyc files from webkitpy prior to importing from
       
   190     # webkitpy to make sure that no import statements falsely succeed.
       
   191     # This helps to check that import statements have been updated correctly
       
   192     # after any file moves.  Otherwise, incorrect import statements can
       
   193     # be masked.
       
   194     #
       
   195     # For example, if webkitpy/python24/versioning.py were moved to a
       
   196     # different location without changing any import statements, and if
       
   197     # the corresponding .pyc file were left behind without deleting it,
       
   198     # then "import webkitpy.python24.versioning" would continue to succeed
       
   199     # even though it would fail for someone checking out a fresh copy
       
   200     # of the source tree.  This is because of a Python feature:
       
   201     #
       
   202     # "It is possible to have a file called spam.pyc (or spam.pyo when -O
       
   203     # is used) without a file spam.py for the same module. This can be used
       
   204     # to distribute a library of Python code in a form that is moderately
       
   205     # hard to reverse engineer."
       
   206     #
       
   207     # ( http://docs.python.org/tutorial/modules.html#compiled-python-files )
       
   208     #
       
   209     # Deleting the orphaned .pyc file prior to importing, however, would
       
   210     # cause an ImportError to occur on import as desired.
       
   211     _clean_webkitpy_with_test()
       
   212 
       
   213     import webkitpy.python24.versioning as versioning
       
   214 
       
   215     versioning.check_version(log=_log)
       
   216 
       
   217     (comparison, current_version, minimum_version) = \
       
   218         versioning.compare_version()
       
   219 
       
   220     if comparison > 0:
       
   221         # Then the current version is later than the minimum version.
       
   222         message = ("You are testing webkitpy with a Python version (%s) "
       
   223                    "higher than the minimum version (%s) it was meant "
       
   224                    "to support." % (current_version, minimum_version))
       
   225         _log.warn(message)
       
   226 
       
   227 
       
   228 if __name__ == "__main__":
       
   229 
       
   230     init(sys.argv[1:])
       
   231 
       
   232     # We import the unit test code after init() to ensure that any
       
   233     # Python version warnings are displayed in case an error occurs
       
   234     # while interpreting webkitpy.unittests.  This also allows
       
   235     # logging to be configured prior to importing -- for example to
       
   236     # enable the display of autoinstall logging.log messages while
       
   237     # running the unit tests.
       
   238     from webkitpy.test.main import Tester
       
   239 
       
   240     Tester().run_tests(sys.argv)