[SCM] WebKit Debian packaging branch, webkit-1.2, updated. upstream/1.1.90-6072-g9a69373

cjerdonek at webkit.org cjerdonek at webkit.org
Thu Apr 8 02:18:41 UTC 2010


The following commit has been merged in the webkit-1.2 branch:
commit dce1e75dcdfa38bd9bcc43bc03af21f4d062b957
Author: cjerdonek at webkit.org <cjerdonek at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Wed Mar 10 18:31:32 2010 +0000

    Refactored and cleaned up the code for unit-testing logging.
    
    Reviewed by Shinichiro Hamaji.
    
    https://bugs.webkit.org/show_bug.cgi?id=35845
    
    * Scripts/webkitpy/init/logtesting.py:
      - Added more information to the module docstring.
      - Added an assertMessages() method to the UnitTestLogStream
        class.  This simplifies the calling code.
      - Renamed the UnitTestLog class to LogTesting, and reformulated
        it as follows:
          - Moved the logging configuration code from the __init__
            method to a new static setUp() method.
          - Documented the __init__ method to be private.
          - Improved the code so that the root logger does not have
            its logging level changed.  Instead we set the handler's
            level.  This makes the unit testing more unintrusive.
          - Updated the assertMessages() method to call the
            UnitTestLogStream class's assertMessages() method.
          - More fully documented the class.
    
    * Scripts/webkitpy/style/checker.py:
      - Added a logger parameter to the configure_logging() method.
        This allows us to prevent test messages from being sent
        to the root logger during unit testing, which may be
        rendering to the screen, etc.
      - Simplified the code by removing the _LevelLoggingFilter class.
      - Replaced the _LevelLoggingFilter class with a one-line lambda
        expression in configure_logging().
    
    * Scripts/webkitpy/style/checker_unittest.py:
      - Changed relative imports to absolute to comply more with PEP8.
      - In the ConfigureLoggingTest class:
        - Changed the setUp() method to prevent test messages from
          being propagated to the root logger.
        - Changed the _log() method to a data attribute.
        - Updated to accommodate changes to logtesting.py.
    
    * Scripts/webkitpy/style_references.py:
      - Updated an import statement.
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@55786 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog
index 519d465..d352274 100644
--- a/WebKitTools/ChangeLog
+++ b/WebKitTools/ChangeLog
@@ -1,3 +1,47 @@
+2010-03-10  Chris Jerdonek  <cjerdonek at webkit.org>
+
+        Reviewed by Shinichiro Hamaji.
+
+        Refactored and cleaned up the code for unit-testing logging.
+
+        https://bugs.webkit.org/show_bug.cgi?id=35845
+
+        * Scripts/webkitpy/init/logtesting.py:
+          - Added more information to the module docstring.
+          - Added an assertMessages() method to the UnitTestLogStream
+            class.  This simplifies the calling code.
+          - Renamed the UnitTestLog class to LogTesting, and reformulated
+            it as follows:
+              - Moved the logging configuration code from the __init__
+                method to a new static setUp() method.
+              - Documented the __init__ method to be private.
+              - Improved the code so that the root logger does not have
+                its logging level changed.  Instead we set the handler's
+                level.  This makes the unit testing more unintrusive.
+              - Updated the assertMessages() method to call the
+                UnitTestLogStream class's assertMessages() method.
+              - More fully documented the class.
+
+        * Scripts/webkitpy/style/checker.py:
+          - Added a logger parameter to the configure_logging() method.
+            This allows us to prevent test messages from being sent
+            to the root logger during unit testing, which may be
+            rendering to the screen, etc.
+          - Simplified the code by removing the _LevelLoggingFilter class.
+          - Replaced the _LevelLoggingFilter class with a one-line lambda
+            expression in configure_logging().
+
+        * Scripts/webkitpy/style/checker_unittest.py:
+          - Changed relative imports to absolute to comply more with PEP8.
+          - In the ConfigureLoggingTest class:
+            - Changed the setUp() method to prevent test messages from
+              being propagated to the root logger.
+            - Changed the _log() method to a data attribute.
+            - Updated to accommodate changes to logtesting.py.
+
+        * Scripts/webkitpy/style_references.py:
+          - Updated an import statement.
+
 2010-03-10  Evan Martin  <evan at chromium.org>
 
         Reviewed by Darin Adler.
diff --git a/WebKitTools/Scripts/webkitpy/init/logtesting.py b/WebKitTools/Scripts/webkitpy/init/logtesting.py
index 6363115..10d00e4 100644
--- a/WebKitTools/Scripts/webkitpy/init/logtesting.py
+++ b/WebKitTools/Scripts/webkitpy/init/logtesting.py
@@ -20,7 +20,16 @@
 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-"""Supports the unit-testing of logging."""
