| Viewing file:  log_test.py (14.95 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
"""Tests for certbot.log."""import logging
 import logging.handlers
 import os
 import sys
 import time
 import unittest
 
 import mock
 import six
 
 from acme import messages
 from acme.magic_typing import Optional  # pylint: disable=unused-import, no-name-in-module
 
 from certbot import compat
 from certbot import constants
 from certbot import errors
 from certbot import util
 from certbot.tests import util as test_util
 
 
 class PreArgParseSetupTest(unittest.TestCase):
 """Tests for certbot.log.pre_arg_parse_setup."""
 
 @classmethod
 def _call(cls, *args, **kwargs):  # pylint: disable=unused-argument
 from certbot.log import pre_arg_parse_setup
 return pre_arg_parse_setup()
 
 @mock.patch('certbot.log.sys')
 @mock.patch('certbot.log.pre_arg_parse_except_hook')
 @mock.patch('certbot.log.logging.getLogger')
 @mock.patch('certbot.log.util.atexit_register')
 def test_it(self, mock_register, mock_get, mock_except_hook, mock_sys):
 mock_sys.argv = ['--debug']
 mock_sys.version_info = sys.version_info
 self._call()
 
 mock_root_logger = mock_get()
 mock_root_logger.setLevel.assert_called_once_with(logging.DEBUG)
 self.assertEqual(mock_root_logger.addHandler.call_count, 2)
 
 memory_handler = None  # type: Optional[logging.handlers.MemoryHandler]
 for call in mock_root_logger.addHandler.call_args_list:
 handler = call[0][0]
 if memory_handler is None and isinstance(handler, logging.handlers.MemoryHandler):
 memory_handler = handler
 target = memory_handler.target  # type: ignore
 else:
 self.assertTrue(isinstance(handler, logging.StreamHandler))
 self.assertTrue(
 isinstance(target, logging.StreamHandler))
 
 mock_register.assert_called_once_with(logging.shutdown)
 mock_sys.excepthook(1, 2, 3)
 mock_except_hook.assert_called_once_with(
 memory_handler, 1, 2, 3, debug=True, log_path=mock.ANY)
 
 
 class PostArgParseSetupTest(test_util.ConfigTestCase):
 """Tests for certbot.log.post_arg_parse_setup."""
 
 @classmethod
 def _call(cls, *args, **kwargs):
 from certbot.log import post_arg_parse_setup
 return post_arg_parse_setup(*args, **kwargs)
 
 def setUp(self):
 super(PostArgParseSetupTest, self).setUp()
 self.config.debug = False
 self.config.max_log_backups = 1000
 self.config.quiet = False
 self.config.verbose_count = constants.CLI_DEFAULTS['verbose_count']
 self.devnull = open(os.devnull, 'w')
 
 from certbot.log import ColoredStreamHandler
 self.stream_handler = ColoredStreamHandler(six.StringIO())
 from certbot.log import MemoryHandler, TempHandler
 self.temp_handler = TempHandler()
 self.temp_path = self.temp_handler.path
 self.memory_handler = MemoryHandler(self.temp_handler)
 self.root_logger = mock.MagicMock(
 handlers=[self.memory_handler, self.stream_handler])
 
 def tearDown(self):
 self.memory_handler.close()
 self.stream_handler.close()
 self.temp_handler.close()
 self.devnull.close()
 super(PostArgParseSetupTest, self).tearDown()
 
 def test_common(self):
 with mock.patch('certbot.log.logging.getLogger') as mock_get_logger:
 mock_get_logger.return_value = self.root_logger
 except_hook_path = 'certbot.log.post_arg_parse_except_hook'
 with mock.patch(except_hook_path) as mock_except_hook:
 with mock.patch('certbot.log.sys') as mock_sys:
 mock_sys.version_info = sys.version_info
 self._call(self.config)
 
 self.root_logger.removeHandler.assert_called_once_with(
 self.memory_handler)
 self.assertTrue(self.root_logger.addHandler.called)
 self.assertTrue(os.path.exists(os.path.join(
 self.config.logs_dir, 'letsencrypt.log')))
 self.assertFalse(os.path.exists(self.temp_path))
 mock_sys.excepthook(1, 2, 3)
 mock_except_hook.assert_called_once_with(
 1, 2, 3, debug=self.config.debug, log_path=self.config.logs_dir)
 
 level = self.stream_handler.level
 if self.config.quiet:
 self.assertEqual(level, constants.QUIET_LOGGING_LEVEL)
 else:
 self.assertEqual(level, -self.config.verbose_count * 10)
 
 def test_debug(self):
 self.config.debug = True
 self.test_common()
 
 def test_quiet(self):
 self.config.quiet = True
 self.test_common()
 
 
 class SetupLogFileHandlerTest(test_util.ConfigTestCase):
 """Tests for certbot.log.setup_log_file_handler."""
 
 @classmethod
 def _call(cls, *args, **kwargs):
 from certbot.log import setup_log_file_handler
 return setup_log_file_handler(*args, **kwargs)
 
 def setUp(self):
 super(SetupLogFileHandlerTest, self).setUp()
 self.config.max_log_backups = 42
 
 @mock.patch('certbot.main.logging.handlers.RotatingFileHandler')
 def test_failure(self, mock_handler):
 mock_handler.side_effect = IOError
 
 try:
 self._call(self.config, 'test.log', '%(message)s')
 except errors.Error as err:
 self.assertTrue('--logs-dir' in str(err))
 else:  # pragma: no cover
 self.fail('Error not raised.')
 
 def test_success_with_rollover(self):
 self._test_success_common(should_rollover=True)
 
 def test_success_without_rollover(self):
 self.config.max_log_backups = 0
 self._test_success_common(should_rollover=False)
 
 def _test_success_common(self, should_rollover):
 log_file = 'test.log'
 handler, log_path = self._call(self.config, log_file, '%(message)s')
 handler.close()
 
 self.assertEqual(handler.level, logging.DEBUG)
 self.assertEqual(handler.formatter.converter, time.localtime)
 
 expected_path = os.path.join(self.config.logs_dir, log_file)
 self.assertEqual(log_path, expected_path)
 
 backup_path = os.path.join(self.config.logs_dir, log_file + '.1')
 self.assertEqual(os.path.exists(backup_path), should_rollover)
 
 @mock.patch('certbot.log.logging.handlers.RotatingFileHandler')
 def test_max_log_backups_used(self, mock_handler):
 self._call(self.config, 'test.log', '%(message)s')
 backup_count = mock_handler.call_args[1]['backupCount']
 self.assertEqual(self.config.max_log_backups, backup_count)
 
 
 class ColoredStreamHandlerTest(unittest.TestCase):
 """Tests for certbot.log.ColoredStreamHandler"""
 
 def setUp(self):
 self.stream = six.StringIO()
 self.stream.isatty = lambda: True
 self.logger = logging.getLogger()
 self.logger.setLevel(logging.DEBUG)
 
 from certbot.log import ColoredStreamHandler
 self.handler = ColoredStreamHandler(self.stream)
 self.logger.addHandler(self.handler)
 
 def tearDown(self):
 self.handler.close()
 
 def test_format(self):
 msg = 'I did a thing'
 self.logger.debug(msg)
 self.assertEqual(self.stream.getvalue(), '{0}\n'.format(msg))
 
 def test_format_and_red_level(self):
 msg = 'I did another thing'
 self.handler.red_level = logging.DEBUG
 self.logger.debug(msg)
 
 self.assertEqual(self.stream.getvalue(),
 '{0}{1}{2}\n'.format(util.ANSI_SGR_RED,
 msg,
 util.ANSI_SGR_RESET))
 
 
 class MemoryHandlerTest(unittest.TestCase):
 """Tests for certbot.log.MemoryHandler"""
 def setUp(self):
 self.logger = logging.getLogger(__name__)
 self.logger.setLevel(logging.DEBUG)
 self.msg = 'hi there'
 self.stream = six.StringIO()
 
 self.stream_handler = logging.StreamHandler(self.stream)
 from certbot.log import MemoryHandler
 self.handler = MemoryHandler(self.stream_handler)
 self.logger.addHandler(self.handler)
 
 def tearDown(self):
 self.handler.close()
 self.stream_handler.close()
 
 def test_flush(self):
 self._test_log_debug()
 self.handler.flush(force=True)
 self.assertEqual(self.stream.getvalue(), self.msg + '\n')
 
 def test_not_flushed(self):
 # By default, logging.ERROR messages and higher are flushed
 self.logger.critical(self.msg)
 self.handler.flush()
 self.assertEqual(self.stream.getvalue(), '')
 
 def test_target_reset(self):
 self._test_log_debug()
 
 new_stream = six.StringIO()
 new_stream_handler = logging.StreamHandler(new_stream)
 self.handler.setTarget(new_stream_handler)
 self.handler.flush(force=True)
 self.assertEqual(self.stream.getvalue(), '')
 self.assertEqual(new_stream.getvalue(), self.msg + '\n')
 new_stream_handler.close()
 
 def _test_log_debug(self):
 self.logger.debug(self.msg)
 
 
 class TempHandlerTest(unittest.TestCase):
 """Tests for certbot.log.TempHandler."""
 def setUp(self):
 self.closed = False
 from certbot.log import TempHandler
 self.handler = TempHandler()
 
 def tearDown(self):
 self.handler.close()
 
 def test_permissions(self):
 self.assertTrue(
 util.check_permissions(self.handler.path, 0o600, compat.os_geteuid()))
 
 def test_delete(self):
 self.handler.close()
 self.assertFalse(os.path.exists(self.handler.path))
 
 def test_no_delete(self):
 self.handler.emit(mock.MagicMock())
 self.handler.close()
 self.assertTrue(os.path.exists(self.handler.path))
 os.remove(self.handler.path)
 
 
 class PreArgParseExceptHookTest(unittest.TestCase):
 """Tests for certbot.log.pre_arg_parse_except_hook."""
 @classmethod
 def _call(cls, *args, **kwargs):
 from certbot.log import pre_arg_parse_except_hook
 return pre_arg_parse_except_hook(*args, **kwargs)
 
 @mock.patch('certbot.log.post_arg_parse_except_hook')
 def test_it(self, mock_post_arg_parse_except_hook):
 # pylint: disable=star-args
 memory_handler = mock.MagicMock()
 args = ('some', 'args',)
 kwargs = {'some': 'kwargs'}
 
 self._call(memory_handler, *args, **kwargs)
 
 mock_post_arg_parse_except_hook.assert_called_once_with(
 *args, **kwargs)
 memory_handler.flush.assert_called_once_with(force=True)
 
 
 class PostArgParseExceptHookTest(unittest.TestCase):
 """Tests for certbot.log.post_arg_parse_except_hook."""
 @classmethod
 def _call(cls, *args, **kwargs):
 from certbot.log import post_arg_parse_except_hook
 return post_arg_parse_except_hook(*args, **kwargs)
 
 def setUp(self):
 self.error_msg = 'test error message'
 self.log_path = 'foo.log'
 
 def test_base_exception(self):
 exc_type = KeyboardInterrupt
 mock_logger, output = self._test_common(exc_type, debug=False)
 self._assert_exception_logged(mock_logger.error, exc_type)
 self._assert_logfile_output(output)
 
 def test_debug(self):
 exc_type = ValueError
 mock_logger, output = self._test_common(exc_type, debug=True)
 self._assert_exception_logged(mock_logger.error, exc_type)
 self._assert_logfile_output(output)
 
 def test_custom_error(self):
 exc_type = errors.PluginError
 mock_logger, output = self._test_common(exc_type, debug=False)
 self._assert_exception_logged(mock_logger.debug, exc_type)
 self._assert_quiet_output(mock_logger, output)
 
 def test_acme_error(self):
 # Get an arbitrary error code
 acme_code = next(six.iterkeys(messages.ERROR_CODES))
 
 def get_acme_error(msg):
 """Wraps ACME errors so the constructor takes only a msg."""
 return messages.Error.with_code(acme_code, detail=msg)
 
 mock_logger, output = self._test_common(get_acme_error, debug=False)
 self._assert_exception_logged(mock_logger.debug, messages.Error)
 self._assert_quiet_output(mock_logger, output)
 self.assertFalse(messages.ERROR_PREFIX in output)
 
 def test_other_error(self):
 exc_type = ValueError
 mock_logger, output = self._test_common(exc_type, debug=False)
 self._assert_exception_logged(mock_logger.debug, exc_type)
 self._assert_quiet_output(mock_logger, output)
 
 def _test_common(self, error_type, debug):
 """Returns the mocked logger and stderr output."""
 mock_err = six.StringIO()
 
 def write_err(*args, **unused_kwargs):
 """Write error to mock_err."""
 mock_err.write(args[0])
 
 try:
 raise error_type(self.error_msg)
 except BaseException:
 exc_info = sys.exc_info()
 with mock.patch('certbot.log.logger') as mock_logger:
 mock_logger.error.side_effect = write_err
 with mock.patch('certbot.log.sys.stderr', mock_err):
 try:
 # pylint: disable=star-args
 self._call(
 *exc_info, debug=debug, log_path=self.log_path)
 except SystemExit as exit_err:
 mock_err.write(str(exit_err))
 else:  # pragma: no cover
 self.fail('SystemExit not raised.')
 
 output = mock_err.getvalue()
 return mock_logger, output
 
 def _assert_exception_logged(self, log_func, exc_type):
 self.assertTrue(log_func.called)
 call_kwargs = log_func.call_args[1]
 self.assertTrue('exc_info' in call_kwargs)
 
 actual_exc_info = call_kwargs['exc_info']
 expected_exc_info = (exc_type, mock.ANY, mock.ANY)
 self.assertEqual(actual_exc_info, expected_exc_info)
 
 def _assert_logfile_output(self, output):
 self.assertTrue('Please see the logfile' in output)
 self.assertTrue(self.log_path in output)
 
 def _assert_quiet_output(self, mock_logger, output):
 self.assertFalse(mock_logger.exception.called)
 self.assertTrue(mock_logger.debug.called)
 self.assertTrue(self.error_msg in output)
 
 
 class ExitWithLogPathTest(test_util.TempDirTestCase):
 """Tests for certbot.log.exit_with_log_path."""
 @classmethod
 def _call(cls, *args, **kwargs):
 from certbot.log import exit_with_log_path
 return exit_with_log_path(*args, **kwargs)
 
 def test_log_file(self):
 log_file = os.path.join(self.tempdir, 'test.log')
 open(log_file, 'w').close()
 
 err_str = self._test_common(log_file)
 self.assertTrue('logfiles' not in err_str)
 self.assertTrue(log_file in err_str)
 
 def test_log_dir(self):
 err_str = self._test_common(self.tempdir)
 self.assertTrue('logfiles' in err_str)
 self.assertTrue(self.tempdir in err_str)
 
 def _test_common(self, *args, **kwargs):
 try:
 self._call(*args, **kwargs)
 except SystemExit as err:
 return str(err)
 else:  # pragma: no cover
 self.fail('SystemExit was not raised.')
 
 
 if __name__ == "__main__":
 unittest.main()  # pragma: no cover
 
 |