Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(249106)

Delta Between Two Patch Sets: Lib/test/test_logging.py

Issue 16510: Using appropriate checks in tests
Left Patch Set: Created 5 years, 11 months ago
Right Patch Set: Created 5 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Lib/test/test_kqueue.py ('k') | Lib/test/test_memoryview.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 #!/usr/bin/env python 1 # Copyright 2001-2013 by Vinay Sajip. All Rights Reserved.
2 #
3 # Copyright 2001-2012 by Vinay Sajip. All Rights Reserved.
4 # 2 #
5 # Permission to use, copy, modify, and distribute this software and its 3 # Permission to use, copy, modify, and distribute this software and its
6 # documentation for any purpose and without fee is hereby granted, 4 # documentation for any purpose and without fee is hereby granted,
7 # provided that the above copyright notice appear in all copies and that 5 # provided that the above copyright notice appear in all copies and that
8 # both that copyright notice and this permission notice appear in 6 # both that copyright notice and this permission notice appear in
9 # supporting documentation, and that the name of Vinay Sajip 7 # supporting documentation, and that the name of Vinay Sajip
10 # not be used in advertising or publicity pertaining to distribution 8 # not be used in advertising or publicity pertaining to distribution
11 # of the software without specific, written prior permission. 9 # of the software without specific, written prior permission.
12 # VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 10 # VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
13 # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 11 # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14 # VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 12 # VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
15 # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 13 # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
16 # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 14 # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 16
19 """Test harness for the logging module. Run all tests. 17 """Test harness for the logging module. Run all tests.
20 18
21 Copyright (C) 2001-2012 Vinay Sajip. All Rights Reserved. 19 Copyright (C) 2001-2013 Vinay Sajip. All Rights Reserved.
22 """ 20 """
23 21
24 import logging 22 import logging
25 import logging.handlers 23 import logging.handlers
26 import logging.config 24 import logging.config
27 25
28 import codecs 26 import codecs
29 import configparser 27 import configparser
30 import datetime 28 import datetime
31 import pickle 29 import pickle
32 import io 30 import io
33 import gc 31 import gc
34 import json 32 import json
35 import os 33 import os
36 import queue 34 import queue
37 import random 35 import random
38 import re 36 import re
39 import select 37 import select
40 import socket 38 import socket
41 import struct 39 import struct
42 import sys 40 import sys
43 import tempfile 41 import tempfile
42 from test.script_helper import assert_python_ok
44 from test.support import (captured_stdout, run_with_locale, run_unittest, 43 from test.support import (captured_stdout, run_with_locale, run_unittest,
45 patch, requires_zlib, TestHandler, Matcher) 44 patch, requires_zlib, TestHandler, Matcher)
46 import textwrap 45 import textwrap
47 import time 46 import time
48 import unittest 47 import unittest
49 import warnings 48 import warnings
50 import weakref 49 import weakref
51 try: 50 try:
52 import threading 51 import threading
53 # The following imports are needed only for tests which 52 # The following imports are needed only for tests which
54 # require threading 53 # require threading
55 import asynchat 54 import asynchat
56 import asyncore 55 import asyncore
57 import errno 56 import errno
58 from http.server import HTTPServer, BaseHTTPRequestHandler 57 from http.server import HTTPServer, BaseHTTPRequestHandler
59 import smtpd 58 import smtpd
60 from urllib.parse import urlparse, parse_qs 59 from urllib.parse import urlparse, parse_qs
61 from socketserver import (ThreadingUDPServer, DatagramRequestHandler, 60 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
62 ThreadingTCPServer, StreamRequestHandler) 61 ThreadingTCPServer, StreamRequestHandler,
62 ThreadingUnixStreamServer,
63 ThreadingUnixDatagramServer)
63 except ImportError: 64 except ImportError:
64 threading = None 65 threading = None
65 try: 66 try:
66 import win32evtlog 67 import win32evtlog
67 except ImportError: 68 except ImportError:
68 win32evtlog = None 69 win32evtlog = None
69 try: 70 try:
70 import win32evtlogutil 71 import win32evtlogutil
71 except ImportError: 72 except ImportError:
72 win32evtlogutil = None 73 win32evtlogutil = None
73 win32evtlog = None 74 win32evtlog = None
74 try: 75 try:
75 import zlib 76 import zlib
76 except ImportError: 77 except ImportError:
77 pass 78 pass
78 79
79
80 class BaseTest(unittest.TestCase): 80 class BaseTest(unittest.TestCase):
81 81
82 """Base class for logging tests.""" 82 """Base class for logging tests."""
83 83
84 log_format = "%(name)s -> %(levelname)s: %(message)s" 84 log_format = "%(name)s -> %(levelname)s: %(message)s"
85 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$" 85 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
86 message_num = 0 86 message_num = 0
87 87
88 def setUp(self): 88 def setUp(self):
89 """Setup the default logging stream to an internal StringIO instance, 89 """Setup the default logging stream to an internal StringIO instance,
90 so that we can examine log output as we want.""" 90 so that we can examine log output as we want."""
91 logger_dict = logging.getLogger().manager.loggerDict 91 logger_dict = logging.getLogger().manager.loggerDict
92 logging._acquireLock() 92 logging._acquireLock()
93 try: 93 try:
94 self.saved_handlers = logging._handlers.copy() 94 self.saved_handlers = logging._handlers.copy()
95 self.saved_handler_list = logging._handlerList[:] 95 self.saved_handler_list = logging._handlerList[:]
96 self.saved_loggers = saved_loggers = logger_dict.copy() 96 self.saved_loggers = saved_loggers = logger_dict.copy()
97 self.saved_level_names = logging._levelNames.copy() 97 self.saved_name_to_level = logging._nameToLevel.copy()
98 self.saved_level_to_name = logging._levelToName.copy()
98 self.logger_states = logger_states = {} 99 self.logger_states = logger_states = {}
99 for name in saved_loggers: 100 for name in saved_loggers:
100 logger_states[name] = getattr(saved_loggers[name], 101 logger_states[name] = getattr(saved_loggers[name],
101 'disabled', None) 102 'disabled', None)
102 finally: 103 finally:
103 logging._releaseLock() 104 logging._releaseLock()
104 105
105 # Set two unused loggers 106 # Set two unused loggers
106 self.logger1 = logging.getLogger("\xab\xd7\xbb") 107 self.logger1 = logging.getLogger("\xab\xd7\xbb")
107 self.logger2 = logging.getLogger("\u013f\u00d6\u0047") 108 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
(...skipping 21 matching lines...) Expand all
129 level.""" 130 level."""
130 self.stream.close() 131 self.stream.close()
131 self.root_logger.removeHandler(self.root_hdlr) 132 self.root_logger.removeHandler(self.root_hdlr)
132 while self.root_logger.handlers: 133 while self.root_logger.handlers:
133 h = self.root_logger.handlers[0] 134 h = self.root_logger.handlers[0]
134 self.root_logger.removeHandler(h) 135 self.root_logger.removeHandler(h)
135 h.close() 136 h.close()
136 self.root_logger.setLevel(self.original_logging_level) 137 self.root_logger.setLevel(self.original_logging_level)
137 logging._acquireLock() 138 logging._acquireLock()
138 try: 139 try:
139 logging._levelNames.clear() 140 logging._levelToName.clear()
140 logging._levelNames.update(self.saved_level_names) 141 logging._levelToName.update(self.saved_level_to_name)
142 logging._nameToLevel.clear()
143 logging._nameToLevel.update(self.saved_name_to_level)
141 logging._handlers.clear() 144 logging._handlers.clear()
142 logging._handlers.update(self.saved_handlers) 145 logging._handlers.update(self.saved_handlers)
143 logging._handlerList[:] = self.saved_handler_list 146 logging._handlerList[:] = self.saved_handler_list
144 loggerDict = logging.getLogger().manager.loggerDict 147 loggerDict = logging.getLogger().manager.loggerDict
145 loggerDict.clear() 148 loggerDict.clear()
146 loggerDict.update(self.saved_loggers) 149 loggerDict.update(self.saved_loggers)
147 logger_states = self.logger_states 150 logger_states = self.logger_states
148 for name in self.logger_states: 151 for name in self.logger_states:
149 if logger_states[name] is not None: 152 if logger_states[name] is not None:
150 self.saved_loggers[name].disabled = logger_states[name] 153 self.saved_loggers[name].disabled = logger_states[name]
151 finally: 154 finally:
152 logging._releaseLock() 155 logging._releaseLock()
153 156
154 def assert_log_lines(self, expected_values, stream=None, pat=None): 157 def assert_log_lines(self, expected_values, stream=None, pat=None):
155 """Match the collected log lines against the regular expression 158 """Match the collected log lines against the regular expression
156 self.expected_log_pat, and compare the extracted group values to 159 self.expected_log_pat, and compare the extracted group values to
157 the expected_values list of tuples.""" 160 the expected_values list of tuples."""
158 stream = stream or self.stream 161 stream = stream or self.stream
159 pat = re.compile(pat or self.expected_log_pat) 162 pat = re.compile(pat or self.expected_log_pat)
160 try: 163 actual_lines = stream.getvalue().splitlines()
161 if hasattr(stream, 'reset'):
162 stream.reset()
163 elif hasattr(stream, 'seek'):
164 stream.seek(0)
165 actual_lines = stream.readlines()
166 except AttributeError:
167 # StringIO.StringIO lacks a reset() method.
168 actual_lines = stream.getvalue().splitlines()
169 self.assertEqual(len(actual_lines), len(expected_values)) 164 self.assertEqual(len(actual_lines), len(expected_values))
170 for actual, expected in zip(actual_lines, expected_values): 165 for actual, expected in zip(actual_lines, expected_values):
171 match = pat.search(actual) 166 match = pat.search(actual)
172 if not match: 167 if not match:
173 self.fail("Log line does not match expected pattern:\n" + 168 self.fail("Log line does not match expected pattern:\n" +
174 actual) 169 actual)
175 self.assertEqual(tuple(match.groups()), expected) 170 self.assertEqual(tuple(match.groups()), expected)
176 s = stream.read() 171 s = stream.read()
177 if s: 172 if s:
178 self.fail("Remaining output at end of log stream:\n" + s) 173 self.fail("Remaining output at end of log stream:\n" + s)
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after
587 h.close() 582 h.close()
588 583
589 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Wi ndows.') 584 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Wi ndows.')
590 @unittest.skipUnless(threading, 'Threading required for this test.') 585 @unittest.skipUnless(threading, 'Threading required for this test.')
591 def test_race(self): 586 def test_race(self):
592 # Issue #14632 refers. 587 # Issue #14632 refers.
593 def remove_loop(fname, tries): 588 def remove_loop(fname, tries):
594 for _ in range(tries): 589 for _ in range(tries):
595 try: 590 try:
596 os.unlink(fname) 591 os.unlink(fname)
592 self.deletion_time = time.time()
597 except OSError: 593 except OSError:
598 pass 594 pass
599 time.sleep(0.004 * random.randint(0, 4)) 595 time.sleep(0.004 * random.randint(0, 4))
600 596
601 del_count = 500 597 del_count = 500
602 log_count = 500 598 log_count = 500
599
600 self.handle_time = None
601 self.deletion_time = None
603 602
604 for delay in (False, True): 603 for delay in (False, True):
605 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-') 604 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
606 os.close(fd) 605 os.close(fd)
607 remover = threading.Thread(target=remove_loop, args=(fn, del_count)) 606 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
608 remover.daemon = True 607 remover.daemon = True
609 remover.start() 608 remover.start()
610 h = logging.handlers.WatchedFileHandler(fn, delay=delay) 609 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
611 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s') 610 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
612 h.setFormatter(f) 611 h.setFormatter(f)
613 try: 612 try:
614 for _ in range(log_count): 613 for _ in range(log_count):
615 time.sleep(0.005) 614 time.sleep(0.005)
616 r = logging.makeLogRecord({'msg': 'testing' }) 615 r = logging.makeLogRecord({'msg': 'testing' })
617 h.handle(r) 616 try:
617 self.handle_time = time.time()
618 h.handle(r)
619 except Exception:
620 print('Deleted at %s, '
621 'opened at %s' % (self.deletion_time,
622 self.handle_time))
623 raise
618 finally: 624 finally:
619 remover.join() 625 remover.join()
620 h.close() 626 h.close()
621 if os.path.exists(fn): 627 if os.path.exists(fn):
622 os.unlink(fn) 628 os.unlink(fn)
623 629
624 630
625 class BadStream(object): 631 class BadStream(object):
626 def write(self, data): 632 def write(self, data):
627 raise RuntimeError('deliberate mistake') 633 raise RuntimeError('deliberate mistake')
(...skipping 21 matching lines...) Expand all
649 h.handle(r) 655 h.handle(r)
650 self.assertEqual('', sio.getvalue()) 656 self.assertEqual('', sio.getvalue())
651 finally: 657 finally:
652 logging.raiseExceptions = old_raise 658 logging.raiseExceptions = old_raise
653 sys.stderr = old_stderr 659 sys.stderr = old_stderr
654 660
655 # -- The following section could be moved into a server_helper.py module 661 # -- The following section could be moved into a server_helper.py module
656 # -- if it proves to be of wider utility than just test_logging 662 # -- if it proves to be of wider utility than just test_logging
657 663
658 if threading: 664 if threading:
659 class TestSMTPChannel(smtpd.SMTPChannel):
660 """
661 This derived class has had to be created because smtpd does not
662 support use of custom channel maps, although they are allowed by
663 asyncore's design. Issue #11959 has been raised to address this,
664 and if resolved satisfactorily, some of this code can be removed.
665 """
666 def __init__(self, server, conn, addr, sockmap):
667 asynchat.async_chat.__init__(self, conn, sockmap)
668 self.smtp_server = server
669 self.conn = conn
670 self.addr = addr
671 self.data_size_limit = None
672 self.received_lines = []
673 self.smtp_state = self.COMMAND
674 self.seen_greeting = ''
675 self.mailfrom = None
676 self.rcpttos = []
677 self.received_data = ''
678 self.fqdn = socket.getfqdn()
679 self.num_bytes = 0
680 try:
681 self.peer = conn.getpeername()
682 except OSError as err:
683 # a race condition may occur if the other end is closing
684 # before we can get the peername
685 self.close()
686 if err.args[0] != errno.ENOTCONN:
687 raise
688 return
689 self.push('220 %s %s' % (self.fqdn, smtpd.__version__))
690 self.set_terminator(b'\r\n')
691 self.extended_smtp = False
692
693
694 class TestSMTPServer(smtpd.SMTPServer): 665 class TestSMTPServer(smtpd.SMTPServer):
695 """ 666 """
696 This class implements a test SMTP server. 667 This class implements a test SMTP server.
697 668
698 :param addr: A (host, port) tuple which the server listens on. 669 :param addr: A (host, port) tuple which the server listens on.
699 You can specify a port value of zero: the server's 670 You can specify a port value of zero: the server's
700 *port* attribute will hold the actual port number 671 *port* attribute will hold the actual port number
701 used, which can be used in client connections. 672 used, which can be used in client connections.
702 :param handler: A callable which will be called to process 673 :param handler: A callable which will be called to process
703 incoming messages. The handler will be passed 674 incoming messages. The handler will be passed
704 the client address tuple, who the message is from, 675 the client address tuple, who the message is from,
705 a list of recipients and the message data. 676 a list of recipients and the message data.
706 :param poll_interval: The interval, in seconds, used in the underlying 677 :param poll_interval: The interval, in seconds, used in the underlying
707 :func:`select` or :func:`poll` call by 678 :func:`select` or :func:`poll` call by
708 :func:`asyncore.loop`. 679 :func:`asyncore.loop`.
709 :param sockmap: A dictionary which will be used to hold 680 :param sockmap: A dictionary which will be used to hold
710 :class:`asyncore.dispatcher` instances used by 681 :class:`asyncore.dispatcher` instances used by
711 :func:`asyncore.loop`. This avoids changing the 682 :func:`asyncore.loop`. This avoids changing the
712 :mod:`asyncore` module's global state. 683 :mod:`asyncore` module's global state.
713 """ 684 """
714 channel_class = TestSMTPChannel
715 685
716 def __init__(self, addr, handler, poll_interval, sockmap): 686 def __init__(self, addr, handler, poll_interval, sockmap):
717 self._localaddr = addr 687 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap)
718 self._remoteaddr = None 688 self.port = self.socket.getsockname()[1]
719 self.data_size_limit = None
720 self.sockmap = sockmap
721 asyncore.dispatcher.__init__(self, map=sockmap)
722 try:
723 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
724 sock.setblocking(0)
725 self.set_socket(sock, map=sockmap)
726 # try to re-use a server port if possible
727 self.set_reuse_addr()
728 self.bind(addr)
729 self.port = sock.getsockname()[1]
730 self.listen(5)
731 except:
732 self.close()
733 raise
734 self._handler = handler 689 self._handler = handler
735 self._thread = None 690 self._thread = None
736 self.poll_interval = poll_interval 691 self.poll_interval = poll_interval
737
738 def handle_accepted(self, conn, addr):
739 """
740 Redefined only because the base class does not pass in a
741 map, forcing use of a global in :mod:`asyncore`.
742 """
743 channel = self.channel_class(self, conn, addr, self.sockmap)
744 692
745 def process_message(self, peer, mailfrom, rcpttos, data): 693 def process_message(self, peer, mailfrom, rcpttos, data):
746 """ 694 """
747 Delegates to the handler passed in to the server's constructor. 695 Delegates to the handler passed in to the server's constructor.
748 696
749 Typically, this will be a test case method. 697 Typically, this will be a test case method.
750 :param peer: The client (host, port) tuple. 698 :param peer: The client (host, port) tuple.
751 :param mailfrom: The address of the sender. 699 :param mailfrom: The address of the sender.
752 :param rcpttos: The addresses of the recipients. 700 :param rcpttos: The addresses of the recipients.
753 :param data: The message. 701 :param data: The message.
(...skipping 11 matching lines...) Expand all
765 713
766 def serve_forever(self, poll_interval): 714 def serve_forever(self, poll_interval):
767 """ 715 """
768 Run the :mod:`asyncore` loop until normal termination 716 Run the :mod:`asyncore` loop until normal termination
769 conditions arise. 717 conditions arise.
770 :param poll_interval: The interval, in seconds, used in the underlyi ng 718 :param poll_interval: The interval, in seconds, used in the underlyi ng
771 :func:`select` or :func:`poll` call by 719 :func:`select` or :func:`poll` call by
772 :func:`asyncore.loop`. 720 :func:`asyncore.loop`.
773 """ 721 """
774 try: 722 try:
775 asyncore.loop(poll_interval, map=self.sockmap) 723 asyncore.loop(poll_interval, map=self._map)
776 except OSError: 724 except OSError:
777 # On FreeBSD 8, closing the server repeatably 725 # On FreeBSD 8, closing the server repeatably
778 # raises this error. We swallow it if the 726 # raises this error. We swallow it if the
779 # server has been closed. 727 # server has been closed.
780 if self.connected or self.accepting: 728 if self.connected or self.accepting:
781 raise 729 raise
782 730
783 def stop(self, timeout=None): 731 def stop(self, timeout=None):
784 """ 732 """
785 Stop the thread by closing the server instance. 733 Stop the thread by closing the server instance.
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
909 857
910 def handle(self): 858 def handle(self):
911 self.server._handler(self) 859 self.server._handler(self)
912 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler, 860 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
913 bind_and_activate) 861 bind_and_activate)
914 ControlMixin.__init__(self, handler, poll_interval) 862 ControlMixin.__init__(self, handler, poll_interval)
915 863
916 def server_bind(self): 864 def server_bind(self):
917 super(TestTCPServer, self).server_bind() 865 super(TestTCPServer, self).server_bind()
918 self.port = self.socket.getsockname()[1] 866 self.port = self.socket.getsockname()[1]
867
868 class TestUnixStreamServer(TestTCPServer):
869 address_family = socket.AF_UNIX
919 870
920 class TestUDPServer(ControlMixin, ThreadingUDPServer): 871 class TestUDPServer(ControlMixin, ThreadingUDPServer):
921 """ 872 """
922 A UDP server which is controllable using :class:`ControlMixin`. 873 A UDP server which is controllable using :class:`ControlMixin`.
923 874
924 :param addr: A tuple with the IP address and port to listen on. 875 :param addr: A tuple with the IP address and port to listen on.
925 :param handler: A handler callable which will be called with a 876 :param handler: A handler callable which will be called with a
926 single parameter - the request - in order to 877 single parameter - the request - in order to
927 process the request. 878 process the request.
928 :param poll_interval: The polling interval for shutdown requests, 879 :param poll_interval: The polling interval for shutdown requests,
(...skipping 28 matching lines...) Expand all
957 self._closed = False 908 self._closed = False
958 909
959 def server_bind(self): 910 def server_bind(self):
960 super(TestUDPServer, self).server_bind() 911 super(TestUDPServer, self).server_bind()
961 self.port = self.socket.getsockname()[1] 912 self.port = self.socket.getsockname()[1]
962 913
963 def server_close(self): 914 def server_close(self):
964 super(TestUDPServer, self).server_close() 915 super(TestUDPServer, self).server_close()
965 self._closed = True 916 self._closed = True
966 917
918 class TestUnixDatagramServer(TestUDPServer):
919 address_family = socket.AF_UNIX
920
967 # - end of server_helper section 921 # - end of server_helper section
968 922
969 @unittest.skipUnless(threading, 'Threading required for this test.') 923 @unittest.skipUnless(threading, 'Threading required for this test.')
970 class SMTPHandlerTest(BaseTest): 924 class SMTPHandlerTest(BaseTest):
925 TIMEOUT = 8.0
971 def test_basic(self): 926 def test_basic(self):
972 sockmap = {} 927 sockmap = {}
973 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001, 928 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
974 sockmap) 929 sockmap)
975 server.start() 930 server.start()
976 addr = ('localhost', server.port) 931 addr = ('localhost', server.port)
977 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log', timeout=5.0) 932 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
933 timeout=self.TIMEOUT)
978 self.assertEqual(h.toaddrs, ['you']) 934 self.assertEqual(h.toaddrs, ['you'])
979 self.messages = [] 935 self.messages = []
980 r = logging.makeLogRecord({'msg': 'Hello'}) 936 r = logging.makeLogRecord({'msg': 'Hello'})
981 self.handled = threading.Event() 937 self.handled = threading.Event()
982 h.handle(r) 938 h.handle(r)
983 self.handled.wait(5.0) # 14314: don't wait forever 939 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
984 server.stop() 940 server.stop()
985 self.assertTrue(self.handled.is_set()) 941 self.assertTrue(self.handled.is_set())
986 self.assertEqual(len(self.messages), 1) 942 self.assertEqual(len(self.messages), 1)
987 peer, mailfrom, rcpttos, data = self.messages[0] 943 peer, mailfrom, rcpttos, data = self.messages[0]
988 self.assertEqual(mailfrom, 'me') 944 self.assertEqual(mailfrom, 'me')
989 self.assertEqual(rcpttos, ['you']) 945 self.assertEqual(rcpttos, ['you'])
990 self.assertIn('\nSubject: Log\n', data) 946 self.assertIn('\nSubject: Log\n', data)
991 self.assertTrue(data.endswith('\n\nHello')) 947 self.assertTrue(data.endswith('\n\nHello'))
992 h.close() 948 h.close()
993 949
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
1254 class=StreamHandler 1210 class=StreamHandler
1255 level=NOTSET 1211 level=NOTSET
1256 formatter=form1 1212 formatter=form1
1257 args=(sys.stdout,) 1213 args=(sys.stdout,)
1258 1214
1259 [formatter_form1] 1215 [formatter_form1]
1260 format=%(levelname)s ++ %(message)s 1216 format=%(levelname)s ++ %(message)s
1261 datefmt= 1217 datefmt=
1262 """ 1218 """
1263 1219
1264 def apply_config(self, conf): 1220 disable_test = """
1221 [loggers]
1222 keys=root
1223
1224 [handlers]
1225 keys=screen
1226
1227 [formatters]
1228 keys=
1229
1230 [logger_root]
1231 level=DEBUG
1232 handlers=screen
1233
1234 [handler_screen]
1235 level=DEBUG
1236 class=StreamHandler
1237 args=(sys.stdout,)
1238 formatter=
1239 """
1240
1241 def apply_config(self, conf, **kwargs):
1265 file = io.StringIO(textwrap.dedent(conf)) 1242 file = io.StringIO(textwrap.dedent(conf))
1266 logging.config.fileConfig(file) 1243 logging.config.fileConfig(file, **kwargs)
1267 1244
1268 def test_config0_ok(self): 1245 def test_config0_ok(self):
1269 # A simple config file which overrides the default settings. 1246 # A simple config file which overrides the default settings.
1270 with captured_stdout() as output: 1247 with captured_stdout() as output:
1271 self.apply_config(self.config0) 1248 self.apply_config(self.config0)
1272 logger = logging.getLogger() 1249 logger = logging.getLogger()
1273 # Won't output anything 1250 # Won't output anything
1274 logger.info(self.next_message()) 1251 logger.info(self.next_message())
1275 # Outputs a message 1252 # Outputs a message
1276 logger.error(self.next_message()) 1253 logger.error(self.next_message())
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1378 hyphenated.critical(self.next_message()) 1355 hyphenated.critical(self.next_message())
1379 self.assert_log_lines([ 1356 self.assert_log_lines([
1380 ('INFO', '4'), 1357 ('INFO', '4'),
1381 ('ERROR', '5'), 1358 ('ERROR', '5'),
1382 ('INFO', '6'), 1359 ('INFO', '6'),
1383 ('ERROR', '7'), 1360 ('ERROR', '7'),
1384 ], stream=output) 1361 ], stream=output)
1385 # Original logger output is empty. 1362 # Original logger output is empty.
1386 self.assert_log_lines([]) 1363 self.assert_log_lines([])
1387 1364
1365 def test_logger_disabling(self):
1366 self.apply_config(self.disable_test)
1367 logger = logging.getLogger('some_pristine_logger')
1368 self.assertFalse(logger.disabled)
1369 self.apply_config(self.disable_test)
1370 self.assertTrue(logger.disabled)
1371 self.apply_config(self.disable_test, disable_existing_loggers=False)
1372 self.assertFalse(logger.disabled)
1373
1388 1374
1389 @unittest.skipUnless(threading, 'Threading required for this test.') 1375 @unittest.skipUnless(threading, 'Threading required for this test.')
1390 class SocketHandlerTest(BaseTest): 1376 class SocketHandlerTest(BaseTest):
1391 1377
1392 """Test for SocketHandler objects.""" 1378 """Test for SocketHandler objects."""
1379
1380 if threading:
1381 server_class = TestTCPServer
1382 address = ('localhost', 0)
1393 1383
1394 def setUp(self): 1384 def setUp(self):
1395 """Set up a TCP server to receive log messages, and a SocketHandler 1385 """Set up a TCP server to receive log messages, and a SocketHandler
1396 pointing to that server's address and port.""" 1386 pointing to that server's address and port."""
1397 BaseTest.setUp(self) 1387 BaseTest.setUp(self)
1398 addr = ('localhost', 0) 1388 self.server = server = self.server_class(self.address,
1399 self.server = server = TestTCPServer(addr, self.handle_socket, 1389 self.handle_socket, 0.01)
1400 0.01)
1401 server.start() 1390 server.start()
1402 server.ready.wait() 1391 server.ready.wait()
1403 self.sock_hdlr = logging.handlers.SocketHandler('localhost', 1392 hcls = logging.handlers.SocketHandler
1404 server.port) 1393 if isinstance(server.server_address, tuple):
1394 self.sock_hdlr = hcls('localhost', server.port)
1395 else:
1396 self.sock_hdlr = hcls(server.server_address, None)
1405 self.log_output = '' 1397 self.log_output = ''
1406 self.root_logger.removeHandler(self.root_logger.handlers[0]) 1398 self.root_logger.removeHandler(self.root_logger.handlers[0])
1407 self.root_logger.addHandler(self.sock_hdlr) 1399 self.root_logger.addHandler(self.sock_hdlr)
1408 self.handled = threading.Semaphore(0) 1400 self.handled = threading.Semaphore(0)
1409 1401
1410 def tearDown(self): 1402 def tearDown(self):
1411 """Shutdown the TCP server.""" 1403 """Shutdown the TCP server."""
1412 try: 1404 try:
1413 self.server.stop(2.0) 1405 self.server.stop(2.0)
1414 self.root_logger.removeHandler(self.sock_hdlr) 1406 self.root_logger.removeHandler(self.sock_hdlr)
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1450 try: 1442 try:
1451 raise RuntimeError('Deliberate mistake') 1443 raise RuntimeError('Deliberate mistake')
1452 except RuntimeError: 1444 except RuntimeError:
1453 self.root_logger.exception('Never sent') 1445 self.root_logger.exception('Never sent')
1454 self.root_logger.error('Never sent, either') 1446 self.root_logger.error('Never sent, either')
1455 now = time.time() 1447 now = time.time()
1456 self.assertGreater(self.sock_hdlr.retryTime, now) 1448 self.assertGreater(self.sock_hdlr.retryTime, now)
1457 time.sleep(self.sock_hdlr.retryTime - now + 0.001) 1449 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1458 self.root_logger.error('Nor this') 1450 self.root_logger.error('Nor this')
1459 1451
1452 def _get_temp_domain_socket():
1453 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1454 os.close(fd)
1455 # just need a name - file can't be present, or we'll get an
1456 # 'address already in use' error.
1457 os.remove(fn)
1458 return fn
1459
1460 @unittest.skipUnless(threading, 'Threading required for this test.')
1461 class UnixSocketHandlerTest(SocketHandlerTest):
1462
1463 """Test for SocketHandler with unix sockets."""
1464
1465 if threading:
1466 server_class = TestUnixStreamServer
1467
1468 def setUp(self):
1469 # override the definition in the base class
1470 self.address = _get_temp_domain_socket()
1471 SocketHandlerTest.setUp(self)
1472
1473 def tearDown(self):
1474 SocketHandlerTest.tearDown(self)
1475 os.remove(self.address)
1460 1476
1461 @unittest.skipUnless(threading, 'Threading required for this test.') 1477 @unittest.skipUnless(threading, 'Threading required for this test.')
1462 class DatagramHandlerTest(BaseTest): 1478 class DatagramHandlerTest(BaseTest):
1463 1479
1464 """Test for DatagramHandler.""" 1480 """Test for DatagramHandler."""
1481
1482 if threading:
1483 server_class = TestUDPServer
1484 address = ('localhost', 0)
1465 1485
1466 def setUp(self): 1486 def setUp(self):
1467 """Set up a UDP server to receive log messages, and a DatagramHandler 1487 """Set up a UDP server to receive log messages, and a DatagramHandler
1468 pointing to that server's address and port.""" 1488 pointing to that server's address and port."""
1469 BaseTest.setUp(self) 1489 BaseTest.setUp(self)
1470 addr = ('localhost', 0) 1490 self.server = server = self.server_class(self.address,
1471 self.server = server = TestUDPServer(addr, self.handle_datagram, 0.01) 1491 self.handle_datagram, 0.01)
1472 server.start() 1492 server.start()
1473 server.ready.wait() 1493 server.ready.wait()
1474 self.sock_hdlr = logging.handlers.DatagramHandler('localhost', 1494 hcls = logging.handlers.DatagramHandler
1475 server.port) 1495 if isinstance(server.server_address, tuple):
1496 self.sock_hdlr = hcls('localhost', server.port)
1497 else:
1498 self.sock_hdlr = hcls(server.server_address, None)
1476 self.log_output = '' 1499 self.log_output = ''
1477 self.root_logger.removeHandler(self.root_logger.handlers[0]) 1500 self.root_logger.removeHandler(self.root_logger.handlers[0])
1478 self.root_logger.addHandler(self.sock_hdlr) 1501 self.root_logger.addHandler(self.sock_hdlr)
1479 self.handled = threading.Event() 1502 self.handled = threading.Event()
1480 1503
1481 def tearDown(self): 1504 def tearDown(self):
1482 """Shutdown the UDP server.""" 1505 """Shutdown the UDP server."""
1483 try: 1506 try:
1484 self.server.stop(2.0) 1507 self.server.stop(2.0)
1485 self.root_logger.removeHandler(self.sock_hdlr) 1508 self.root_logger.removeHandler(self.sock_hdlr)
(...skipping 14 matching lines...) Expand all
1500 logger = logging.getLogger("udp") 1523 logger = logging.getLogger("udp")
1501 logger.error("spam") 1524 logger.error("spam")
1502 self.handled.wait() 1525 self.handled.wait()
1503 self.handled.clear() 1526 self.handled.clear()
1504 logger.error("eggs") 1527 logger.error("eggs")
1505 self.handled.wait() 1528 self.handled.wait()
1506 self.assertEqual(self.log_output, "spam\neggs\n") 1529 self.assertEqual(self.log_output, "spam\neggs\n")
1507 1530
1508 1531
1509 @unittest.skipUnless(threading, 'Threading required for this test.') 1532 @unittest.skipUnless(threading, 'Threading required for this test.')
1533 class UnixDatagramHandlerTest(DatagramHandlerTest):
1534
1535 """Test for DatagramHandler using Unix sockets."""
1536
1537 if threading:
1538 server_class = TestUnixDatagramServer
1539
1540 def setUp(self):
1541 # override the definition in the base class
1542 self.address = _get_temp_domain_socket()
1543 DatagramHandlerTest.setUp(self)
1544
1545 def tearDown(self):
1546 DatagramHandlerTest.tearDown(self)
1547 os.remove(self.address)
1548
1549 @unittest.skipUnless(threading, 'Threading required for this test.')
1510 class SysLogHandlerTest(BaseTest): 1550 class SysLogHandlerTest(BaseTest):
1511 1551
1512 """Test for SysLogHandler using UDP.""" 1552 """Test for SysLogHandler using UDP."""
1553
1554 if threading:
1555 server_class = TestUDPServer
1556 address = ('localhost', 0)
1513 1557
1514 def setUp(self): 1558 def setUp(self):
1515 """Set up a UDP server to receive log messages, and a SysLogHandler 1559 """Set up a UDP server to receive log messages, and a SysLogHandler
1516 pointing to that server's address and port.""" 1560 pointing to that server's address and port."""
1517 BaseTest.setUp(self) 1561 BaseTest.setUp(self)
1518 addr = ('localhost', 0) 1562 self.server = server = self.server_class(self.address,
1519 self.server = server = TestUDPServer(addr, self.handle_datagram, 1563 self.handle_datagram, 0.01)
1520 0.01)
1521 server.start() 1564 server.start()
1522 server.ready.wait() 1565 server.ready.wait()
1523 self.sl_hdlr = logging.handlers.SysLogHandler(('localhost', 1566 hcls = logging.handlers.SysLogHandler
1524 server.port)) 1567 if isinstance(server.server_address, tuple):
1568 self.sl_hdlr = hcls(('localhost', server.port))
1569 else:
1570 self.sl_hdlr = hcls(server.server_address)
1525 self.log_output = '' 1571 self.log_output = ''
1526 self.root_logger.removeHandler(self.root_logger.handlers[0]) 1572 self.root_logger.removeHandler(self.root_logger.handlers[0])
1527 self.root_logger.addHandler(self.sl_hdlr) 1573 self.root_logger.addHandler(self.sl_hdlr)
1528 self.handled = threading.Event() 1574 self.handled = threading.Event()
1529 1575
1530 def tearDown(self): 1576 def tearDown(self):
1531 """Shutdown the UDP server.""" 1577 """Shutdown the UDP server."""
1532 try: 1578 try:
1533 self.server.stop(2.0) 1579 self.server.stop(2.0)
1534 self.root_logger.removeHandler(self.sl_hdlr) 1580 self.root_logger.removeHandler(self.sl_hdlr)
(...skipping 15 matching lines...) Expand all
1550 self.sl_hdlr.append_nul = False 1596 self.sl_hdlr.append_nul = False
1551 logger.error("sp\xe4m") 1597 logger.error("sp\xe4m")
1552 self.handled.wait() 1598 self.handled.wait()
1553 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m') 1599 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
1554 self.handled.clear() 1600 self.handled.clear()
1555 self.sl_hdlr.ident = "h\xe4m-" 1601 self.sl_hdlr.ident = "h\xe4m-"
1556 logger.error("sp\xe4m") 1602 logger.error("sp\xe4m")
1557 self.handled.wait() 1603 self.handled.wait()
1558 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m') 1604 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
1559 1605
1606
1607 @unittest.skipUnless(threading, 'Threading required for this test.')
1608 class UnixSysLogHandlerTest(SysLogHandlerTest):
1609
1610 """Test for SysLogHandler with Unix sockets."""
1611
1612 if threading:
1613 server_class = TestUnixDatagramServer
1614
1615 def setUp(self):
1616 # override the definition in the base class
1617 self.address = _get_temp_domain_socket()
1618 SysLogHandlerTest.setUp(self)
1619
1620 def tearDown(self):
1621 SysLogHandlerTest.tearDown(self)
1622 os.remove(self.address)
1560 1623
1561 @unittest.skipUnless(threading, 'Threading required for this test.') 1624 @unittest.skipUnless(threading, 'Threading required for this test.')
1562 class HTTPHandlerTest(BaseTest): 1625 class HTTPHandlerTest(BaseTest):
1563 """Test for HTTPHandler.""" 1626 """Test for HTTPHandler."""
1564 1627
1565 PEMFILE = """-----BEGIN RSA PRIVATE KEY----- 1628 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1566 MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG 1629 MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1567 zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5 1630 zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1568 aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB 1631 aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1569 AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7 1632 AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
(...skipping 836 matching lines...) Expand 10 before | Expand all | Expand 10 after
2406 '.': { 2469 '.': {
2407 'foo': 'bar', 2470 'foo': 'bar',
2408 'terminator': '!\n', 2471 'terminator': '!\n',
2409 } 2472 }
2410 }, 2473 },
2411 }, 2474 },
2412 'root' : { 2475 'root' : {
2413 'level' : 'WARNING', 2476 'level' : 'WARNING',
2414 'handlers' : ['hand1'], 2477 'handlers' : ['hand1'],
2415 }, 2478 },
2479 }
2480
2481 out_of_order = {
2482 "version": 1,
2483 "formatters": {
2484 "mySimpleFormatter": {
2485 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2486 "style": "$"
2487 }
2488 },
2489 "handlers": {
2490 "fileGlobal": {
2491 "class": "logging.StreamHandler",
2492 "level": "DEBUG",
2493 "formatter": "mySimpleFormatter"
2494 },
2495 "bufferGlobal": {
2496 "class": "logging.handlers.MemoryHandler",
2497 "capacity": 5,
2498 "formatter": "mySimpleFormatter",
2499 "target": "fileGlobal",
2500 "level": "DEBUG"
2501 }
2502 },
2503 "loggers": {
2504 "mymodule": {
2505 "level": "DEBUG",
2506 "handlers": ["bufferGlobal"],
2507 "propagate": "true"
2508 }
2509 }
2416 } 2510 }
2417 2511
2418 def apply_config(self, conf): 2512 def apply_config(self, conf):
2419 logging.config.dictConfig(conf) 2513 logging.config.dictConfig(conf)
2420 2514
2421 def test_config0_ok(self): 2515 def test_config0_ok(self):
2422 # A simple config which overrides the default settings. 2516 # A simple config which overrides the default settings.
2423 with captured_stdout() as output: 2517 with captured_stdout() as output:
2424 self.apply_config(self.config0) 2518 self.apply_config(self.config0)
2425 logger = logging.getLogger() 2519 logger = logging.getLogger()
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after
2780 self.assert_log_lines([ 2874 self.assert_log_lines([
2781 ('INFO', '5'), 2875 ('INFO', '5'),
2782 ('ERROR', '6'), 2876 ('ERROR', '6'),
2783 ], stream=output) 2877 ], stream=output)
2784 # Original logger output still has the stuff we logged before. 2878 # Original logger output still has the stuff we logged before.
2785 self.assert_log_lines([ 2879 self.assert_log_lines([
2786 ('INFO', '1'), 2880 ('INFO', '1'),
2787 ('ERROR', '2'), 2881 ('ERROR', '2'),
2788 ], pat=r"^[\w.]+ -> (\w+): (\d+)$") 2882 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
2789 2883
2884 def test_out_of_order(self):
2885 self.apply_config(self.out_of_order)
2886 handler = logging.getLogger('mymodule').handlers[0]
2887 self.assertIsInstance(handler.target, logging.Handler)
2888 self.assertIsInstance(handler.formatter._style,
2889 logging.StringTemplateStyle)
2890
2790 def test_baseconfig(self): 2891 def test_baseconfig(self):
2791 d = { 2892 d = {
2792 'atuple': (1, 2, 3), 2893 'atuple': (1, 2, 3),
2793 'alist': ['a', 'b', 'c'], 2894 'alist': ['a', 'b', 'c'],
2794 'adict': {'d': 'e', 'f': 3 }, 2895 'adict': {'d': 'e', 'f': 3 },
2795 'nest1': ('g', ('h', 'i'), 'j'), 2896 'nest1': ('g', ('h', 'i'), 'j'),
2796 'nest2': ['k', ['l', 'm'], 'n'], 2897 'nest2': ['k', ['l', 'm'], 'n'],
2797 'nest3': ['o', 'cfg://alist', 'p'], 2898 'nest3': ['o', 'cfg://alist', 'p'],
2798 } 2899 }
2799 bc = logging.config.BaseConfigurator(d) 2900 bc = logging.config.BaseConfigurator(d)
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after
3288 3389
3289 class MyLogger(logging.Logger): 3390 class MyLogger(logging.Logger):
3290 pass 3391 pass
3291 3392
3292 logging.setLoggerClass(MyLogger) 3393 logging.setLoggerClass(MyLogger)
3293 self.assertEqual(logging.getLoggerClass(), MyLogger) 3394 self.assertEqual(logging.getLoggerClass(), MyLogger)
3294 3395
3295 logging.setLoggerClass(logging.Logger) 3396 logging.setLoggerClass(logging.Logger)
3296 self.assertEqual(logging.getLoggerClass(), logging.Logger) 3397 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3297 3398
3399 def test_logging_at_shutdown(self):
3400 # Issue #20037
3401 code = """if 1:
3402 import logging
3403
3404 class A:
3405 def __del__(self):
3406 try:
3407 raise ValueError("some error")
3408 except Exception:
3409 logging.exception("exception in __del__")
3410
3411 a = A()"""
3412 rc, out, err = assert_python_ok("-c", code)
3413 err = err.decode()
3414 self.assertIn("exception in __del__", err)
3415 self.assertIn("ValueError: some error", err)
3416
3417
3298 class LogRecordTest(BaseTest): 3418 class LogRecordTest(BaseTest):
3299 def test_str_rep(self): 3419 def test_str_rep(self):
3300 r = logging.makeLogRecord({}) 3420 r = logging.makeLogRecord({})
3301 s = str(r) 3421 s = str(r)
3302 self.assertTrue(s.startswith('<LogRecord: ')) 3422 self.assertTrue(s.startswith('<LogRecord: '))
3303 self.assertTrue(s.endswith('>')) 3423 self.assertTrue(s.endswith('>'))
3304 3424
3305 def test_dict_arg(self): 3425 def test_dict_arg(self):
3306 h = RecordingHandler() 3426 h = RecordingHandler()
3307 r = logging.getLogger() 3427 r = logging.getLogger()
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
3388 # format defaults to logging.BASIC_FORMAT 3508 # format defaults to logging.BASIC_FORMAT
3389 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT) 3509 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3390 # datefmt defaults to None 3510 # datefmt defaults to None
3391 self.assertIsNone(formatter.datefmt) 3511 self.assertIsNone(formatter.datefmt)
3392 # style defaults to % 3512 # style defaults to %
3393 self.assertIsInstance(formatter._style, logging.PercentStyle) 3513 self.assertIsInstance(formatter._style, logging.PercentStyle)
3394 3514
3395 # level is not explicitly set 3515 # level is not explicitly set
3396 self.assertEqual(logging.root.level, self.original_logging_level) 3516 self.assertEqual(logging.root.level, self.original_logging_level)
3397 3517
3518 def test_strformatstyle(self):
3519 with captured_stdout() as output:
3520 logging.basicConfig(stream=sys.stdout, style="{")
3521 logging.error("Log an error")
3522 sys.stdout.seek(0)
3523 self.assertEqual(output.getvalue().strip(),
3524 "ERROR:root:Log an error")
3525
3526 def test_stringtemplatestyle(self):
3527 with captured_stdout() as output:
3528 logging.basicConfig(stream=sys.stdout, style="$")
3529 logging.error("Log an error")
3530 sys.stdout.seek(0)
3531 self.assertEqual(output.getvalue().strip(),
3532 "ERROR:root:Log an error")
3533
3398 def test_filename(self): 3534 def test_filename(self):
3535
3536 def cleanup(h1, h2, fn):
3537 h1.close()
3538 h2.close()
3539 os.remove(fn)
3540
3399 logging.basicConfig(filename='test.log') 3541 logging.basicConfig(filename='test.log')
3400 3542
3401 self.assertEqual(len(logging.root.handlers), 1) 3543 self.assertEqual(len(logging.root.handlers), 1)
3402 handler = logging.root.handlers[0] 3544 handler = logging.root.handlers[0]
3403 self.assertIsInstance(handler, logging.FileHandler) 3545 self.assertIsInstance(handler, logging.FileHandler)
3404 3546
3405 expected = logging.FileHandler('test.log', 'a') 3547 expected = logging.FileHandler('test.log', 'a')
3406 self.addCleanup(expected.close)
3407 self.assertEqual(handler.stream.mode, expected.stream.mode) 3548 self.assertEqual(handler.stream.mode, expected.stream.mode)
3408 self.assertEqual(handler.stream.name, expected.stream.name) 3549 self.assertEqual(handler.stream.name, expected.stream.name)
3550 self.addCleanup(cleanup, handler, expected, 'test.log')
3409 3551
3410 def test_filemode(self): 3552 def test_filemode(self):
3553
3554 def cleanup(h1, h2, fn):
3555 h1.close()
3556 h2.close()
3557 os.remove(fn)
3558
3411 logging.basicConfig(filename='test.log', filemode='wb') 3559 logging.basicConfig(filename='test.log', filemode='wb')
3412 3560
3413 handler = logging.root.handlers[0] 3561 handler = logging.root.handlers[0]
3414 expected = logging.FileHandler('test.log', 'wb') 3562 expected = logging.FileHandler('test.log', 'wb')
3415 self.addCleanup(expected.close)
3416 self.assertEqual(handler.stream.mode, expected.stream.mode) 3563 self.assertEqual(handler.stream.mode, expected.stream.mode)
3564 self.addCleanup(cleanup, handler, expected, 'test.log')
3417 3565
3418 def test_stream(self): 3566 def test_stream(self):
3419 stream = io.StringIO() 3567 stream = io.StringIO()
3420 self.addCleanup(stream.close) 3568 self.addCleanup(stream.close)
3421 logging.basicConfig(stream=stream) 3569 logging.basicConfig(stream=stream)
3422 3570
3423 self.assertEqual(len(logging.root.handlers), 1) 3571 self.assertEqual(len(logging.root.handlers), 1)
3424 handler = logging.root.handlers[0] 3572 handler = logging.root.handlers[0]
3425 self.assertIsInstance(handler, logging.StreamHandler) 3573 self.assertIsInstance(handler, logging.StreamHandler)
3426 self.assertEqual(handler.stream, stream) 3574 self.assertEqual(handler.stream, stream)
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after
3862 4010
3863 def test_invalid(self): 4011 def test_invalid(self):
3864 assertRaises = self.assertRaises 4012 assertRaises = self.assertRaises
3865 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler, 4013 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
3866 self.fn, 'X', delay=True) 4014 self.fn, 'X', delay=True)
3867 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler, 4015 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
3868 self.fn, 'W', delay=True) 4016 self.fn, 'W', delay=True)
3869 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler, 4017 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
3870 self.fn, 'W7', delay=True) 4018 self.fn, 'W7', delay=True)
3871 4019
4020 def test_compute_rollover_daily_attime(self):
4021 currentTime = 0
4022 atTime = datetime.time(12, 0, 0)
4023 rh = logging.handlers.TimedRotatingFileHandler(
4024 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4025 atTime=atTime)
4026 try:
4027 actual = rh.computeRollover(currentTime)
4028 self.assertEqual(actual, currentTime + 12 * 60 * 60)
4029
4030 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4031 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4032 finally:
4033 rh.close()
4034
4035 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
4036 def test_compute_rollover_weekly_attime(self):
4037 currentTime = int(time.time())
4038 today = currentTime - currentTime % 86400
4039
4040 atTime = datetime.time(12, 0, 0)
4041
4042 wday = time.gmtime(today).tm_wday
4043 for day in range(7):
4044 rh = logging.handlers.TimedRotatingFileHandler(
4045 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4046 atTime=atTime)
4047 try:
4048 if wday > day:
4049 # The rollover day has already passed this week, so we
4050 # go over into next week
4051 expected = (7 - wday + day)
4052 else:
4053 expected = (day - wday)
4054 # At this point expected is in days from now, convert to seconds
4055 expected *= 24 * 60 * 60
4056 # Add in the rollover time
4057 expected += 12 * 60 * 60
4058 # Add in adjustment for today
4059 expected += today
4060 actual = rh.computeRollover(today)
4061 if actual != expected:
4062 print('failed in timezone: %d' % time.timezone)
4063 print('local vars: %s' % locals())
4064 self.assertEqual(actual, expected)
4065 if day == wday:
4066 # goes into following week
4067 expected += 7 * 24 * 60 * 60
4068 actual = rh.computeRollover(today + 13 * 60 * 60)
4069 if actual != expected:
4070 print('failed in timezone: %d' % time.timezone)
4071 print('local vars: %s' % locals())
4072 self.assertEqual(actual, expected)
4073 finally:
4074 rh.close()
4075
4076
3872 def secs(**kw): 4077 def secs(**kw):
3873 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1) 4078 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
3874 4079
3875 for when, exp in (('S', 1), 4080 for when, exp in (('S', 1),
3876 ('M', 60), 4081 ('M', 60),
3877 ('H', 60 * 60), 4082 ('H', 60 * 60),
3878 ('D', 60 * 60 * 24), 4083 ('D', 60 * 60 * 24),
3879 ('MIDNIGHT', 60 * 60 * 24), 4084 ('MIDNIGHT', 60 * 60 * 24),
3880 # current time (epoch start) is a Thursday, W0 means Monday 4085 # current time (epoch start) is a Thursday, W0 means Monday
3881 ('W0', secs(days=4, hours=24)), 4086 ('W0', secs(days=4, hours=24)),
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
3953 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest, 4158 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
3954 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest, 4159 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
3955 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest, 4160 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
3956 ManagerTest, FormatterTest, BufferingFormatterTest, 4161 ManagerTest, FormatterTest, BufferingFormatterTest,
3957 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest, 4162 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
3958 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, 4163 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
3959 BasicConfigTest, LoggerAdapterTest, LoggerTest, 4164 BasicConfigTest, LoggerAdapterTest, LoggerTest,
3960 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest, 4165 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
3961 LastResortTest, LogRecordTest, ExceptionTest, 4166 LastResortTest, LogRecordTest, ExceptionTest,
3962 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest, 4167 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
3963 TimedRotatingFileHandlerTest 4168 TimedRotatingFileHandlerTest, UnixSocketHandlerTest,
4169 UnixDatagramHandlerTest, UnixSysLogHandlerTest
3964 ) 4170 )
3965 4171
3966 if __name__ == "__main__": 4172 if __name__ == "__main__":
3967 test_main() 4173 test_main()
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+