mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Added tests to improve coverage.
This commit is contained in:
parent
0255973af6
commit
7367d08838
1 changed files with 339 additions and 108 deletions
|
@ -33,6 +33,7 @@ import errno
|
||||||
import pickle
|
import pickle
|
||||||
import io
|
import io
|
||||||
import gc
|
import gc
|
||||||
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import queue
|
import queue
|
||||||
|
@ -40,7 +41,8 @@ import re
|
||||||
import select
|
import select
|
||||||
import smtpd
|
import smtpd
|
||||||
import socket
|
import socket
|
||||||
from socketserver import ThreadingTCPServer, StreamRequestHandler
|
from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
|
||||||
|
ThreadingTCPServer, StreamRequestHandler)
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
@ -49,6 +51,7 @@ from test.support import TestHandler, Matcher
|
||||||
import textwrap
|
import textwrap
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
|
from urllib.parse import urlparse, parse_qs
|
||||||
import warnings
|
import warnings
|
||||||
import weakref
|
import weakref
|
||||||
try:
|
try:
|
||||||
|
@ -596,9 +599,8 @@ class StreamHandlerTest(BaseTest):
|
||||||
logging.raiseExceptions = old_raise
|
logging.raiseExceptions = old_raise
|
||||||
sys.stderr = old_stderr
|
sys.stderr = old_stderr
|
||||||
|
|
||||||
|
# -- The following section could be moved into a server_helper.py module
|
||||||
TEST_SMTP_PORT = 9025
|
# -- if it proves to be of wider utility than just test_logging
|
||||||
|
|
||||||
|
|
||||||
class TestSMTPChannel(smtpd.SMTPChannel):
|
class TestSMTPChannel(smtpd.SMTPChannel):
|
||||||
def __init__(self, server, conn, addr, sockmap):
|
def __init__(self, server, conn, addr, sockmap):
|
||||||
|
@ -642,6 +644,7 @@ class TestSMTPServer(smtpd.SMTPServer):
|
||||||
# try to re-use a server port if possible
|
# try to re-use a server port if possible
|
||||||
self.set_reuse_addr()
|
self.set_reuse_addr()
|
||||||
self.bind(addr)
|
self.bind(addr)
|
||||||
|
self.port = sock.getsockname()[1]
|
||||||
self.listen(5)
|
self.listen(5)
|
||||||
except:
|
except:
|
||||||
self.close()
|
self.close()
|
||||||
|
@ -666,23 +669,162 @@ class TestSMTPServer(smtpd.SMTPServer):
|
||||||
def serve_forever(self, poll_interval):
|
def serve_forever(self, poll_interval):
|
||||||
asyncore.loop(poll_interval, map=self.sockmap)
|
asyncore.loop(poll_interval, map=self.sockmap)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self, timeout=None):
|
||||||
self.close()
|
self.close()
|
||||||
self._thread.join()
|
self._thread.join(timeout)
|
||||||
self._thread = None
|
self._thread = None
|
||||||
|
|
||||||
|
class ControlMixin(object):
|
||||||
|
"""
|
||||||
|
This mixin is used to start a server on a separate thread, and
|
||||||
|
shut it down programmatically. Request handling is simplified - instead
|
||||||
|
of needing to derive a suitable RequestHandler subclass, you just
|
||||||
|
provide a callable which will be passed each received request to be
|
||||||
|
processed.
|
||||||
|
|
||||||
|
:param handler: A handler callable which will be called with a
|
||||||
|
single parameter - the request - in order to
|
||||||
|
process the request. This handler is called on the
|
||||||
|
server thread, effectively meaning that requests are
|
||||||
|
processed serially. While not quite Web scale ;-),
|
||||||
|
this should be fine for testing applications.
|
||||||
|
:param poll_interval: The polling interval in seconds.
|
||||||
|
"""
|
||||||
|
def __init__(self, handler, poll_interval):
|
||||||
|
self._thread = None
|
||||||
|
self.poll_interval = poll_interval
|
||||||
|
self._handler = handler
|
||||||
|
self.ready = threading.Event()
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""
|
||||||
|
Create a daemon thread to run the server, and start it.
|
||||||
|
"""
|
||||||
|
self._thread = t = threading.Thread(target=self.serve_forever,
|
||||||
|
args=(self.poll_interval,))
|
||||||
|
t.setDaemon(True)
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
def serve_forever(self, poll_interval):
|
||||||
|
self.ready.set()
|
||||||
|
super(ControlMixin, self).serve_forever(poll_interval)
|
||||||
|
|
||||||
|
def stop(self, timeout=None):
|
||||||
|
"""
|
||||||
|
Tell the server thread to stop, and wait for it to do so.
|
||||||
|
"""
|
||||||
|
self.shutdown()
|
||||||
|
if self._thread is not None:
|
||||||
|
self._thread.join(timeout)
|
||||||
|
self._thread = None
|
||||||
|
self.server_close()
|
||||||
|
self.ready.clear()
|
||||||
|
|
||||||
|
class TestHTTPServer(ControlMixin, HTTPServer):
|
||||||
|
"""
|
||||||
|
An HTTP server which is controllable using :class:`ControlMixin`.
|
||||||
|
|
||||||
|
:param addr: A tuple with the IP address and port to listen on.
|
||||||
|
:param handler: A handler callable which will be called with a
|
||||||
|
single parameter - the request - in order to
|
||||||
|
process the request.
|
||||||
|
:param poll_interval: The polling interval in seconds.
|
||||||
|
"""
|
||||||
|
def __init__(self, addr, handler, poll_interval=0.5, log=False):
|
||||||
|
class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||||
|
def __getattr__(self, name, default=None):
|
||||||
|
if name.startswith('do_'):
|
||||||
|
return self.process_request
|
||||||
|
raise AttributeError(name)
|
||||||
|
|
||||||
|
def process_request(self):
|
||||||
|
self.server._handler(self)
|
||||||
|
|
||||||
|
def log_message(self, format, *args):
|
||||||
|
if log:
|
||||||
|
super(DelegatingHTTPRequestHandler,
|
||||||
|
self).log_message(format, *args)
|
||||||
|
HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
|
||||||
|
ControlMixin.__init__(self, handler, poll_interval)
|
||||||
|
|
||||||
|
class TestTCPServer(ControlMixin, ThreadingTCPServer):
|
||||||
|
"""
|
||||||
|
A TCP server which is controllable using :class:`ControlMixin`.
|
||||||
|
|
||||||
|
:param addr: A tuple with the IP address and port to listen on.
|
||||||
|
:param handler: A handler callable which will be called with a single
|
||||||
|
parameter - the request - in order to process the request.
|
||||||
|
:param poll_interval: The polling interval in seconds.
|
||||||
|
:bind_and_activate: If True (the default), binds the server and starts it
|
||||||
|
listening. If False, you need to call
|
||||||
|
:meth:`server_bind` and :meth:`server_activate` at
|
||||||
|
some later time before calling :meth:`start`, so that
|
||||||
|
the server will set up the socket and listen on it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
allow_reuse_address = True
|
||||||
|
|
||||||
|
def __init__(self, addr, handler, poll_interval=0.5,
|
||||||
|
bind_and_activate=True):
|
||||||
|
class DelegatingTCPRequestHandler(StreamRequestHandler):
|
||||||
|
|
||||||
|
def handle(self):
|
||||||
|
self.server._handler(self)
|
||||||
|
ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
|
||||||
|
bind_and_activate)
|
||||||
|
ControlMixin.__init__(self, handler, poll_interval)
|
||||||
|
|
||||||
|
def server_bind(self):
|
||||||
|
super(TestTCPServer, self).server_bind()
|
||||||
|
self.port = self.socket.getsockname()[1]
|
||||||
|
|
||||||
|
class TestUDPServer(ControlMixin, ThreadingUDPServer):
|
||||||
|
"""
|
||||||
|
A UDP server which is controllable using :class:`ControlMixin`.
|
||||||
|
|
||||||
|
:param addr: A tuple with the IP address and port to listen on.
|
||||||
|
:param handler: A handler callable which will be called with a
|
||||||
|
single parameter - the request - in order to
|
||||||
|
process the request.
|
||||||
|
:param poll_interval: The polling interval for shutdown requests,
|
||||||
|
in seconds.
|
||||||
|
:bind_and_activate: If True (the default), binds the server and
|
||||||
|
starts it listening. If False, you need to
|
||||||
|
call :meth:`server_bind` and
|
||||||
|
:meth:`server_activate` at some later time
|
||||||
|
before calling :meth:`start`, so that the server will
|
||||||
|
set up the socket and listen on it.
|
||||||
|
"""
|
||||||
|
def __init__(self, addr, handler, poll_interval=0.5, bind_and_activate=True):
|
||||||
|
class DelegatingUDPRequestHandler(DatagramRequestHandler):
|
||||||
|
|
||||||
|
def handle(self):
|
||||||
|
self.server._handler(self)
|
||||||
|
ThreadingUDPServer.__init__(self, addr, DelegatingUDPRequestHandler,
|
||||||
|
bind_and_activate)
|
||||||
|
ControlMixin.__init__(self, handler, poll_interval)
|
||||||
|
|
||||||
|
def server_bind(self):
|
||||||
|
super(TestUDPServer, self).server_bind()
|
||||||
|
self.port = self.socket.getsockname()[1]
|
||||||
|
|
||||||
|
|
||||||
|
# - end of server_helper section
|
||||||
|
|
||||||
class SMTPHandlerTest(BaseTest):
|
class SMTPHandlerTest(BaseTest):
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
addr = ('localhost', TEST_SMTP_PORT)
|
sockmap = {}
|
||||||
|
server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
|
||||||
|
sockmap)
|
||||||
|
server.start()
|
||||||
|
addr = ('localhost', server.port)
|
||||||
h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log')
|
h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log')
|
||||||
self.assertEqual(h.toaddrs, ['you'])
|
self.assertEqual(h.toaddrs, ['you'])
|
||||||
self.messages = []
|
self.messages = []
|
||||||
sockmap = {}
|
|
||||||
server = TestSMTPServer(addr, self.process_message, 0.001, sockmap)
|
|
||||||
server.start()
|
|
||||||
r = logging.makeLogRecord({'msg': 'Hello'})
|
r = logging.makeLogRecord({'msg': 'Hello'})
|
||||||
|
self.handled = threading.Event()
|
||||||
h.handle(r)
|
h.handle(r)
|
||||||
|
self.handled.wait()
|
||||||
server.stop()
|
server.stop()
|
||||||
self.assertEqual(len(self.messages), 1)
|
self.assertEqual(len(self.messages), 1)
|
||||||
peer, mailfrom, rcpttos, data = self.messages[0]
|
peer, mailfrom, rcpttos, data = self.messages[0]
|
||||||
|
@ -694,7 +836,7 @@ class SMTPHandlerTest(BaseTest):
|
||||||
|
|
||||||
def process_message(self, *args):
|
def process_message(self, *args):
|
||||||
self.messages.append(args)
|
self.messages.append(args)
|
||||||
|
self.handled.set()
|
||||||
|
|
||||||
class MemoryHandlerTest(BaseTest):
|
class MemoryHandlerTest(BaseTest):
|
||||||
|
|
||||||
|
@ -1068,68 +1210,6 @@ class ConfigFileTest(BaseTest):
|
||||||
# Original logger output is empty.
|
# Original logger output is empty.
|
||||||
self.assert_log_lines([])
|
self.assert_log_lines([])
|
||||||
|
|
||||||
class LogRecordStreamHandler(StreamRequestHandler):
|
|
||||||
|
|
||||||
"""Handler for a streaming logging request. It saves the log message in the
|
|
||||||
TCP server's 'log_output' attribute."""
|
|
||||||
|
|
||||||
TCP_LOG_END = "!!!END!!!"
|
|
||||||
|
|
||||||
def handle(self):
|
|
||||||
"""Handle multiple requests - each expected to be of 4-byte length,
|
|
||||||
followed by the LogRecord in pickle format. Logs the record
|
|
||||||
according to whatever policy is configured locally."""
|
|
||||||
while True:
|
|
||||||
chunk = self.connection.recv(4)
|
|
||||||
if len(chunk) < 4:
|
|
||||||
break
|
|
||||||
slen = struct.unpack(">L", chunk)[0]
|
|
||||||
chunk = self.connection.recv(slen)
|
|
||||||
while len(chunk) < slen:
|
|
||||||
chunk = chunk + self.connection.recv(slen - len(chunk))
|
|
||||||
obj = self.unpickle(chunk)
|
|
||||||
record = logging.makeLogRecord(obj)
|
|
||||||
self.handle_log_record(record)
|
|
||||||
|
|
||||||
def unpickle(self, data):
|
|
||||||
return pickle.loads(data)
|
|
||||||
|
|
||||||
def handle_log_record(self, record):
|
|
||||||
# If the end-of-messages sentinel is seen, tell the server to
|
|
||||||
# terminate.
|
|
||||||
if self.TCP_LOG_END in record.msg:
|
|
||||||
self.server.abort = 1
|
|
||||||
return
|
|
||||||
self.server.log_output += record.msg + "\n"
|
|
||||||
|
|
||||||
|
|
||||||
class LogRecordSocketReceiver(ThreadingTCPServer):
|
|
||||||
|
|
||||||
"""A simple-minded TCP socket-based logging receiver suitable for test
|
|
||||||
purposes."""
|
|
||||||
|
|
||||||
allow_reuse_address = 1
|
|
||||||
log_output = ""
|
|
||||||
|
|
||||||
def __init__(self, host='localhost',
|
|
||||||
port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
|
|
||||||
handler=LogRecordStreamHandler):
|
|
||||||
ThreadingTCPServer.__init__(self, (host, port), handler)
|
|
||||||
self.abort = False
|
|
||||||
self.timeout = 0.1
|
|
||||||
self.finished = threading.Event()
|
|
||||||
|
|
||||||
def serve_until_stopped(self):
|
|
||||||
while not self.abort:
|
|
||||||
rd, wr, ex = select.select([self.socket.fileno()], [], [],
|
|
||||||
self.timeout)
|
|
||||||
if rd:
|
|
||||||
self.handle_request()
|
|
||||||
# Notify the main thread that we're about to exit
|
|
||||||
self.finished.set()
|
|
||||||
# close the listen socket
|
|
||||||
self.server_close()
|
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(threading, 'Threading required for this test.')
|
@unittest.skipUnless(threading, 'Threading required for this test.')
|
||||||
class SocketHandlerTest(BaseTest):
|
class SocketHandlerTest(BaseTest):
|
||||||
|
@ -1140,51 +1220,54 @@ class SocketHandlerTest(BaseTest):
|
||||||
"""Set up a TCP server to receive log messages, and a SocketHandler
|
"""Set up a TCP server to receive log messages, and a SocketHandler
|
||||||
pointing to that server's address and port."""
|
pointing to that server's address and port."""
|
||||||
BaseTest.setUp(self)
|
BaseTest.setUp(self)
|
||||||
self.tcpserver = LogRecordSocketReceiver(port=0)
|
addr = ('localhost', 0)
|
||||||
self.port = self.tcpserver.socket.getsockname()[1]
|
self.server = server = TestTCPServer(addr, self.handle_socket,
|
||||||
self.threads = [
|
0.01)
|
||||||
threading.Thread(target=self.tcpserver.serve_until_stopped)]
|
server.start()
|
||||||
for thread in self.threads:
|
server.ready.wait()
|
||||||
thread.start()
|
self.sock_hdlr = logging.handlers.SocketHandler('localhost',
|
||||||
|
server.port)
|
||||||
self.sock_hdlr = logging.handlers.SocketHandler('localhost', self.port)
|
self.log_output = ''
|
||||||
self.sock_hdlr.setFormatter(self.root_formatter)
|
|
||||||
self.root_logger.removeHandler(self.root_logger.handlers[0])
|
self.root_logger.removeHandler(self.root_logger.handlers[0])
|
||||||
self.root_logger.addHandler(self.sock_hdlr)
|
self.root_logger.addHandler(self.sock_hdlr)
|
||||||
|
self.handled = threading.Semaphore(0)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Shutdown the TCP server."""
|
"""Shutdown the TCP server."""
|
||||||
try:
|
try:
|
||||||
if hasattr(self, 'tcpserver'):
|
self.server.stop(2.0)
|
||||||
self.tcpserver.abort = True
|
|
||||||
del self.tcpserver
|
|
||||||
self.root_logger.removeHandler(self.sock_hdlr)
|
self.root_logger.removeHandler(self.sock_hdlr)
|
||||||
self.sock_hdlr.close()
|
self.sock_hdlr.close()
|
||||||
for thread in self.threads:
|
|
||||||
thread.join(2.0)
|
|
||||||
finally:
|
finally:
|
||||||
BaseTest.tearDown(self)
|
BaseTest.tearDown(self)
|
||||||
|
|
||||||
def get_output(self):
|
def handle_socket(self, request):
|
||||||
"""Get the log output as received by the TCP server."""
|
conn = request.connection
|
||||||
# Signal the TCP receiver and wait for it to terminate.
|
while True:
|
||||||
self.root_logger.critical(LogRecordStreamHandler.TCP_LOG_END)
|
chunk = conn.recv(4)
|
||||||
self.tcpserver.finished.wait(2.0)
|
if len(chunk) < 4:
|
||||||
return self.tcpserver.log_output
|
break
|
||||||
|
slen = struct.unpack(">L", chunk)[0]
|
||||||
|
chunk = conn.recv(slen)
|
||||||
|
while len(chunk) < slen:
|
||||||
|
chunk = chunk + conn.recv(slen - len(chunk))
|
||||||
|
obj = pickle.loads(chunk)
|
||||||
|
record = logging.makeLogRecord(obj)
|
||||||
|
self.log_output += record.msg + '\n'
|
||||||
|
self.handled.release()
|
||||||
|
|
||||||
def test_output(self):
|
def test_output(self):
|
||||||
# The log message sent to the SocketHandler is properly received.
|
# The log message sent to the SocketHandler is properly received.
|
||||||
logger = logging.getLogger("tcp")
|
logger = logging.getLogger("tcp")
|
||||||
logger.error("spam")
|
logger.error("spam")
|
||||||
|
self.handled.acquire()
|
||||||
logger.debug("eggs")
|
logger.debug("eggs")
|
||||||
self.assertEqual(self.get_output(), "spam\neggs\n")
|
self.handled.acquire()
|
||||||
|
self.assertEqual(self.log_output, "spam\neggs\n")
|
||||||
|
|
||||||
def test_noserver(self):
|
def test_noserver(self):
|
||||||
# Kill the server
|
# Kill the server
|
||||||
self.tcpserver.abort = True
|
self.server.stop(2.0)
|
||||||
del self.tcpserver
|
|
||||||
for thread in self.threads:
|
|
||||||
thread.join(2.0)
|
|
||||||
#The logging call should try to connect, which should fail
|
#The logging call should try to connect, which should fail
|
||||||
try:
|
try:
|
||||||
raise RuntimeError('Deliberate mistake')
|
raise RuntimeError('Deliberate mistake')
|
||||||
|
@ -1196,6 +1279,143 @@ class SocketHandlerTest(BaseTest):
|
||||||
time.sleep(self.sock_hdlr.retryTime - now + 0.001)
|
time.sleep(self.sock_hdlr.retryTime - now + 0.001)
|
||||||
self.root_logger.error('Nor this')
|
self.root_logger.error('Nor this')
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(threading, 'Threading required for this test.')
|
||||||
|
class DatagramHandlerTest(BaseTest):
|
||||||
|
|
||||||
|
"""Test for DatagramHandler."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""Set up a UDP server to receive log messages, and a DatagramHandler
|
||||||
|
pointing to that server's address and port."""
|
||||||
|
BaseTest.setUp(self)
|
||||||
|
addr = ('localhost', 0)
|
||||||
|
self.server = server = TestUDPServer(addr, self.handle_datagram,
|
||||||
|
0.01)
|
||||||
|
server.start()
|
||||||
|
server.ready.wait()
|
||||||
|
self.sock_hdlr = logging.handlers.DatagramHandler('localhost',
|
||||||
|
server.port)
|
||||||
|
self.log_output = ''
|
||||||
|
self.root_logger.removeHandler(self.root_logger.handlers[0])
|
||||||
|
self.root_logger.addHandler(self.sock_hdlr)
|
||||||
|
self.handled = threading.Event()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""Shutdown the UDP server."""
|
||||||
|
try:
|
||||||
|
self.server.stop(2.0)
|
||||||
|
self.root_logger.removeHandler(self.sock_hdlr)
|
||||||
|
self.sock_hdlr.close()
|
||||||
|
finally:
|
||||||
|
BaseTest.tearDown(self)
|
||||||
|
|
||||||
|
def handle_datagram(self, request):
|
||||||
|
slen = struct.pack('>L', 0) # length of prefix
|
||||||
|
packet = request.packet[len(slen):]
|
||||||
|
obj = pickle.loads(packet)
|
||||||
|
record = logging.makeLogRecord(obj)
|
||||||
|
self.log_output += record.msg + '\n'
|
||||||
|
self.handled.set()
|
||||||
|
|
||||||
|
def test_output(self):
|
||||||
|
# The log message sent to the DatagramHandler is properly received.
|
||||||
|
logger = logging.getLogger("udp")
|
||||||
|
logger.error("spam")
|
||||||
|
self.handled.wait()
|
||||||
|
self.assertEqual(self.log_output, "spam\n")
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(threading, 'Threading required for this test.')
|
||||||
|
class SysLogHandlerTest(BaseTest):
|
||||||
|
|
||||||
|
"""Test for SysLogHandler using UDP."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""Set up a UDP server to receive log messages, and a SysLogHandler
|
||||||
|
pointing to that server's address and port."""
|
||||||
|
BaseTest.setUp(self)
|
||||||
|
addr = ('localhost', 0)
|
||||||
|
self.server = server = TestUDPServer(addr, self.handle_datagram,
|
||||||
|
0.01)
|
||||||
|
server.start()
|
||||||
|
server.ready.wait()
|
||||||
|
self.sl_hdlr = logging.handlers.SysLogHandler(('localhost',
|
||||||
|
server.port))
|
||||||
|
self.log_output = ''
|
||||||
|
self.root_logger.removeHandler(self.root_logger.handlers[0])
|
||||||
|
self.root_logger.addHandler(self.sl_hdlr)
|
||||||
|
self.handled = threading.Event()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""Shutdown the UDP server."""
|
||||||
|
try:
|
||||||
|
self.server.stop(2.0)
|
||||||
|
self.root_logger.removeHandler(self.sl_hdlr)
|
||||||
|
self.sl_hdlr.close()
|
||||||
|
finally:
|
||||||
|
BaseTest.tearDown(self)
|
||||||
|
|
||||||
|
def handle_datagram(self, request):
|
||||||
|
self.log_output = request.packet
|
||||||
|
self.handled.set()
|
||||||
|
|
||||||
|
def test_output(self):
|
||||||
|
# The log message sent to the SysLogHandler is properly received.
|
||||||
|
logger = logging.getLogger("slh")
|
||||||
|
logger.error("sp\xe4m")
|
||||||
|
self.handled.wait()
|
||||||
|
self.assertEqual(self.log_output, b'<11>\xef\xbb\xbfsp\xc3\xa4m\x00')
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(threading, 'Threading required for this test.')
|
||||||
|
class HTTPHandlerTest(BaseTest):
|
||||||
|
|
||||||
|
"""Test for HTTPHandler."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""Set up an HTTP server to receive log messages, and a HTTPHandler
|
||||||
|
pointing to that server's address and port."""
|
||||||
|
BaseTest.setUp(self)
|
||||||
|
addr = ('localhost', 0)
|
||||||
|
self.server = server = TestHTTPServer(addr, self.handle_request,
|
||||||
|
0.01)
|
||||||
|
server.start()
|
||||||
|
server.ready.wait()
|
||||||
|
host = 'localhost:%d' % server.server_port
|
||||||
|
self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob')
|
||||||
|
self.log_data = None
|
||||||
|
self.root_logger.removeHandler(self.root_logger.handlers[0])
|
||||||
|
self.root_logger.addHandler(self.h_hdlr)
|
||||||
|
self.handled = threading.Event()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""Shutdown the UDP server."""
|
||||||
|
try:
|
||||||
|
self.server.stop(2.0)
|
||||||
|
self.root_logger.removeHandler(self.h_hdlr)
|
||||||
|
self.h_hdlr.close()
|
||||||
|
finally:
|
||||||
|
BaseTest.tearDown(self)
|
||||||
|
|
||||||
|
def handle_request(self, request):
|
||||||
|
self.log_data = urlparse(request.path)
|
||||||
|
request.send_response(200)
|
||||||
|
self.handled.set()
|
||||||
|
|
||||||
|
def test_output(self):
|
||||||
|
# The log message sent to the SysLogHandler is properly received.
|
||||||
|
logger = logging.getLogger("http")
|
||||||
|
msg = "sp\xe4m"
|
||||||
|
logger.error(msg)
|
||||||
|
self.handled.wait()
|
||||||
|
self.assertEqual(self.log_data.path, '/frob')
|
||||||
|
d = parse_qs(self.log_data.query)
|
||||||
|
self.assertEqual(d['name'], ['http'])
|
||||||
|
self.assertEqual(d['funcName'], ['test_output'])
|
||||||
|
self.assertEqual(d['msg'], [msg])
|
||||||
|
|
||||||
|
|
||||||
class MemoryTest(BaseTest):
|
class MemoryTest(BaseTest):
|
||||||
|
|
||||||
"""Test memory persistence of logger objects."""
|
"""Test memory persistence of logger objects."""
|
||||||
|
@ -3129,7 +3349,7 @@ class BaseFileTest(BaseTest):
|
||||||
def assertLogFile(self, filename):
|
def assertLogFile(self, filename):
|
||||||
"Assert a log file is there and register it for deletion"
|
"Assert a log file is there and register it for deletion"
|
||||||
self.assertTrue(os.path.exists(filename),
|
self.assertTrue(os.path.exists(filename),
|
||||||
msg="Log file %r does not exist")
|
msg="Log file %r does not exist" % filename)
|
||||||
self.rmfiles.append(filename)
|
self.rmfiles.append(filename)
|
||||||
|
|
||||||
|
|
||||||
|
@ -3181,8 +3401,18 @@ class RotatingFileHandlerTest(BaseFileTest):
|
||||||
rh.close()
|
rh.close()
|
||||||
|
|
||||||
class TimedRotatingFileHandlerTest(BaseFileTest):
|
class TimedRotatingFileHandlerTest(BaseFileTest):
|
||||||
# test methods added below
|
# other test methods added below
|
||||||
pass
|
def test_rollover(self):
|
||||||
|
fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S')
|
||||||
|
r = logging.makeLogRecord({'msg': 'testing'})
|
||||||
|
fh.emit(r)
|
||||||
|
self.assertLogFile(self.fn)
|
||||||
|
time.sleep(1.0)
|
||||||
|
fh.emit(r)
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
prevsec = now - datetime.timedelta(seconds=1)
|
||||||
|
suffix = prevsec.strftime(".%Y-%m-%d_%H-%M-%S")
|
||||||
|
self.assertLogFile(self.fn + suffix)
|
||||||
|
|
||||||
def secs(**kw):
|
def secs(**kw):
|
||||||
return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
|
return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
|
||||||
|
@ -3238,14 +3468,15 @@ for when, exp in (('S', 1),
|
||||||
def test_main():
|
def test_main():
|
||||||
run_unittest(BuiltinLevelsTest, BasicFilterTest,
|
run_unittest(BuiltinLevelsTest, BasicFilterTest,
|
||||||
CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
|
CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
|
||||||
ConfigFileTest, SocketHandlerTest, MemoryTest,
|
ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
|
||||||
EncodingTest, WarningsTest, ConfigDictTest, ManagerTest,
|
MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
|
||||||
FormatterTest, BufferingFormatterTest, StreamHandlerTest,
|
ManagerTest, FormatterTest, BufferingFormatterTest,
|
||||||
LogRecordFactoryTest, ChildLoggerTest, QueueHandlerTest,
|
StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
|
||||||
ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
|
QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
|
||||||
LoggerAdapterTest, LoggerTest, SMTPHandlerTest,
|
BasicConfigTest, LoggerAdapterTest, LoggerTest,
|
||||||
FileHandlerTest, RotatingFileHandlerTest,
|
SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
|
||||||
LastResortTest, LogRecordTest, ExceptionTest,
|
LastResortTest, LogRecordTest, ExceptionTest,
|
||||||
|
SysLogHandlerTest, HTTPHandlerTest,
|
||||||
TimedRotatingFileHandlerTest
|
TimedRotatingFileHandlerTest
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue