test_sigchld.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Tests for L{twisted.internet._sigchld}, an alternate, superior SIGCHLD
  5. monitoring API.
  6. """
  7. from __future__ import division, absolute_import
  8. import os, signal, errno
  9. from twisted.python.runtime import platformType
  10. from twisted.python.log import msg
  11. from twisted.trial.unittest import SynchronousTestCase
  12. if platformType == "posix":
  13. from twisted.internet.fdesc import setNonBlocking
  14. from twisted.internet._signals import installHandler, isDefaultHandler
  15. else:
  16. skip = "These tests can only run on POSIX platforms."
  17. class SetWakeupSIGCHLDTests(SynchronousTestCase):
  18. """
  19. Tests for the L{signal.set_wakeup_fd} implementation of the
  20. L{installHandler} and L{isDefaultHandler} APIs.
  21. """
  22. def pipe(self):
  23. """
  24. Create a non-blocking pipe which will be closed after the currently
  25. running test.
  26. """
  27. read, write = os.pipe()
  28. self.addCleanup(os.close, read)
  29. self.addCleanup(os.close, write)
  30. setNonBlocking(read)
  31. setNonBlocking(write)
  32. return read, write
  33. def setUp(self):
  34. """
  35. Save the current SIGCHLD handler as reported by L{signal.signal} and
  36. the current file descriptor registered with L{installHandler}.
  37. """
  38. handler = signal.getsignal(signal.SIGCHLD)
  39. if handler != signal.SIG_DFL:
  40. self.signalModuleHandler = handler
  41. signal.signal(signal.SIGCHLD, signal.SIG_DFL)
  42. else:
  43. self.signalModuleHandler = None
  44. self.oldFD = installHandler(-1)
  45. if self.signalModuleHandler is not None and self.oldFD != -1:
  46. msg("Previous test didn't clean up after its SIGCHLD setup: %r %r"
  47. % (self.signalModuleHandler, self.oldFD))
  48. def tearDown(self):
  49. """
  50. Restore whatever signal handler was present when setUp ran.
  51. """
  52. # If tests set up any kind of handlers, clear them out.
  53. installHandler(-1)
  54. signal.signal(signal.SIGCHLD, signal.SIG_DFL)
  55. # Now restore whatever the setup was before the test ran.
  56. if self.signalModuleHandler is not None:
  57. signal.signal(signal.SIGCHLD, self.signalModuleHandler)
  58. elif self.oldFD != -1:
  59. installHandler(self.oldFD)
  60. def test_isDefaultHandler(self):
  61. """
  62. L{isDefaultHandler} returns true if the SIGCHLD handler is SIG_DFL,
  63. false otherwise.
  64. """
  65. self.assertTrue(isDefaultHandler())
  66. signal.signal(signal.SIGCHLD, signal.SIG_IGN)
  67. self.assertFalse(isDefaultHandler())
  68. signal.signal(signal.SIGCHLD, signal.SIG_DFL)
  69. self.assertTrue(isDefaultHandler())
  70. signal.signal(signal.SIGCHLD, lambda *args: None)
  71. self.assertFalse(isDefaultHandler())
  72. def test_returnOldFD(self):
  73. """
  74. L{installHandler} returns the previously registered file descriptor.
  75. """
  76. read, write = self.pipe()
  77. oldFD = installHandler(write)
  78. self.assertEqual(installHandler(oldFD), write)
  79. def test_uninstallHandler(self):
  80. """
  81. C{installHandler(-1)} removes the SIGCHLD handler completely.
  82. """
  83. read, write = self.pipe()
  84. self.assertTrue(isDefaultHandler())
  85. installHandler(write)
  86. self.assertFalse(isDefaultHandler())
  87. installHandler(-1)
  88. self.assertTrue(isDefaultHandler())
  89. def test_installHandler(self):
  90. """
  91. The file descriptor passed to L{installHandler} has a byte written to
  92. it when SIGCHLD is delivered to the process.
  93. """
  94. read, write = self.pipe()
  95. installHandler(write)
  96. exc = self.assertRaises(OSError, os.read, read, 1)
  97. self.assertEqual(exc.errno, errno.EAGAIN)
  98. os.kill(os.getpid(), signal.SIGCHLD)
  99. self.assertEqual(len(os.read(read, 5)), 1)