+"""Supports the unit-testing of logging code.
+
+Provides support for unit-testing messages logged using the built-in
+logging module.
+
+Use the LogTesting class for basic testing needs.  For more advanced
+needs (e.g. unit-testing methods that configure logging), see the
+UnitTestLogStream class.
+
+"""
 
 import logging
 
@@ -30,93 +39,141 @@ class UnitTestLogStream(object):
     """Represents a file-like object for unit-testing logging.
 
     This is meant for passing to the logging.StreamHandler constructor.
+    Log messages captured by instances of this object can be tested
+    using self.assertMessages() below.
 
     """
 
-    def __init__(self):
+    def __init__(self, test_case):
+        """Create an instance.
+
+        Args:
+          test_case: A unittest.TestCase instance.
+
+        """
+        self._test_case = test_case
         self.messages = []
         """A list of log messages written to the stream."""
 
+    # Python documentation says that any object passed to the StreamHandler
+    # constructor should support write() and flush():
+    #
+    # http://docs.python.org/library/logging.html#module-logging.handlers
     def write(self, message):
         self.messages.append(message)
 
     def flush(self):
         pass
 
+    def assertMessages(self, messages):
+        """Assert that the given messages match the logged messages.
 
-class UnitTestLog(object):
+        messages: A list of log message strings.
 
-    """Supports unit-testing logging.
+        """
+        self._test_case.assertEquals(messages, self.messages)
+
+
+class LogTesting(object):
+
+    """Supports end-to-end unit-testing of log messages.
+
+        Sample usage:
 
-    Sample usage:
+          class SampleTest(unittest.TestCase):
 
-    # The following line should go in the setUp() method of a
-    # unittest.TestCase.  In particular, self is a TestCase instance.
-    self._log = UnitTestLog(self)
+              def setUp(self):
+                  self._log = LogTesting.setUp(self)  # Turn logging on.
 
-    # Call the following in a test method of a unittest.TestCase.
-    log = logging.getLogger("webkitpy")
-    log.info("message1")
-    log.warn("message2")
-    self._log.assertMessages(["INFO: message1\n",
-                              "WARN: message2\n"])  # Should succeed.
+              def tearDown(self):
+                  self._log.tearDown()  # Turn off and reset logging.
 
-    # The following line should go in the tearDown() method of
-    # unittest.TestCase.
-    self._log.tearDown()
+              def test_logging_in_some_method(self):
+                  call_some_method()  # Contains calls to _log.info(), etc.
+
+                  # Check the resulting log messages.
+                  self._log.assertMessages(["INFO: expected message #1",
+                                          "WARNING: expected message #2"])
 
     """
 
-    def __init__(self, test_case, logging_level=None):
-        """Configure unit test logging, and return an instance.
+    def __init__(self, test_stream, handler):
+        """Create an instance.
+
+        This method should never be called directly.  Instances should
+        instead be created using the static setUp() method.
+
+        Args:
+          test_stream: A UnitTestLogStream instance.
+          handler: The handler added to the logger.
+
+        """
+        self._test_stream = test_stream
+        self._handler = handler
+
+    @staticmethod
+    def _getLogger():
+        """Return the logger being tested."""
+        # It is possible we might want to return something other than
+        # the root logger in some special situation.  For now, the
+        # root logger seems to suffice.
+        return logging.getLogger()
+
+    @staticmethod
+    def setUp(test_case, logging_level=logging.INFO):
+        """Configure logging for unit testing.
 
-        This method configures the root logger to log to a testing
-        log stream.  Only messages logged at or above the given level
-        are logged to the stream.  Messages are formatted in the
-        following way, for example--
+        Configures the root logger to log to a testing log stream.
+        Only messages logged at or above the given level are logged
+        to the stream.  Messages logged to the stream are formatted
+        in the following way, for example--
 
         "INFO: This is a test log message."
 
         This method should normally be called in the setUp() method
-        of a unittest.TestCase.
+        of a unittest.TestCase.  See the docstring of this class
+        for more details.
+
+        Returns:
+          A LogTesting instance.
 
         Args:
           test_case: A unittest.TestCase instance.
-          logging_level: A logging level.  Only messages logged at or
-                         above this level are written to the testing
-                         log stream.  Defaults to logging.INFO.
+          logging_level: An integer logging level that is the minimum level
+                         of log messages you would like to test.
 
         """
