2014-09-12 19:24:53 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
2016-01-07 05:26:29 +01:00
|
|
|
# Copyright 2014-2016 OpenMarket Ltd
|
2014-09-12 19:24:53 +02:00
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
2018-06-04 08:06:06 +02:00
|
|
|
|
|
|
|
import logging
|
|
|
|
|
2018-01-09 13:05:25 +01:00
|
|
|
import twisted
|
2018-06-04 08:06:06 +02:00
|
|
|
import twisted.logger
|
2014-09-12 19:24:53 +02:00
|
|
|
from twisted.trial import unittest
|
|
|
|
|
2018-06-04 08:06:06 +02:00
|
|
|
from synapse.util.logcontext import LoggingContextFilter
|
|
|
|
|
|
|
|
# Set up putting Synapse's logs into Trial's.
|
|
|
|
rootLogger = logging.getLogger()
|
|
|
|
|
|
|
|
log_format = (
|
|
|
|
"%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class ToTwistedHandler(logging.Handler):
|
|
|
|
tx_log = twisted.logger.Logger()
|
|
|
|
|
|
|
|
def emit(self, record):
|
|
|
|
log_entry = self.format(record)
|
|
|
|
log_level = record.levelname.lower().replace('warning', 'warn')
|
2018-06-27 12:38:03 +02:00
|
|
|
self.tx_log.emit(
|
|
|
|
twisted.logger.LogLevel.levelWithName(log_level),
|
|
|
|
log_entry.replace("{", r"(").replace("}", r")"),
|
|
|
|
)
|
2014-09-12 19:24:53 +02:00
|
|
|
|
|
|
|
|
2018-06-04 08:06:06 +02:00
|
|
|
handler = ToTwistedHandler()
|
|
|
|
formatter = logging.Formatter(log_format)
|
|
|
|
handler.setFormatter(formatter)
|
|
|
|
handler.addFilter(LoggingContextFilter(request=""))
|
|
|
|
rootLogger.addHandler(handler)
|
2014-09-12 19:24:53 +02:00
|
|
|
|
|
|
|
|
2014-09-12 20:07:29 +02:00
|
|
|
def around(target):
|
|
|
|
"""A CLOS-style 'around' modifier, which wraps the original method of the
|
|
|
|
given instance with another piece of code.
|
|
|
|
|
|
|
|
@around(self)
|
|
|
|
def method_name(orig, *args, **kwargs):
|
|
|
|
return orig(*args, **kwargs)
|
|
|
|
"""
|
2018-08-10 15:54:09 +02:00
|
|
|
|
2014-09-12 20:07:29 +02:00
|
|
|
def _around(code):
|
|
|
|
name = code.__name__
|
|
|
|
orig = getattr(target, name)
|
2016-02-19 16:34:38 +01:00
|
|
|
|
2014-09-12 20:07:29 +02:00
|
|
|
def new(*args, **kwargs):
|
|
|
|
return code(orig, *args, **kwargs)
|
2016-02-19 16:34:38 +01:00
|
|
|
|
2014-09-12 20:07:29 +02:00
|
|
|
setattr(target, name, new)
|
2016-02-19 16:34:38 +01:00
|
|
|
|
2014-09-12 20:07:29 +02:00
|
|
|
return _around
|
|
|
|
|
|
|
|
|
2014-09-12 19:24:53 +02:00
|
|
|
class TestCase(unittest.TestCase):
|
2014-09-12 19:45:48 +02:00
|
|
|
"""A subclass of twisted.trial's TestCase which looks for 'loglevel'
|
|
|
|
attributes on both itself and its individual test methods, to override the
|
|
|
|
root logger's logging level while that test (case|method) runs."""
|
|
|
|
|
2014-09-12 19:43:49 +02:00
|
|
|
def __init__(self, methodName, *args, **kwargs):
|
|
|
|
super(TestCase, self).__init__(methodName, *args, **kwargs)
|
2014-09-12 19:29:07 +02:00
|
|
|
|
2014-09-12 19:43:49 +02:00
|
|
|
method = getattr(self, methodName)
|
|
|
|
|
2018-06-04 08:06:06 +02:00
|
|
|
level = getattr(method, "loglevel", getattr(self, "loglevel", logging.ERROR))
|
2014-09-12 19:29:07 +02:00
|
|
|
|
2014-09-12 20:07:29 +02:00
|
|
|
@around(self)
|
|
|
|
def setUp(orig):
|
2018-01-09 13:05:25 +01:00
|
|
|
# enable debugging of delayed calls - this means that we get a
|
|
|
|
# traceback when a unit test exits leaving things on the reactor.
|
|
|
|
twisted.internet.base.DelayedCall.debug = True
|
|
|
|
|
2014-09-12 19:29:07 +02:00
|
|
|
old_level = logging.getLogger().level
|
|
|
|
|
|
|
|
if old_level != level:
|
2018-08-10 15:54:09 +02:00
|
|
|
|
2014-09-12 20:07:29 +02:00
|
|
|
@around(self)
|
|
|
|
def tearDown(orig):
|
|
|
|
ret = orig()
|
2014-09-12 19:29:07 +02:00
|
|
|
logging.getLogger().setLevel(old_level)
|
|
|
|
return ret
|
|
|
|
|
|
|
|
logging.getLogger().setLevel(level)
|
2014-09-12 20:07:29 +02:00
|
|
|
return orig()
|
2014-09-12 19:38:11 +02:00
|
|
|
|
2014-09-17 16:56:40 +02:00
|
|
|
def assertObjectHasAttributes(self, attrs, obj):
|
|
|
|
"""Asserts that the given object has each of the attributes given, and
|
|
|
|
that the value of each matches according to assertEquals."""
|
|
|
|
for (key, value) in attrs.items():
|
|
|
|
if not hasattr(obj, key):
|
|
|
|
raise AssertionError("Expected obj to have a '.%s'" % key)
|
|
|
|
try:
|
|
|
|
self.assertEquals(attrs[key], getattr(obj, key))
|
|
|
|
except AssertionError as e:
|
|
|
|
raise (type(e))(e.message + " for '.%s'" % key)
|
|
|
|
|
2018-07-17 12:43:18 +02:00
|
|
|
def assert_dict(self, required, actual):
|
|
|
|
"""Does a partial assert of a dict.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
required (dict): The keys and value which MUST be in 'actual'.
|
|
|
|
actual (dict): The test result. Extra keys will not be checked.
|
|
|
|
"""
|
|
|
|
for key in required:
|
2018-08-10 15:54:09 +02:00
|
|
|
self.assertEquals(
|
|
|
|
required[key], actual[key], msg="%s mismatch. %s" % (key, actual)
|
|
|
|
)
|
2018-07-17 12:43:18 +02:00
|
|
|
|
2014-09-12 19:38:11 +02:00
|
|
|
|
|
|
|
def DEBUG(target):
|
2014-09-12 19:45:48 +02:00
|
|
|
"""A decorator to set the .loglevel attribute to logging.DEBUG.
|
|
|
|
Can apply to either a TestCase or an individual test method."""
|
2014-09-12 19:38:11 +02:00
|
|
|
target.loglevel = logging.DEBUG
|
|
|
|
return target
|