test_vt.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. # -*- coding: utf-8 -*-
  2. '''
  3. :codeauthor: Pedro Algarvio (pedro@algarvio.me)
  4. tests.unit.utils.vt_test
  5. ~~~~~~~~~~~~~~~~~~~~~~~~
  6. VirtualTerminal tests
  7. '''
  8. # Import Python libs
  9. from __future__ import absolute_import, print_function, unicode_literals
  10. import os
  11. import sys
  12. import random
  13. import subprocess
  14. import time
  15. # Import Salt Testing libs
  16. from tests.support.unit import TestCase, skipIf
  17. # Import Salt libs
  18. import salt.utils.files
  19. import salt.utils.platform
  20. import salt.utils.vt
  21. # Import 3rd-party libs
  22. from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
  23. class VTTestCase(TestCase):
  24. @skipIf(True, 'Disabled until we can figure out why this fails when whole test suite runs.')
  25. def test_vt_size(self):
  26. '''Confirm that the terminal size is being set'''
  27. if not sys.stdin.isatty():
  28. self.skipTest('Not attached to a TTY. The test would fail.')
  29. cols = random.choice(range(80, 250))
  30. terminal = salt.utils.vt.Terminal(
  31. 'echo "Foo!"',
  32. shell=True,
  33. cols=cols,
  34. rows=24,
  35. stream_stdout=False,
  36. stream_stderr=False
  37. )
  38. # First the assertion
  39. self.assertEqual(
  40. terminal.getwinsize(), (24, cols)
  41. )
  42. # Then wait for the terminal child to exit
  43. terminal.wait()
  44. terminal.close()
  45. @skipIf(True, 'Disabled until we can find out why this kills the tests suite with an exit code of 134')
  46. def test_issue_10404_ptys_not_released(self):
  47. n_executions = 15
  48. def current_pty_count():
  49. # Get current number of PTY's
  50. try:
  51. if os.path.exists('/proc/sys/kernel/pty/nr'):
  52. with salt.utils.files.fopen('/proc/sys/kernel/pty/nr') as fh_:
  53. return int(fh_.read().strip())
  54. proc = subprocess.Popen(
  55. 'sysctl -a 2> /dev/null | grep pty.nr | awk \'{print $3}\'',
  56. shell=True,
  57. stdout=subprocess.PIPE
  58. )
  59. stdout, _ = proc.communicate()
  60. return int(stdout.strip())
  61. except (ValueError, OSError, IOError):
  62. if salt.utils.platform.is_darwin():
  63. # We're unable to findout how many PTY's are open
  64. self.skipTest(
  65. 'Unable to find out how many PTY\'s are open on Darwin - '
  66. 'Skipping for now'
  67. )
  68. self.fail('Unable to find out how many PTY\'s are open')
  69. nr_ptys = current_pty_count()
  70. # Using context manager's
  71. for idx in range(0, nr_ptys + n_executions):
  72. try:
  73. with salt.utils.vt.Terminal('echo "Run {0}"'.format(idx),
  74. shell=True,
  75. stream_stdout=False,
  76. stream_stderr=False) as terminal:
  77. terminal.wait()
  78. try:
  79. if current_pty_count() > (nr_ptys + (n_executions/2)):
  80. self.fail('VT is not cleaning up PTY\'s')
  81. except (ValueError, OSError, IOError):
  82. self.fail('Unable to find out how many PTY\'s are open')
  83. except Exception as exc: # pylint: disable=broad-except
  84. if 'out of pty devices' in str(exc):
  85. # We're not cleaning up
  86. raise
  87. # We're pushing the system resources, let's keep going
  88. continue
  89. # Not using context manager's
  90. for idx in range(0, nr_ptys + n_executions):
  91. try:
  92. terminal = salt.utils.vt.Terminal('echo "Run {0}"'.format(idx),
  93. shell=True,
  94. stream_stdout=False,
  95. stream_stderr=False)
  96. terminal.wait()
  97. try:
  98. if current_pty_count() > (nr_ptys + (n_executions/2)):
  99. self.fail('VT is not cleaning up PTY\'s')
  100. except (ValueError, OSError, IOError):
  101. self.fail('Unable to find out how many PTY\'s are open')
  102. except Exception as exc: # pylint: disable=broad-except
  103. if 'out of pty devices' in str(exc):
  104. # We're not cleaning up
  105. raise
  106. # We're pushing the system resources, let's keep going
  107. continue
  108. @skipIf(True, 'Disabled until we can figure out how to make this more reliable.')
  109. def test_isalive_while_theres_data_to_read(self):
  110. expected_data = 'Alive!\n'
  111. term = salt.utils.vt.Terminal('echo "Alive!"',
  112. shell=True,
  113. stream_stdout=False,
  114. stream_stderr=False)
  115. buffer_o = buffer_e = ''
  116. try:
  117. while term.has_unread_data:
  118. stdout, stderr = term.recv()
  119. if stdout:
  120. buffer_o += stdout
  121. if stderr:
  122. buffer_e += stderr
  123. # While there's data to be read, the process is alive
  124. if stdout is None and stderr is None:
  125. self.assertFalse(term.isalive())
  126. # term should be dead now
  127. self.assertEqual(buffer_o, expected_data)
  128. self.assertFalse(term.isalive())
  129. stdout, stderr = term.recv()
  130. self.assertFalse(term.isalive())
  131. self.assertIsNone(stderr)
  132. self.assertIsNone(stdout)
  133. finally:
  134. term.close(terminate=True, kill=True)
  135. expected_data = 'Alive!\n'
  136. term = salt.utils.vt.Terminal('echo "Alive!" 1>&2',
  137. shell=True,
  138. stream_stdout=False,
  139. stream_stderr=False)
  140. buffer_o = buffer_e = ''
  141. try:
  142. while term.has_unread_data:
  143. stdout, stderr = term.recv()
  144. if stdout:
  145. buffer_o += stdout
  146. if stderr:
  147. buffer_e += stderr
  148. # While there's data to be read, the process is alive
  149. if stdout is None and stderr is None:
  150. self.assertFalse(term.isalive())
  151. # term should be dead now
  152. self.assertEqual(buffer_e, expected_data)
  153. self.assertFalse(term.isalive())
  154. stdout, stderr = term.recv()
  155. self.assertFalse(term.isalive())
  156. self.assertIsNone(stderr)
  157. self.assertIsNone(stdout)
  158. finally:
  159. term.close(terminate=True, kill=True)
  160. expected_data = 'Alive!\nAlive!\n'
  161. term = salt.utils.vt.Terminal('echo "Alive!"; sleep 5; echo "Alive!"',
  162. shell=True,
  163. stream_stdout=False,
  164. stream_stderr=False)
  165. buffer_o = buffer_e = ''
  166. try:
  167. while term.has_unread_data:
  168. stdout, stderr = term.recv()
  169. if stdout:
  170. buffer_o += stdout
  171. if stderr:
  172. buffer_e += stderr
  173. # While there's data to be read, the process is alive
  174. if stdout is None and stderr is None:
  175. self.assertFalse(term.isalive())
  176. if buffer_o != expected_data:
  177. self.assertTrue(term.isalive())
  178. # Don't spin
  179. time.sleep(0.1)
  180. # term should be dead now
  181. self.assertEqual(buffer_o, expected_data)
  182. self.assertFalse(term.isalive())
  183. stdout, stderr = term.recv()
  184. self.assertFalse(term.isalive())
  185. self.assertIsNone(stderr)
  186. self.assertIsNone(stdout)
  187. finally:
  188. term.close(terminate=True, kill=True)