Create a mechanism for marking tests "logcontext clean" (#8399)
This commit is contained in:
parent
bd715e1278
commit
5e3ca12b15
|
@ -0,0 +1 @@
|
||||||
|
Create a mechanism for marking tests "logcontext clean".
|
|
@ -65,6 +65,11 @@ except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# a hook which can be set during testing to assert that we aren't abusing logcontexts.
|
||||||
|
def logcontext_error(msg: str):
|
||||||
|
logger.warning(msg)
|
||||||
|
|
||||||
|
|
||||||
# get an id for the current thread.
|
# get an id for the current thread.
|
||||||
#
|
#
|
||||||
# threading.get_ident doesn't actually return an OS-level tid, and annoyingly,
|
# threading.get_ident doesn't actually return an OS-level tid, and annoyingly,
|
||||||
|
@ -330,10 +335,9 @@ class LoggingContext:
|
||||||
"""Enters this logging context into thread local storage"""
|
"""Enters this logging context into thread local storage"""
|
||||||
old_context = set_current_context(self)
|
old_context = set_current_context(self)
|
||||||
if self.previous_context != old_context:
|
if self.previous_context != old_context:
|
||||||
logger.warning(
|
logcontext_error(
|
||||||
"Expected previous context %r, found %r",
|
"Expected previous context %r, found %r"
|
||||||
self.previous_context,
|
% (self.previous_context, old_context,)
|
||||||
old_context,
|
|
||||||
)
|
)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@ -346,10 +350,10 @@ class LoggingContext:
|
||||||
current = set_current_context(self.previous_context)
|
current = set_current_context(self.previous_context)
|
||||||
if current is not self:
|
if current is not self:
|
||||||
if current is SENTINEL_CONTEXT:
|
if current is SENTINEL_CONTEXT:
|
||||||
logger.warning("Expected logging context %s was lost", self)
|
logcontext_error("Expected logging context %s was lost" % (self,))
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
logcontext_error(
|
||||||
"Expected logging context %s but found %s", self, current
|
"Expected logging context %s but found %s" % (self, current)
|
||||||
)
|
)
|
||||||
|
|
||||||
# the fact that we are here suggests that the caller thinks that everything
|
# the fact that we are here suggests that the caller thinks that everything
|
||||||
|
@ -387,16 +391,16 @@ class LoggingContext:
|
||||||
support getrusuage.
|
support getrusuage.
|
||||||
"""
|
"""
|
||||||
if get_thread_id() != self.main_thread:
|
if get_thread_id() != self.main_thread:
|
||||||
logger.warning("Started logcontext %s on different thread", self)
|
logcontext_error("Started logcontext %s on different thread" % (self,))
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.finished:
|
if self.finished:
|
||||||
logger.warning("Re-starting finished log context %s", self)
|
logcontext_error("Re-starting finished log context %s" % (self,))
|
||||||
|
|
||||||
# If we haven't already started record the thread resource usage so
|
# If we haven't already started record the thread resource usage so
|
||||||
# far
|
# far
|
||||||
if self.usage_start:
|
if self.usage_start:
|
||||||
logger.warning("Re-starting already-active log context %s", self)
|
logcontext_error("Re-starting already-active log context %s" % (self,))
|
||||||
else:
|
else:
|
||||||
self.usage_start = rusage
|
self.usage_start = rusage
|
||||||
|
|
||||||
|
@ -414,7 +418,7 @@ class LoggingContext:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if get_thread_id() != self.main_thread:
|
if get_thread_id() != self.main_thread:
|
||||||
logger.warning("Stopped logcontext %s on different thread", self)
|
logcontext_error("Stopped logcontext %s on different thread" % (self,))
|
||||||
return
|
return
|
||||||
|
|
||||||
if not rusage:
|
if not rusage:
|
||||||
|
@ -422,9 +426,9 @@ class LoggingContext:
|
||||||
|
|
||||||
# Record the cpu used since we started
|
# Record the cpu used since we started
|
||||||
if not self.usage_start:
|
if not self.usage_start:
|
||||||
logger.warning(
|
logcontext_error(
|
||||||
"Called stop on logcontext %s without recording a start rusage",
|
"Called stop on logcontext %s without recording a start rusage"
|
||||||
self,
|
% (self,)
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -584,14 +588,13 @@ class PreserveLoggingContext:
|
||||||
|
|
||||||
if context != self._new_context:
|
if context != self._new_context:
|
||||||
if not context:
|
if not context:
|
||||||
logger.warning(
|
logcontext_error(
|
||||||
"Expected logging context %s was lost", self._new_context
|
"Expected logging context %s was lost" % (self._new_context,)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
logcontext_error(
|
||||||
"Expected logging context %s but found %s",
|
"Expected logging context %s but found %s"
|
||||||
self._new_context,
|
% (self._new_context, context,)
|
||||||
context,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ from synapse.storage.keys import FetchKeyResult
|
||||||
|
|
||||||
from tests import unittest
|
from tests import unittest
|
||||||
from tests.test_utils import make_awaitable
|
from tests.test_utils import make_awaitable
|
||||||
|
from tests.unittest import logcontext_clean
|
||||||
|
|
||||||
|
|
||||||
class MockPerspectiveServer:
|
class MockPerspectiveServer:
|
||||||
|
@ -67,6 +68,7 @@ class MockPerspectiveServer:
|
||||||
signedjson.sign.sign_json(res, self.server_name, self.key)
|
signedjson.sign.sign_json(res, self.server_name, self.key)
|
||||||
|
|
||||||
|
|
||||||
|
@logcontext_clean
|
||||||
class KeyringTestCase(unittest.HomeserverTestCase):
|
class KeyringTestCase(unittest.HomeserverTestCase):
|
||||||
def check_context(self, val, expected):
|
def check_context(self, val, expected):
|
||||||
self.assertEquals(getattr(current_context(), "request", None), expected)
|
self.assertEquals(getattr(current_context(), "request", None), expected)
|
||||||
|
@ -309,6 +311,7 @@ class KeyringTestCase(unittest.HomeserverTestCase):
|
||||||
mock_fetcher2.get_keys.assert_called_once()
|
mock_fetcher2.get_keys.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@logcontext_clean
|
||||||
class ServerKeyFetcherTestCase(unittest.HomeserverTestCase):
|
class ServerKeyFetcherTestCase(unittest.HomeserverTestCase):
|
||||||
def make_homeserver(self, reactor, clock):
|
def make_homeserver(self, reactor, clock):
|
||||||
self.http_client = Mock()
|
self.http_client = Mock()
|
||||||
|
|
|
@ -23,7 +23,7 @@ import logging
|
||||||
import time
|
import time
|
||||||
from typing import Optional, Tuple, Type, TypeVar, Union
|
from typing import Optional, Tuple, Type, TypeVar, Union
|
||||||
|
|
||||||
from mock import Mock
|
from mock import Mock, patch
|
||||||
|
|
||||||
from canonicaljson import json
|
from canonicaljson import json
|
||||||
|
|
||||||
|
@ -169,6 +169,19 @@ def INFO(target):
|
||||||
return target
|
return target
|
||||||
|
|
||||||
|
|
||||||
|
def logcontext_clean(target):
|
||||||
|
"""A decorator which marks the TestCase or method as 'logcontext_clean'
|
||||||
|
|
||||||
|
... ie, any logcontext errors should cause a test failure
|
||||||
|
"""
|
||||||
|
|
||||||
|
def logcontext_error(msg):
|
||||||
|
raise AssertionError("logcontext error: %s" % (msg))
|
||||||
|
|
||||||
|
patcher = patch("synapse.logging.context.logcontext_error", new=logcontext_error)
|
||||||
|
return patcher(target)
|
||||||
|
|
||||||
|
|
||||||
class HomeserverTestCase(TestCase):
|
class HomeserverTestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
A base TestCase that reduces boilerplate for HomeServer-using test cases.
|
A base TestCase that reduces boilerplate for HomeServer-using test cases.
|
||||||
|
|
Loading…
Reference in New Issue