123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
-
- """
- Tests for L{twisted.python.threadable}.
- """
-
- from __future__ import division, absolute_import
-
- import sys, pickle
-
- try:
- import threading
- except ImportError:
- threadingSkip = "Platform lacks thread support"
- else:
- threadingSkip = None
-
- from twisted.python.compat import _PY3
- from twisted.trial import unittest
-
- from twisted.python import threadable
-
- class TestObject:
- synchronized = ['aMethod']
-
- x = -1
- y = 1
-
- def aMethod(self):
- for i in range(10):
- self.x, self.y = self.y, self.x
- self.z = self.x + self.y
- assert self.z == 0, "z == %d, not 0 as expected" % (self.z,)
-
- threadable.synchronize(TestObject)
-
- class SynchronizationTests(unittest.SynchronousTestCase):
- def setUp(self):
- """
- Reduce the CPython check interval so that thread switches happen much
- more often, hopefully exercising more possible race conditions. Also,
- delay actual test startup until the reactor has been started.
- """
- if _PY3:
- if getattr(sys, 'getswitchinterval', None) is not None:
- self.addCleanup(sys.setswitchinterval, sys.getswitchinterval())
- sys.setswitchinterval(0.0000001)
- else:
- if getattr(sys, 'getcheckinterval', None) is not None:
- self.addCleanup(sys.setcheckinterval, sys.getcheckinterval())
- sys.setcheckinterval(7)
-
-
- def test_synchronizedName(self):
- """
- The name of a synchronized method is inaffected by the synchronization
- decorator.
- """
- self.assertEqual("aMethod", TestObject.aMethod.__name__)
-
-
- def test_isInIOThread(self):
- """
- L{threadable.isInIOThread} returns C{True} if and only if it is called
- in the same thread as L{threadable.registerAsIOThread}.
- """
- threadable.registerAsIOThread()
- foreignResult = []
- t = threading.Thread(
- target=lambda: foreignResult.append(threadable.isInIOThread()))
- t.start()
- t.join()
- self.assertFalse(
- foreignResult[0], "Non-IO thread reported as IO thread")
- self.assertTrue(
- threadable.isInIOThread(), "IO thread reported as not IO thread")
-
-
- def testThreadedSynchronization(self):
- o = TestObject()
-
- errors = []
-
- def callMethodLots():
- try:
- for i in range(1000):
- o.aMethod()
- except AssertionError as e:
- errors.append(str(e))
-
- threads = []
- for x in range(5):
- t = threading.Thread(target=callMethodLots)
- threads.append(t)
- t.start()
-
- for t in threads:
- t.join()
-
- if errors:
- raise unittest.FailTest(errors)
-
- if threadingSkip is not None:
- testThreadedSynchronization.skip = threadingSkip
- test_isInIOThread.skip = threadingSkip
-
-
- def testUnthreadedSynchronization(self):
- o = TestObject()
- for i in range(1000):
- o.aMethod()
-
-
-
- class SerializationTests(unittest.SynchronousTestCase):
- def testPickling(self):
- lock = threadable.XLock()
- lockType = type(lock)
- lockPickle = pickle.dumps(lock)
- newLock = pickle.loads(lockPickle)
- self.assertIsInstance(newLock, lockType)
-
- if threadingSkip is not None:
- testPickling.skip = threadingSkip
-
-
- def testUnpickling(self):
- lockPickle = b'ctwisted.python.threadable\nunpickle_lock\np0\n(tp1\nRp2\n.'
- lock = pickle.loads(lockPickle)
- newPickle = pickle.dumps(lock, 2)
- pickle.loads(newPickle)
|