-        if logging_level is None:
-            logging_level = logging.INFO
-
-        stream = UnitTestLogStream()
+        stream = UnitTestLogStream(test_case)
         handler = logging.StreamHandler(stream)
+        handler.setLevel(logging_level)
         formatter = logging.Formatter("%(levelname)s: %(message)s")
         handler.setFormatter(formatter)
 
-        logger = logging.getLogger()
-        logger.setLevel(logging_level)
+        # Notice that we only change the root logger by adding a handler
+        # to it.  In particular, we do not reset its level using
+        # logger.setLevel().  This ensures that we have not interfered
+        # with how the code being tested may have configured the root
+        # logger.
+        logger = LogTesting._getLogger()
         logger.addHandler(handler)
 
-        self._handler = handler
-        self._messages = stream.messages
-        self._test_case = test_case
-
-    def _logger(self):
-        """Return the root logger used for logging."""
-        return logging.getLogger()
-
-    def assertMessages(self, messages):
-        """Assert that the given messages match the logged messages."""
-        self._test_case.assertEquals(messages, self._messages)
+        return LogTesting(stream, handler)
 
     def tearDown(self):
-        """Unconfigure unit test logging.
+        """Restore logging to its original state.
 
-        This should normally be called in the tearDown method of a
-        unittest.TestCase
+        This should normally be called in the tearDown() method of a
+        unittest.TestCase.  See the docstring of this class for more
+        details.
 
         """
-        logger = self._logger()
+        logger = LogTesting._getLogger()
         logger.removeHandler(self._handler)
+
+    def assertMessages(self, messages):
+        """Assert that the given messages match the logged messages.
+
+        messages: A list of log message strings.
+
+        """
+        self._test_stream.assertMessages(messages)
diff --git a/WebKitTools/Scripts/webkitpy/style/checker.py b/WebKitTools/Scripts/webkitpy/style/checker.py
index 92d65d3..f8ba4f5 100644
--- a/WebKitTools/Scripts/webkitpy/style/checker.py
+++ b/WebKitTools/Scripts/webkitpy/style/checker.py
@@ -230,12 +230,12 @@ def check_webkit_style_configuration(options):
 #        This can use a formatter like the following, for example--
 #
 #        formatter = logging.Formatter("%(name)s: [%(levelname)s] %(message)s")
-def configure_logging(stream):
+def configure_logging(stream, logger=None):
     """Configure logging, and return the list of handlers added.
 
-    Configures the root logger to log INFO messages and higher.
-    Formats WARNING messages and above to display the logging level
-    and messages strictly below WARNING not to display it.
+    Configures a logger to log INFO messages and higher.  Formats WARNING
+    messages and above to display the logging level, and messages strictly
+    below WARNING not to display it.
 
     Returns:
       A list of references to the logging handlers added to the root
@@ -248,6 +248,9 @@ def configure_logging(stream):
       stream: A file-like object to which to log.  The stream must
               define an "encoding" data attribute, or else logging
               raises an error.
