##// END OF EJS Templates
Test that the system() subprocess can be interrupted.
Itamar Turner-Trauring -
Show More
@@ -1,144 +1,172 b''
1 1 # encoding: utf-8
2 2 """
3 3 Tests for platutils.py
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import sys
18 18 import os
19 import time
20 from _thread import interrupt_main # Py 3
21 import threading
19 22
20 23 import nose.tools as nt
21 24
22 25 from IPython.utils.process import (find_cmd, FindCmdError, arg_split,
23 26 system, getoutput, getoutputerror,
24 27 get_output_error_code)
25 28 from IPython.testing import decorators as dec
26 29 from IPython.testing import tools as tt
27 30
28 31 python = os.path.basename(sys.executable)
29 32
30 33 #-----------------------------------------------------------------------------
31 34 # Tests
32 35 #-----------------------------------------------------------------------------
33 36
34 37
35 38 @dec.skip_win32
36 39 def test_find_cmd_ls():
37 40 """Make sure we can find the full path to ls."""
38 41 path = find_cmd('ls')
39 42 nt.assert_true(path.endswith('ls'))
40 43
41 44
42 45 def has_pywin32():
43 46 try:
44 47 import win32api
45 48 except ImportError:
46 49 return False
47 50 return True
48 51
49 52
50 53 @dec.onlyif(has_pywin32, "This test requires win32api to run")
51 54 def test_find_cmd_pythonw():
52 55 """Try to find pythonw on Windows."""
53 56 path = find_cmd('pythonw')
54 57 assert path.lower().endswith('pythonw.exe'), path
55 58
56 59
57 60 @dec.onlyif(lambda : sys.platform != 'win32' or has_pywin32(),
58 61 "This test runs on posix or in win32 with win32api installed")
59 62 def test_find_cmd_fail():
60 63 """Make sure that FindCmdError is raised if we can't find the cmd."""
61 64 nt.assert_raises(FindCmdError,find_cmd,'asdfasdf')
62 65
63 66
64 67 @dec.skip_win32
65 68 def test_arg_split():
66 69 """Ensure that argument lines are correctly split like in a shell."""
67 70 tests = [['hi', ['hi']],
68 71 [u'hi', [u'hi']],
69 72 ['hello there', ['hello', 'there']],
70 73 # \u01ce == \N{LATIN SMALL LETTER A WITH CARON}
71 74 # Do not use \N because the tests crash with syntax error in
72 75 # some cases, for example windows python2.6.
73 76 [u'h\u01cello', [u'h\u01cello']],
74 77 ['something "with quotes"', ['something', '"with quotes"']],
75 78 ]
76 79 for argstr, argv in tests:
77 80 nt.assert_equal(arg_split(argstr), argv)
78 81
79 82 @dec.skip_if_not_win32
80 83 def test_arg_split_win32():
81 84 """Ensure that argument lines are correctly split like in a shell."""
82 85 tests = [['hi', ['hi']],
83 86 [u'hi', [u'hi']],
84 87 ['hello there', ['hello', 'there']],
85 88 [u'h\u01cello', [u'h\u01cello']],
86 89 ['something "with quotes"', ['something', 'with quotes']],
87 90 ]
88 91 for argstr, argv in tests:
89 92 nt.assert_equal(arg_split(argstr), argv)
90 93
91 94
92 95 class SubProcessTestCase(tt.TempFileMixin):
93 96 def setUp(self):
94 97 """Make a valid python temp file."""
95 98 lines = [ "import sys",
96 99 "print('on stdout', end='', file=sys.stdout)",
97 100 "print('on stderr', end='', file=sys.stderr)",
98 101 "sys.stdout.flush()",
99 102 "sys.stderr.flush()"]
100 103 self.mktmp('\n'.join(lines))
101 104
102 105 def test_system(self):
103 106 status = system('%s "%s"' % (python, self.fname))
104 107 self.assertEqual(status, 0)
105 108
106 109 def test_system_quotes(self):
107 110 status = system('%s -c "import sys"' % python)
108 111 self.assertEqual(status, 0)
109 112
113 def test_system_interrupt(self):
114 """
115 When interrupted in the way ipykernel interrupts IPython, the
116 subprocess is interrupted.
117 """
118 if threading.main_thread() != threading.current_thread():
119 raise nt.SkipTest("Can't run this test if not in main thread.")
120
121 def interrupt():
122 # Wait for subprocess to start:
123 time.sleep(0.5)
124 interrupt_main()
125
126 threading.Thread(target=interrupt).start()
127 try:
128 status = system('%s -c "import time; time.sleep(5)"' % python)
129 except KeyboardInterrupt:
130 # Success!
131 return
132 self.assertNotEqual(
133 status, 0, "The process wasn't interrupted. Status: %s" % (status,)
134 )
135
110 136 def test_getoutput(self):
111 137 out = getoutput('%s "%s"' % (python, self.fname))
112 138 # we can't rely on the order the line buffered streams are flushed
113 139 try:
114 140 self.assertEqual(out, 'on stderron stdout')
115 141 except AssertionError:
116 142 self.assertEqual(out, 'on stdouton stderr')
117 143
118 144 def test_getoutput_quoted(self):
119 145 out = getoutput('%s -c "print (1)"' % python)
120 146 self.assertEqual(out.strip(), '1')
121 147
122 148 #Invalid quoting on windows
123 149 @dec.skip_win32
124 150 def test_getoutput_quoted2(self):
125 151 out = getoutput("%s -c 'print (1)'" % python)
126 152 self.assertEqual(out.strip(), '1')
127 153 out = getoutput("%s -c 'print (\"1\")'" % python)
128 154 self.assertEqual(out.strip(), '1')
129 155
130 156 def test_getoutput_error(self):
131 157 out, err = getoutputerror('%s "%s"' % (python, self.fname))
132 158 self.assertEqual(out, 'on stdout')
133 159 self.assertEqual(err, 'on stderr')
134 160
135 161 def test_get_output_error_code(self):
136 162 quiet_exit = '%s -c "import sys; sys.exit(1)"' % python
137 163 out, err, code = get_output_error_code(quiet_exit)
138 164 self.assertEqual(out, '')
139 165 self.assertEqual(err, '')
140 166 self.assertEqual(code, 1)
141 167 out, err, code = get_output_error_code('%s "%s"' % (python, self.fname))
142 168 self.assertEqual(out, 'on stdout')
143 169 self.assertEqual(err, 'on stderr')
144 170 self.assertEqual(code, 0)
171
172
General Comments 0
You need to be logged in to leave comments. Login now