test_stdio.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Tests for L{twisted.internet.stdio}.
  5. """
  6. from __future__ import absolute_import, division
  7. from twisted.python.runtime import platform
  8. from twisted.internet.test.reactormixins import ReactorBuilder
  9. from twisted.internet.protocol import Protocol
  10. if not platform.isWindows():
  11. from twisted.internet.stdio import StandardIO
  12. class StdioFilesTests(ReactorBuilder):
  13. """
  14. L{StandardIO} supports reading and writing to filesystem files.
  15. """
  16. def setUp(self):
  17. path = self.mktemp()
  18. open(path, "wb").close()
  19. self.extraFile = open(path, "rb+")
  20. self.addCleanup(self.extraFile.close)
  21. def test_addReader(self):
  22. """
  23. Adding a filesystem file reader to a reactor will make sure it is
  24. polled.
  25. """
  26. reactor = self.buildReactor()
  27. class DataProtocol(Protocol):
  28. data = b""
  29. def dataReceived(self, data):
  30. self.data += data
  31. # It'd be better to stop reactor on connectionLost, but that
  32. # fails on FreeBSD, probably due to
  33. # http://bugs.python.org/issue9591:
  34. if self.data == b"hello!":
  35. reactor.stop()
  36. path = self.mktemp()
  37. with open(path, "wb") as f:
  38. f.write(b"hello!")
  39. with open(path, "rb") as f:
  40. # Read bytes from a file, deliver them to a protocol instance:
  41. protocol = DataProtocol()
  42. StandardIO(protocol, stdin=f.fileno(),
  43. stdout=self.extraFile.fileno(),
  44. reactor=reactor)
  45. self.runReactor(reactor)
  46. self.assertEqual(protocol.data, b"hello!")
  47. def test_addWriter(self):
  48. """
  49. Adding a filesystem file writer to a reactor will make sure it is
  50. polled.
  51. """
  52. reactor = self.buildReactor()
  53. class DisconnectProtocol(Protocol):
  54. def connectionLost(self, reason):
  55. reactor.stop()
  56. path = self.mktemp()
  57. with open(path, "wb") as f:
  58. # Write bytes to a transport, hopefully have them written to a
  59. # file:
  60. protocol = DisconnectProtocol()
  61. StandardIO(protocol, stdout=f.fileno(),
  62. stdin=self.extraFile.fileno(), reactor=reactor)
  63. protocol.transport.write(b"hello")
  64. protocol.transport.write(b", world")
  65. protocol.transport.loseConnection()
  66. self.runReactor(reactor)
  67. with open(path, "rb") as f:
  68. self.assertEqual(f.read(), b"hello, world")
  69. def test_removeReader(self):
  70. """
  71. Removing a filesystem file reader from a reactor will make sure it is
  72. no longer polled.
  73. """
  74. reactor = self.buildReactor()
  75. self.addCleanup(self.unbuildReactor, reactor)
  76. path = self.mktemp()
  77. open(path, "wb").close()
  78. with open(path, "rb") as f:
  79. # Have the reader added:
  80. stdio = StandardIO(Protocol(), stdin=f.fileno(),
  81. stdout=self.extraFile.fileno(),
  82. reactor=reactor)
  83. self.assertIn(stdio._reader, reactor.getReaders())
  84. stdio._reader.stopReading()
  85. self.assertNotIn(stdio._reader, reactor.getReaders())
  86. def test_removeWriter(self):
  87. """
  88. Removing a filesystem file writer from a reactor will make sure it is
  89. no longer polled.
  90. """
  91. reactor = self.buildReactor()
  92. self.addCleanup(self.unbuildReactor, reactor)
  93. # Cleanup might fail if file is GCed too soon:
  94. self.f = f = open(self.mktemp(), "wb")
  95. # Have the reader added:
  96. protocol = Protocol()
  97. stdio = StandardIO(protocol, stdout=f.fileno(),
  98. stdin=self.extraFile.fileno(),
  99. reactor=reactor)
  100. protocol.transport.write(b"hello")
  101. self.assertIn(stdio._writer, reactor.getWriters())
  102. stdio._writer.stopWriting()
  103. self.assertNotIn(stdio._writer, reactor.getWriters())
  104. def test_removeAll(self):
  105. """
  106. Calling C{removeAll} on a reactor includes descriptors that are
  107. filesystem files.
  108. """
  109. reactor = self.buildReactor()
  110. self.addCleanup(self.unbuildReactor, reactor)
  111. path = self.mktemp()
  112. open(path, "wb").close()
  113. # Cleanup might fail if file is GCed too soon:
  114. self.f = f = open(path, "rb")
  115. # Have the reader added:
  116. stdio = StandardIO(Protocol(), stdin=f.fileno(),
  117. stdout=self.extraFile.fileno(), reactor=reactor)
  118. # And then removed:
  119. removed = reactor.removeAll()
  120. self.assertIn(stdio._reader, removed)
  121. self.assertNotIn(stdio._reader, reactor.getReaders())
  122. def test_getReaders(self):
  123. """
  124. C{reactor.getReaders} includes descriptors that are filesystem files.
  125. """
  126. reactor = self.buildReactor()
  127. self.addCleanup(self.unbuildReactor, reactor)
  128. path = self.mktemp()
  129. open(path, "wb").close()
  130. # Cleanup might fail if file is GCed too soon:
  131. with open(path, "rb") as f:
  132. # Have the reader added:
  133. stdio = StandardIO(Protocol(), stdin=f.fileno(),
  134. stdout=self.extraFile.fileno(), reactor=reactor)
  135. self.assertIn(stdio._reader, reactor.getReaders())
  136. def test_getWriters(self):
  137. """
  138. C{reactor.getWriters} includes descriptors that are filesystem files.
  139. """
  140. reactor = self.buildReactor()
  141. self.addCleanup(self.unbuildReactor, reactor)
  142. # Cleanup might fail if file is GCed too soon:
  143. self.f = f = open(self.mktemp(), "wb")
  144. # Have the reader added:
  145. stdio = StandardIO(Protocol(), stdout=f.fileno(),
  146. stdin=self.extraFile.fileno(), reactor=reactor)
  147. self.assertNotIn(stdio._writer, reactor.getWriters())
  148. stdio._writer.startWriting()
  149. self.assertIn(stdio._writer, reactor.getWriters())
  150. if platform.isWindows():
  151. skip = ("StandardIO does not accept stdout as an argument to Windows. "
  152. "Testing redirection to a file is therefore harder.")
  153. globals().update(StdioFilesTests.makeTestCaseClasses())