+      logger: A logging.logger instance to configure.  This parameter
+              should be used only in unit tests.  Defaults to the
+              root logger.
 
     """
     # If the stream does not define an "encoding" data attribute, the
@@ -265,14 +268,19 @@ def configure_logging(stream):
     formatter = logging.Formatter("%(levelname)s: %(message)s")
     error_handler.setFormatter(formatter)
 
-    # Handles records strictly below logging.WARNING.
+    # Create a logging.Filter instance that only accepts messages
+    # below WARNING (i.e. filters out anything WARNING or above).
+    non_error_filter = logging.Filter()
+    # The filter method accepts a logging.LogRecord instance.
+    non_error_filter.filter = lambda record: record.levelno < logging.WARNING
+
     non_error_handler = logging.StreamHandler(stream)
-    non_error_filter = _LevelLoggingFilter(logging.WARNING)
     non_error_handler.addFilter(non_error_filter)
     formatter = logging.Formatter("%(message)s")
     non_error_handler.setFormatter(formatter)
 
-    logger = logging.getLogger()
+    if logger is None:
+        logger = logging.getLogger()
     logger.setLevel(logging.INFO)
 
     handlers = [error_handler, non_error_handler]
@@ -283,31 +291,6 @@ def configure_logging(stream):
     return handlers
 
 
-# FIXME: Consider moving this class into a module in webkitpy.init after
-#        getting more experience with its use.  We want to make sure
-#        we have the right API before doing so.  For example, we may
-#        want to provide a constructor that has both upper and lower
-#        bounds, and not just an upper bound.
-class _LevelLoggingFilter(object):
-
-    """A logging filter for blocking records at or above a certain level."""
-
-    def __init__(self, logging_level):
-        """Create a _LevelLoggingFilter.
-
-        Args:
-          logging_level: The logging level cut-off.  Logging levels at
-                         or above this level will not be logged.
-
-        """
-        self._logging_level = logging_level
-
-    # The logging module requires that this method be defined.
-    def filter(self, log_record):
-        """Return whether given the LogRecord should be logged."""
-        return log_record.levelno < self._logging_level
-
-
 # Enum-like idiom
 class FileType:
 
diff --git a/WebKitTools/Scripts/webkitpy/style/checker_unittest.py b/WebKitTools/Scripts/webkitpy/style/checker_unittest.py
index d866663..06bb191 100755
--- a/WebKitTools/Scripts/webkitpy/style/checker_unittest.py
+++ b/WebKitTools/Scripts/webkitpy/style/checker_unittest.py
@@ -38,8 +38,8 @@ import logging
 import unittest
 
 import checker as style
-from ..style_references import UnitTestLog
-from ..style_references import UnitTestLogStream
+from webkitpy.style_references import LogTesting
+from webkitpy.style_references import UnitTestLogStream
 from checker import _BASE_FILTER_RULES
 from checker import _MAX_REPORTS_PER_CATEGORY
 from checker import _PATH_RULES_SPECIFIER as PATH_RULES_SPECIFIER
@@ -63,9 +63,19 @@ class ConfigureLoggingTest(unittest.TestCase):
     """Tests the configure_logging() function."""
 
     def setUp(self):
-        log_stream = UnitTestLogStream()
-
-        self._handlers = configure_logging(log_stream)
+        log_stream = UnitTestLogStream(self)
+        # Use a logger other than the root logger or one prefixed with
+        # webkit so as not to conflict with test-webkitpy logging.
+        logger = logging.getLogger("unittest")
+
+        # Configure the test logger not to pass messages along to the
+        # root logger.  This prevents test messages from being
+        # propagated to loggers used by test-webkitpy logging (e.g.
+        # the root logger).
+        logger.propagate = False
+
+        self._handlers = configure_logging(log_stream, logger)
+        self._log = logger
         self._log_stream = log_stream
 
     def tearDown(self):
@@ -75,21 +85,16 @@ class ConfigureLoggingTest(unittest.TestCase):
         for a unit test does not affect logging in other unit tests.
 
         """
-        # This should be the same as the logger configured in the
-        # configure_logging() method.
-        logger = logging.getLogger()
+        logger = self._log
         for handler in self._handlers:
             logger.removeHandler(handler)
 
-    def _log(self):
-        return logging.getLogger("webkitpy")
-
     def assert_log_messages(self, messages):
         """Assert that the logged messages equal the given messages."""
-        self.assertEquals(messages, self._log_stream.messages)
+        self._log_stream.assertMessages(messages)
 
     def test_warning_message(self):
-        self._log().warn("test message")
+        self._log.warn("test message")
         self.assert_log_messages(["WARNING: test message\n"])
 
     def test_below_warning_message(self):
@@ -97,16 +102,16 @@ class ConfigureLoggingTest(unittest.TestCase):
         # In practice, we will probably only be calling log.info(),
         # which corresponds to a logging level of 20.
         level = logging.WARNING - 1  # Equals 29.
-        self._log().log(level, "test message")
+        self._log.log(level, "test message")
         self.assert_log_messages(["test message\n"])
 
     def test_debug_message(self):
-        self._log().debug("test message")
+        self._log.debug("test message")
         self.assert_log_messages([])
 
     def test_two_messages(self):
-        self._log().info("message1")
-        self._log().info("message2")
+        self._log.info("message1")
+        self._log.info("message2")
         self.assert_log_messages(["message1\n", "message2\n"])
 
 
@@ -502,7 +507,7 @@ class StyleCheckerCheckFileTest(unittest.TestCase):
 
     """
     def setUp(self):
-        self._log = UnitTestLog(self)
+        self._log = LogTesting.setUp(self)
         self.got_file_path = None
         self.got_handle_style_error = None
         self.got_processor = None
diff --git a/WebKitTools/Scripts/webkitpy/style_references.py b/WebKitTools/Scripts/webkitpy/style_references.py
index cb8a985..e57cd0e 100644
--- a/WebKitTools/Scripts/webkitpy/style_references.py
+++ b/WebKitTools/Scripts/webkitpy/style_references.py
@@ -41,7 +41,7 @@
 import os
 
 from diff_parser import DiffParser
-from init.logtesting import UnitTestLog
+from init.logtesting import LogTesting
 from init.logtesting import UnitTestLogStream
 from scm import detect_scm_system
 

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list