/resources/lib/twisted/twisted/test/test_fdesc.py

https://github.com/analogue/mythbox · Python · 235 lines · 131 code · 38 blank · 66 comment · 20 complexity · 044fcf1db031e64c5a0cef82fb890d63 MD5 · raw file

  1. # Copyright (c) 2007-2009 Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Tests for L{twisted.internet.fdesc}.
  5. """
  6. import os, sys
  7. import errno
  8. try:
  9. import fcntl
  10. except ImportError:
  11. skip = "not supported on this platform"
  12. else:
  13. from twisted.internet import fdesc
  14. from twisted.python.util import untilConcludes
  15. from twisted.trial import unittest
  16. class ReadWriteTestCase(unittest.TestCase):
  17. """
  18. Tests for fdesc.readFromFD, fdesc.writeToFD.
  19. """
  20. def setUp(self):
  21. """
  22. Create two non-blocking pipes that can be used in tests.
  23. """
  24. self.r, self.w = os.pipe()
  25. fdesc.setNonBlocking(self.r)
  26. fdesc.setNonBlocking(self.w)
  27. def tearDown(self):
  28. """
  29. Close pipes.
  30. """
  31. try:
  32. os.close(self.w)
  33. except OSError:
  34. pass
  35. try:
  36. os.close(self.r)
  37. except OSError:
  38. pass
  39. def write(self, d):
  40. """
  41. Write data to the pipe.
  42. """
  43. return fdesc.writeToFD(self.w, d)
  44. def read(self):
  45. """
  46. Read data from the pipe.
  47. """
  48. l = []
  49. res = fdesc.readFromFD(self.r, l.append)
  50. if res is None:
  51. if l:
  52. return l[0]
  53. else:
  54. return ""
  55. else:
  56. return res
  57. def test_writeAndRead(self):
  58. """
  59. Test that the number of bytes L{fdesc.writeToFD} reports as written
  60. with its return value are seen by L{fdesc.readFromFD}.
  61. """
  62. n = self.write("hello")
  63. self.failUnless(n > 0)
  64. s = self.read()
  65. self.assertEquals(len(s), n)
  66. self.assertEquals("hello"[:n], s)
  67. def test_writeAndReadLarge(self):
  68. """
  69. Similar to L{test_writeAndRead}, but use a much larger string to verify
  70. the behavior for that case.
  71. """
  72. orig = "0123456879" * 10000
  73. written = self.write(orig)
  74. self.failUnless(written > 0)
  75. result = []
  76. resultlength = 0
  77. i = 0
  78. while resultlength < written or i < 50:
  79. result.append(self.read())
  80. resultlength += len(result[-1])
  81. # Increment a counter to be sure we'll exit at some point
  82. i += 1
  83. result = "".join(result)
  84. self.assertEquals(len(result), written)
  85. self.assertEquals(orig[:written], result)
  86. def test_readFromEmpty(self):
  87. """
  88. Verify that reading from a file descriptor with no data does not raise
  89. an exception and does not result in the callback function being called.
  90. """
  91. l = []
  92. result = fdesc.readFromFD(self.r, l.append)
  93. self.assertEquals(l, [])
  94. self.assertEquals(result, None)
  95. def test_readFromCleanClose(self):
  96. """
  97. Test that using L{fdesc.readFromFD} on a cleanly closed file descriptor
  98. returns a connection done indicator.
  99. """
  100. os.close(self.w)
  101. self.assertEquals(self.read(), fdesc.CONNECTION_DONE)
  102. def test_writeToClosed(self):
  103. """
  104. Verify that writing with L{fdesc.writeToFD} when the read end is closed
  105. results in a connection lost indicator.
  106. """
  107. os.close(self.r)
  108. self.assertEquals(self.write("s"), fdesc.CONNECTION_LOST)
  109. def test_readFromInvalid(self):
  110. """
  111. Verify that reading with L{fdesc.readFromFD} when the read end is
  112. closed results in a connection lost indicator.
  113. """
  114. os.close(self.r)
  115. self.assertEquals(self.read(), fdesc.CONNECTION_LOST)
  116. def test_writeToInvalid(self):
  117. """
  118. Verify that writing with L{fdesc.writeToFD} when the write end is
  119. closed results in a connection lost indicator.
  120. """
  121. os.close(self.w)
  122. self.assertEquals(self.write("s"), fdesc.CONNECTION_LOST)
  123. def test_writeErrors(self):
  124. """
  125. Test error path for L{fdesc.writeTod}.
  126. """
  127. oldOsWrite = os.write
  128. def eagainWrite(fd, data):
  129. err = OSError()
  130. err.errno = errno.EAGAIN
  131. raise err
  132. os.write = eagainWrite
  133. try:
  134. self.assertEquals(self.write("s"), 0)
  135. finally:
  136. os.write = oldOsWrite
  137. def eintrWrite(fd, data):
  138. err = OSError()
  139. err.errno = errno.EINTR
  140. raise err
  141. os.write = eintrWrite
  142. try:
  143. self.assertEquals(self.write("s"), 0)
  144. finally:
  145. os.write = oldOsWrite
  146. class CloseOnExecTests(unittest.TestCase):
  147. """
  148. Tests for L{fdesc._setCloseOnExec} and L{fdesc._unsetCloseOnExec}.
  149. """
  150. program = '''
  151. import os, errno
  152. try:
  153. os.write(%d, 'lul')
  154. except OSError, e:
  155. if e.errno == errno.EBADF:
  156. os._exit(0)
  157. os._exit(5)
  158. except:
  159. os._exit(10)
  160. else:
  161. os._exit(20)
  162. '''
  163. def _execWithFileDescriptor(self, fObj):
  164. pid = os.fork()
  165. if pid == 0:
  166. try:
  167. os.execv(sys.executable, [sys.executable, '-c', self.program % (fObj.fileno(),)])
  168. except:
  169. import traceback
  170. traceback.print_exc()
  171. os._exit(30)
  172. else:
  173. # On Linux wait(2) doesn't seem ever able to fail with EINTR but
  174. # POSIX seems to allow it and on OS X it happens quite a lot.
  175. return untilConcludes(os.waitpid, pid, 0)[1]
  176. def test_setCloseOnExec(self):
  177. """
  178. A file descriptor passed to L{fdesc._setCloseOnExec} is not inherited
  179. by a new process image created with one of the exec family of
  180. functions.
  181. """
  182. fObj = file(self.mktemp(), 'w')
  183. fdesc._setCloseOnExec(fObj.fileno())
  184. status = self._execWithFileDescriptor(fObj)
  185. self.assertTrue(os.WIFEXITED(status))
  186. self.assertEqual(os.WEXITSTATUS(status), 0)
  187. def test_unsetCloseOnExec(self):
  188. """
  189. A file descriptor passed to L{fdesc._unsetCloseOnExec} is inherited by
  190. a new process image created with one of the exec family of functions.
  191. """
  192. fObj = file(self.mktemp(), 'w')
  193. fdesc._setCloseOnExec(fObj.fileno())
  194. fdesc._unsetCloseOnExec(fObj.fileno())
  195. status = self._execWithFileDescriptor(fObj)
  196. self.assertTrue(os.WIFEXITED(status))
  197. self.assertEqual(os.WEXITSTATUS(status), 20)