tests.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import gc
  2. import sys
  3. import time
  4. import unittest
  5. import weakref
  6. from types import TracebackType
  7. from django.dispatch import Signal, receiver
  8. if sys.platform.startswith('java'):
  9. def garbage_collect():
  10. # Some JVM GCs will execute finalizers in a different thread, meaning
  11. # we need to wait for that to complete before we go on looking for the
  12. # effects of that.
  13. gc.collect()
  14. time.sleep(0.1)
  15. elif hasattr(sys, "pypy_version_info"):
  16. def garbage_collect():
  17. # Collecting weakreferences can take two collections on PyPy.
  18. gc.collect()
  19. gc.collect()
  20. else:
  21. def garbage_collect():
  22. gc.collect()
  23. def receiver_1_arg(val, **kwargs):
  24. return val
  25. class Callable(object):
  26. def __call__(self, val, **kwargs):
  27. return val
  28. def a(self, val, **kwargs):
  29. return val
  30. a_signal = Signal(providing_args=["val"])
  31. b_signal = Signal(providing_args=["val"])
  32. c_signal = Signal(providing_args=["val"])
  33. d_signal = Signal(providing_args=["val"], use_caching=True)
  34. class DispatcherTests(unittest.TestCase):
  35. """Test suite for dispatcher (barely started)"""
  36. def assertTestIsClean(self, signal):
  37. """Assert that everything has been cleaned up automatically"""
  38. # Note that dead weakref cleanup happens as side effect of using
  39. # the signal's receivers through the signals API. So, first do a
  40. # call to an API method to force cleanup.
  41. self.assertFalse(signal.has_listeners())
  42. self.assertEqual(signal.receivers, [])
  43. def test_exact(self):
  44. a_signal.connect(receiver_1_arg, sender=self)
  45. expected = [(receiver_1_arg, "test")]
  46. result = a_signal.send(sender=self, val="test")
  47. self.assertEqual(result, expected)
  48. a_signal.disconnect(receiver_1_arg, sender=self)
  49. self.assertTestIsClean(a_signal)
  50. def test_ignored_sender(self):
  51. a_signal.connect(receiver_1_arg)
  52. expected = [(receiver_1_arg, "test")]
  53. result = a_signal.send(sender=self, val="test")
  54. self.assertEqual(result, expected)
  55. a_signal.disconnect(receiver_1_arg)
  56. self.assertTestIsClean(a_signal)
  57. def test_garbage_collected(self):
  58. a = Callable()
  59. a_signal.connect(a.a, sender=self)
  60. expected = []
  61. del a
  62. garbage_collect()
  63. result = a_signal.send(sender=self, val="test")
  64. self.assertEqual(result, expected)
  65. self.assertTestIsClean(a_signal)
  66. def test_cached_garbaged_collected(self):
  67. """
  68. Make sure signal caching sender receivers don't prevent garbage
  69. collection of senders.
  70. """
  71. class sender:
  72. pass
  73. wref = weakref.ref(sender)
  74. d_signal.connect(receiver_1_arg)
  75. d_signal.send(sender, val='garbage')
  76. del sender
  77. garbage_collect()
  78. try:
  79. self.assertIsNone(wref())
  80. finally:
  81. # Disconnect after reference check since it flushes the tested cache.
  82. d_signal.disconnect(receiver_1_arg)
  83. def test_multiple_registration(self):
  84. a = Callable()
  85. a_signal.connect(a)
  86. a_signal.connect(a)
  87. a_signal.connect(a)
  88. a_signal.connect(a)
  89. a_signal.connect(a)
  90. a_signal.connect(a)
  91. result = a_signal.send(sender=self, val="test")
  92. self.assertEqual(len(result), 1)
  93. self.assertEqual(len(a_signal.receivers), 1)
  94. del a
  95. del result
  96. garbage_collect()
  97. self.assertTestIsClean(a_signal)
  98. def test_uid_registration(self):
  99. def uid_based_receiver_1(**kwargs):
  100. pass
  101. def uid_based_receiver_2(**kwargs):
  102. pass
  103. a_signal.connect(uid_based_receiver_1, dispatch_uid="uid")
  104. a_signal.connect(uid_based_receiver_2, dispatch_uid="uid")
  105. self.assertEqual(len(a_signal.receivers), 1)
  106. a_signal.disconnect(dispatch_uid="uid")
  107. self.assertTestIsClean(a_signal)
  108. def test_robust(self):
  109. """Test the send_robust() function"""
  110. def fails(val, **kwargs):
  111. raise ValueError('this')
  112. a_signal.connect(fails)
  113. result = a_signal.send_robust(sender=self, val="test")
  114. err = result[0][1]
  115. self.assertIsInstance(err, ValueError)
  116. self.assertEqual(err.args, ('this',))
  117. self.assertTrue(hasattr(err, '__traceback__'))
  118. self.assertTrue(isinstance(err.__traceback__, TracebackType))
  119. a_signal.disconnect(fails)
  120. self.assertTestIsClean(a_signal)
  121. def test_disconnection(self):
  122. receiver_1 = Callable()
  123. receiver_2 = Callable()
  124. receiver_3 = Callable()
  125. a_signal.connect(receiver_1)
  126. a_signal.connect(receiver_2)
  127. a_signal.connect(receiver_3)
  128. a_signal.disconnect(receiver_1)
  129. del receiver_2
  130. garbage_collect()
  131. a_signal.disconnect(receiver_3)
  132. self.assertTestIsClean(a_signal)
  133. def test_values_returned_by_disconnection(self):
  134. receiver_1 = Callable()
  135. receiver_2 = Callable()
  136. a_signal.connect(receiver_1)
  137. receiver_1_disconnected = a_signal.disconnect(receiver_1)
  138. receiver_2_disconnected = a_signal.disconnect(receiver_2)
  139. self.assertTrue(receiver_1_disconnected)
  140. self.assertFalse(receiver_2_disconnected)
  141. self.assertTestIsClean(a_signal)
  142. def test_has_listeners(self):
  143. self.assertFalse(a_signal.has_listeners())
  144. self.assertFalse(a_signal.has_listeners(sender=object()))
  145. receiver_1 = Callable()
  146. a_signal.connect(receiver_1)
  147. self.assertTrue(a_signal.has_listeners())
  148. self.assertTrue(a_signal.has_listeners(sender=object()))
  149. a_signal.disconnect(receiver_1)
  150. self.assertFalse(a_signal.has_listeners())
  151. self.assertFalse(a_signal.has_listeners(sender=object()))
  152. class ReceiverTestCase(unittest.TestCase):
  153. """
  154. Test suite for receiver.
  155. """
  156. def test_receiver_single_signal(self):
  157. @receiver(a_signal)
  158. def f(val, **kwargs):
  159. self.state = val
  160. self.state = False
  161. a_signal.send(sender=self, val=True)
  162. self.assertTrue(self.state)
  163. def test_receiver_signal_list(self):
  164. @receiver([a_signal, b_signal, c_signal])
  165. def f(val, **kwargs):
  166. self.state.append(val)
  167. self.state = []
  168. a_signal.send(sender=self, val='a')
  169. c_signal.send(sender=self, val='c')
  170. b_signal.send(sender=self, val='b')
  171. self.assertIn('a', self.state)
  172. self.assertIn('b', self.state)
  173. self.assertIn('c', self.state)