test_logcontext.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import twisted.python.failure
  2. from twisted.internet import defer, reactor
  3. from synapse.util import Clock, logcontext
  4. from synapse.util.logcontext import LoggingContext
  5. from .. import unittest
  6. class LoggingContextTestCase(unittest.TestCase):
  7. def _check_test_key(self, value):
  8. self.assertEquals(LoggingContext.current_context().request, value)
  9. def test_with_context(self):
  10. with LoggingContext() as context_one:
  11. context_one.request = "test"
  12. self._check_test_key("test")
  13. @defer.inlineCallbacks
  14. def test_sleep(self):
  15. clock = Clock(reactor)
  16. @defer.inlineCallbacks
  17. def competing_callback():
  18. with LoggingContext() as competing_context:
  19. competing_context.request = "competing"
  20. yield clock.sleep(0)
  21. self._check_test_key("competing")
  22. reactor.callLater(0, competing_callback)
  23. with LoggingContext() as context_one:
  24. context_one.request = "one"
  25. yield clock.sleep(0)
  26. self._check_test_key("one")
  27. def _test_run_in_background(self, function):
  28. sentinel_context = LoggingContext.current_context()
  29. callback_completed = [False]
  30. def test():
  31. context_one.request = "one"
  32. d = function()
  33. def cb(res):
  34. self._check_test_key("one")
  35. callback_completed[0] = True
  36. return res
  37. d.addCallback(cb)
  38. return d
  39. with LoggingContext() as context_one:
  40. context_one.request = "one"
  41. # fire off function, but don't wait on it.
  42. logcontext.run_in_background(test)
  43. self._check_test_key("one")
  44. # now wait for the function under test to have run, and check that
  45. # the logcontext is left in a sane state.
  46. d2 = defer.Deferred()
  47. def check_logcontext():
  48. if not callback_completed[0]:
  49. reactor.callLater(0.01, check_logcontext)
  50. return
  51. # make sure that the context was reset before it got thrown back
  52. # into the reactor
  53. try:
  54. self.assertIs(LoggingContext.current_context(), sentinel_context)
  55. d2.callback(None)
  56. except BaseException:
  57. d2.errback(twisted.python.failure.Failure())
  58. reactor.callLater(0.01, check_logcontext)
  59. # test is done once d2 finishes
  60. return d2
  61. def test_run_in_background_with_blocking_fn(self):
  62. @defer.inlineCallbacks
  63. def blocking_function():
  64. yield Clock(reactor).sleep(0)
  65. return self._test_run_in_background(blocking_function)
  66. def test_run_in_background_with_non_blocking_fn(self):
  67. @defer.inlineCallbacks
  68. def nonblocking_function():
  69. with logcontext.PreserveLoggingContext():
  70. yield defer.succeed(None)
  71. return self._test_run_in_background(nonblocking_function)
  72. def test_run_in_background_with_chained_deferred(self):
  73. # a function which returns a deferred which looks like it has been
  74. # called, but is actually paused
  75. def testfunc():
  76. return logcontext.make_deferred_yieldable(_chained_deferred_function())
  77. return self._test_run_in_background(testfunc)
  78. @defer.inlineCallbacks
  79. def test_make_deferred_yieldable(self):
  80. # a function which retuns an incomplete deferred, but doesn't follow
  81. # the synapse rules.
  82. def blocking_function():
  83. d = defer.Deferred()
  84. reactor.callLater(0, d.callback, None)
  85. return d
  86. sentinel_context = LoggingContext.current_context()
  87. with LoggingContext() as context_one:
  88. context_one.request = "one"
  89. d1 = logcontext.make_deferred_yieldable(blocking_function())
  90. # make sure that the context was reset by make_deferred_yieldable
  91. self.assertIs(LoggingContext.current_context(), sentinel_context)
  92. yield d1
  93. # now it should be restored
  94. self._check_test_key("one")
  95. @defer.inlineCallbacks
  96. def test_make_deferred_yieldable_with_chained_deferreds(self):
  97. sentinel_context = LoggingContext.current_context()
  98. with LoggingContext() as context_one:
  99. context_one.request = "one"
  100. d1 = logcontext.make_deferred_yieldable(_chained_deferred_function())
  101. # make sure that the context was reset by make_deferred_yieldable
  102. self.assertIs(LoggingContext.current_context(), sentinel_context)
  103. yield d1
  104. # now it should be restored
  105. self._check_test_key("one")
  106. @defer.inlineCallbacks
  107. def test_make_deferred_yieldable_on_non_deferred(self):
  108. """Check that make_deferred_yieldable does the right thing when its
  109. argument isn't actually a deferred"""
  110. with LoggingContext() as context_one:
  111. context_one.request = "one"
  112. d1 = logcontext.make_deferred_yieldable("bum")
  113. self._check_test_key("one")
  114. r = yield d1
  115. self.assertEqual(r, "bum")
  116. self._check_test_key("one")
  117. # a function which returns a deferred which has been "called", but
  118. # which had a function which returned another incomplete deferred on
  119. # its callback list, so won't yet call any other new callbacks.
  120. def _chained_deferred_function():
  121. d = defer.succeed(None)
  122. def cb(res):
  123. d2 = defer.Deferred()
  124. reactor.callLater(0, d2.callback, res)
  125. return d2
  126. d.addCallback(cb)
  127. return d