Create a mechanism for marking tests "logcontext clean" (#8399)

This commit is contained in:
Richard van der Hoff 2020-09-28 17:58:33 +01:00 committed by GitHub
parent bd715e1278
commit 5e3ca12b15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 21 deletions

1
changelog.d/8399.misc Normal file
View File

@ -0,0 +1 @@
Create a mechanism for marking tests "logcontext clean".

View File

@ -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,
) )

View File

@ -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()

View File

@ -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.