/vendor/packages/twisted/twisted/internet/test/test_threads.py

https://github.com/openhatch/oh-mainline
Python | 164 lines | 68 code | 24 blank | 72 comment | 2 complexity | 48beb76a50dadb73c6cf2e9545057f6d MD5 | raw file
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Tests for implementations of L{IReactorThreads}.
  5. """
  6. __metaclass__ = type
  7. from weakref import ref
  8. import gc
  9. from twisted.internet.test.reactormixins import ReactorBuilder
  10. from twisted.python.threadpool import ThreadPool
  11. class ThreadTestsBuilder(ReactorBuilder):
  12. """
  13. Builder for defining tests relating to L{IReactorThreads}.
  14. """
  15. def test_getThreadPool(self):
  16. """
  17. C{reactor.getThreadPool()} returns an instance of L{ThreadPool} which
  18. starts when C{reactor.run()} is called and stops before it returns.
  19. """
  20. state = []
  21. reactor = self.buildReactor()
  22. pool = reactor.getThreadPool()
  23. self.assertIsInstance(pool, ThreadPool)
  24. self.assertFalse(
  25. pool.started, "Pool should not start before reactor.run")
  26. def f():
  27. # Record the state for later assertions
  28. state.append(pool.started)
  29. state.append(pool.joined)
  30. reactor.stop()
  31. reactor.callWhenRunning(f)
  32. self.runReactor(reactor, 2)
  33. self.assertTrue(
  34. state[0], "Pool should start after reactor.run")
  35. self.assertFalse(
  36. state[1], "Pool should not be joined before reactor.stop")
  37. self.assertTrue(
  38. pool.joined,
  39. "Pool should be stopped after reactor.run returns")
  40. def test_suggestThreadPoolSize(self):
  41. """
  42. C{reactor.suggestThreadPoolSize()} sets the maximum size of the reactor
  43. threadpool.
  44. """
  45. reactor = self.buildReactor()
  46. reactor.suggestThreadPoolSize(17)
  47. pool = reactor.getThreadPool()
  48. self.assertEqual(pool.max, 17)
  49. def test_delayedCallFromThread(self):
  50. """
  51. A function scheduled with L{IReactorThreads.callFromThread} invoked
  52. from a delayed call is run immediately in the next reactor iteration.
  53. When invoked from the reactor thread, previous implementations of
  54. L{IReactorThreads.callFromThread} would skip the pipe/socket based wake
  55. up step, assuming the reactor would wake up on its own. However, this
  56. resulted in the reactor not noticing a insert into the thread queue at
  57. the right time (in this case, after the thread queue has been processed
  58. for that reactor iteration).
  59. """
  60. reactor = self.buildReactor()
  61. def threadCall():
  62. reactor.stop()
  63. # Set up the use of callFromThread being tested.
  64. reactor.callLater(0, reactor.callFromThread, threadCall)
  65. before = reactor.seconds()
  66. self.runReactor(reactor, 60)
  67. after = reactor.seconds()
  68. # We specified a timeout of 60 seconds. The timeout code in runReactor
  69. # probably won't actually work, though. If the reactor comes out of
  70. # the event notification API just a little bit early, say after 59.9999
  71. # seconds instead of after 60 seconds, then the queued thread call will
  72. # get processed but the timeout delayed call runReactor sets up won't!
  73. # Then the reactor will stop and runReactor will return without the
  74. # timeout firing. As it turns out, select() and poll() are quite
  75. # likely to return *slightly* earlier than we ask them to, so the
  76. # timeout will rarely happen, even if callFromThread is broken. So,
  77. # instead we'll measure the elapsed time and make sure it's something
  78. # less than about half of the timeout we specified. This is heuristic.
  79. # It assumes that select() won't ever return after 30 seconds when we
  80. # asked it to timeout after 60 seconds. And of course like all
  81. # time-based tests, it's slightly non-deterministic. If the OS doesn't
  82. # schedule this process for 30 seconds, then the test might fail even
  83. # if callFromThread is working.
  84. self.assertTrue(after - before < 30)
  85. def test_stopThreadPool(self):
  86. """
  87. When the reactor stops, L{ReactorBase._stopThreadPool} drops the
  88. reactor's direct reference to its internal threadpool and removes
  89. the associated startup and shutdown triggers.
  90. This is the case of the thread pool being created before the reactor
  91. is run.
  92. """
  93. reactor = self.buildReactor()
  94. threadpool = ref(reactor.getThreadPool())
  95. reactor.callWhenRunning(reactor.stop)
  96. self.runReactor(reactor)
  97. gc.collect()
  98. self.assertIdentical(threadpool(), None)
  99. def test_stopThreadPoolWhenStartedAfterReactorRan(self):
  100. """
  101. We must handle the case of shutting down the thread pool when it was
  102. started after the reactor was run in a special way.
  103. Some implementation background: The thread pool is started with
  104. callWhenRunning, which only returns a system trigger ID when it is
  105. invoked before the reactor is started.
  106. This is the case of the thread pool being created after the reactor
  107. is started.
  108. """
  109. reactor = self.buildReactor()
  110. threadPoolRefs = []
  111. def acquireThreadPool():
  112. threadPoolRefs.append(ref(reactor.getThreadPool()))
  113. reactor.stop()
  114. reactor.callWhenRunning(acquireThreadPool)
  115. self.runReactor(reactor)
  116. gc.collect()
  117. self.assertIdentical(threadPoolRefs[0](), None)
  118. def test_cleanUpThreadPoolEvenBeforeReactorIsRun(self):
  119. """
  120. When the reactor has its shutdown event fired before it is run, the
  121. thread pool is completely destroyed.
  122. For what it's worth, the reason we support this behavior at all is
  123. because Trial does this.
  124. This is the case of the thread pool being created without the reactor
  125. being started at al.
  126. """
  127. reactor = self.buildReactor()
  128. threadPoolRef = ref(reactor.getThreadPool())
  129. reactor.fireSystemEvent("shutdown")
  130. gc.collect()
  131. self.assertIdentical(threadPoolRef(), None)
  132. globals().update(ThreadTestsBuilder.makeTestCaseClasses())