You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_threadable.py 3.7KB

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Tests for L{twisted.python.threadable}.
  5. """
  6. from __future__ import division, absolute_import
  7. import sys, pickle
  8. try:
  9. import threading
  10. except ImportError:
  11. threadingSkip = "Platform lacks thread support"
  12. else:
  13. threadingSkip = None
  14. from twisted.python.compat import _PY3
  15. from twisted.trial import unittest
  16. from twisted.python import threadable
  17. class TestObject:
  18. synchronized = ['aMethod']
  19. x = -1
  20. y = 1
  21. def aMethod(self):
  22. for i in range(10):
  23. self.x, self.y = self.y, self.x
  24. self.z = self.x + self.y
  25. assert self.z == 0, "z == %d, not 0 as expected" % (self.z,)
  26. threadable.synchronize(TestObject)
  27. class SynchronizationTests(unittest.SynchronousTestCase):
  28. def setUp(self):
  29. """
  30. Reduce the CPython check interval so that thread switches happen much
  31. more often, hopefully exercising more possible race conditions. Also,
  32. delay actual test startup until the reactor has been started.
  33. """
  34. if _PY3:
  35. if getattr(sys, 'getswitchinterval', None) is not None:
  36. self.addCleanup(sys.setswitchinterval, sys.getswitchinterval())
  37. sys.setswitchinterval(0.0000001)
  38. else:
  39. if getattr(sys, 'getcheckinterval', None) is not None:
  40. self.addCleanup(sys.setcheckinterval, sys.getcheckinterval())
  41. sys.setcheckinterval(7)
  42. def test_synchronizedName(self):
  43. """
  44. The name of a synchronized method is inaffected by the synchronization
  45. decorator.
  46. """
  47. self.assertEqual("aMethod", TestObject.aMethod.__name__)
  48. def test_isInIOThread(self):
  49. """
  50. L{threadable.isInIOThread} returns C{True} if and only if it is called
  51. in the same thread as L{threadable.registerAsIOThread}.
  52. """
  53. threadable.registerAsIOThread()
  54. foreignResult = []
  55. t = threading.Thread(
  56. target=lambda: foreignResult.append(threadable.isInIOThread()))
  57. t.start()
  58. t.join()
  59. self.assertFalse(
  60. foreignResult[0], "Non-IO thread reported as IO thread")
  61. self.assertTrue(
  62. threadable.isInIOThread(), "IO thread reported as not IO thread")
  63. def testThreadedSynchronization(self):
  64. o = TestObject()
  65. errors = []
  66. def callMethodLots():
  67. try:
  68. for i in range(1000):
  69. o.aMethod()
  70. except AssertionError as e:
  71. errors.append(str(e))
  72. threads = []
  73. for x in range(5):
  74. t = threading.Thread(target=callMethodLots)
  75. threads.append(t)
  76. t.start()
  77. for t in threads:
  78. t.join()
  79. if errors:
  80. raise unittest.FailTest(errors)
  81. if threadingSkip is not None:
  82. testThreadedSynchronization.skip = threadingSkip
  83. test_isInIOThread.skip = threadingSkip
  84. def testUnthreadedSynchronization(self):
  85. o = TestObject()
  86. for i in range(1000):
  87. o.aMethod()
  88. class SerializationTests(unittest.SynchronousTestCase):
  89. def testPickling(self):
  90. lock = threadable.XLock()
  91. lockType = type(lock)
  92. lockPickle = pickle.dumps(lock)
  93. newLock = pickle.loads(lockPickle)
  94. self.assertIsInstance(newLock, lockType)
  95. if threadingSkip is not None:
  96. testPickling.skip = threadingSkip
  97. def testUnpickling(self):
  98. lockPickle = b'ctwisted.python.threadable\nunpickle_lock\np0\n(tp1\nRp2\n.'
  99. lock = pickle.loads(lockPickle)
  100. newPickle = pickle.dumps(lock, 2)
  101. pickle.loads(newPickle)