blob: e0cfd04a23b7a280b2321cc23a782c2e2ec43ac3 [file] [log] [blame]
[email protected]eba40222011-04-05 14:52:481#!/usr/bin/env python
2# Copyright (c) 2011 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Unit tests for subprocess2.py."""
7
[email protected]4942e4a2011-11-15 15:50:508import logging
[email protected]eba40222011-04-05 14:52:489import optparse
10import os
11import sys
12import time
13import unittest
14
[email protected]4942e4a2011-11-15 15:50:5015try:
16 import fcntl
17except ImportError:
18 fcntl = None
19
[email protected]428342a2011-11-10 15:46:3320sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
[email protected]eba40222011-04-05 14:52:4821
22import subprocess2
23
[email protected]7bb06bb2011-11-29 15:22:0624from testing_support import auto_stub
25
[email protected]4942e4a2011-11-15 15:50:5026# Method could be a function
27# pylint: disable=R0201
28
29
30def convert_to_crlf(string):
31 """Unconditionally convert LF to CRLF."""
32 return string.replace('\n', '\r\n')
33
34
35def convert_to_cr(string):
36 """Unconditionally convert LF to CR."""
37 return string.replace('\n', '\r')
38
39
40def convert_win(string):
41 """Converts string to CRLF on Windows only."""
42 if sys.platform == 'win32':
43 return string.replace('\n', '\r\n')
44 return string
45
46
[email protected]7bb06bb2011-11-29 15:22:0647class DefaultsTest(auto_stub.TestCase):
48 # TODO(maruel): Do a reopen() on sys.__stdout__ and sys.__stderr__ so they
49 # can be trapped in the child process for better coverage.
50 def _fake_communicate(self):
[email protected]ef77f9e2011-11-24 15:24:0251 """Mocks subprocess2.communicate()."""
[email protected]eba40222011-04-05 14:52:4852 results = {}
[email protected]1f063db2011-04-18 19:04:5253 def fake_communicate(args, **kwargs):
[email protected]f08b09c2011-04-06 13:14:2754 assert not results
[email protected]eba40222011-04-05 14:52:4855 results.update(kwargs)
56 results['args'] = args
[email protected]ef77f9e2011-11-24 15:24:0257 return ('stdout', 'stderr'), 0
[email protected]7bb06bb2011-11-29 15:22:0658 self.mock(subprocess2, 'communicate', fake_communicate)
[email protected]eba40222011-04-05 14:52:4859 return results
60
[email protected]7bb06bb2011-11-29 15:22:0661 def _fake_Popen(self):
[email protected]ef77f9e2011-11-24 15:24:0262 """Mocks the whole subprocess2.Popen class."""
[email protected]f08b09c2011-04-06 13:14:2763 results = {}
64 class fake_Popen(object):
65 returncode = -8
66 def __init__(self, args, **kwargs):
67 assert not results
68 results.update(kwargs)
69 results['args'] = args
[email protected]428342a2011-11-10 15:46:3370 @staticmethod
71 def communicate():
[email protected]f08b09c2011-04-06 13:14:2772 return None, None
[email protected]7bb06bb2011-11-29 15:22:0673 self.mock(subprocess2, 'Popen', fake_Popen)
[email protected]f08b09c2011-04-06 13:14:2774 return results
75
[email protected]7bb06bb2011-11-29 15:22:0676 def _fake_subprocess_Popen(self):
[email protected]ef77f9e2011-11-24 15:24:0277 """Mocks the base class subprocess.Popen only."""
[email protected]f08b09c2011-04-06 13:14:2778 results = {}
[email protected]ef77f9e2011-11-24 15:24:0279 def __init__(self, args, **kwargs):
80 assert not results
81 results.update(kwargs)
82 results['args'] = args
83 def communicate():
84 return None, None
[email protected]7bb06bb2011-11-29 15:22:0685 self.mock(subprocess2.subprocess.Popen, '__init__', __init__)
86 self.mock(subprocess2.subprocess.Popen, 'communicate', communicate)
[email protected]f08b09c2011-04-06 13:14:2787 return results
88
[email protected]eba40222011-04-05 14:52:4889 def test_check_call_defaults(self):
[email protected]1f063db2011-04-18 19:04:5290 results = self._fake_communicate()
[email protected]eba40222011-04-05 14:52:4891 self.assertEquals(
[email protected]ef77f9e2011-11-24 15:24:0292 ('stdout', 'stderr'), subprocess2.check_call_out(['foo'], a=True))
[email protected]eba40222011-04-05 14:52:4893 expected = {
94 'args': ['foo'],
95 'a':True,
96 }
97 self.assertEquals(expected, results)
98
[email protected]87e6d332011-09-09 19:01:2899 def test_capture_defaults(self):
100 results = self._fake_communicate()
101 self.assertEquals(
102 'stdout', subprocess2.capture(['foo'], a=True))
103 expected = {
104 'args': ['foo'],
105 'a':True,
106 'stdin': subprocess2.VOID,
107 'stdout': subprocess2.PIPE,
108 }
109 self.assertEquals(expected, results)
110
[email protected]1f063db2011-04-18 19:04:52111 def test_communicate_defaults(self):
[email protected]f08b09c2011-04-06 13:14:27112 results = self._fake_Popen()
[email protected]1f063db2011-04-18 19:04:52113 self.assertEquals(
114 ((None, None), -8), subprocess2.communicate(['foo'], a=True))
[email protected]f08b09c2011-04-06 13:14:27115 expected = {
116 'args': ['foo'],
117 'a': True,
118 }
119 self.assertEquals(expected, results)
120
121 def test_Popen_defaults(self):
122 results = self._fake_subprocess_Popen()
123 proc = subprocess2.Popen(['foo'], a=True)
[email protected]ef77f9e2011-11-24 15:24:02124 # Cleanup code in subprocess.py needs this member to be set.
125 # pylint: disable=W0201
126 proc._child_created = None
127 # Since subprocess.Popen.__init__() is not called, proc.returncode shouldn't
128 # be present.
129 self.assertFalse(hasattr(proc, 'returncode'))
[email protected]f08b09c2011-04-06 13:14:27130 expected = {
131 'args': ['foo'],
132 'a': True,
133 'shell': bool(sys.platform=='win32'),
[email protected]f08b09c2011-04-06 13:14:27134 }
[email protected]c98c0c52011-04-06 13:39:43135 if sys.platform != 'win32':
136 env = os.environ.copy()
137 is_english = lambda name: env.get(name, 'en').startswith('en')
138 if not is_english('LANG'):
139 env['LANG'] = 'en_US.UTF-8'
140 expected['env'] = env
141 if not is_english('LANGUAGE'):
142 env['LANGUAGE'] = 'en_US.UTF-8'
143 expected['env'] = env
[email protected]f08b09c2011-04-06 13:14:27144 self.assertEquals(expected, results)
145
[email protected]eba40222011-04-05 14:52:48146 def test_check_output_defaults(self):
[email protected]1f063db2011-04-18 19:04:52147 results = self._fake_communicate()
[email protected]eba40222011-04-05 14:52:48148 # It's discarding 'stderr' because it assumes stderr=subprocess2.STDOUT but
[email protected]1f063db2011-04-18 19:04:52149 # fake_communicate() doesn't 'implement' that.
[email protected]eba40222011-04-05 14:52:48150 self.assertEquals('stdout', subprocess2.check_output(['foo'], a=True))
151 expected = {
152 'args': ['foo'],
153 'a':True,
[email protected]4a982272011-04-12 20:49:37154 'stdin': subprocess2.VOID,
[email protected]eba40222011-04-05 14:52:48155 'stdout': subprocess2.PIPE,
[email protected]eba40222011-04-05 14:52:48156 }
157 self.assertEquals(expected, results)
158
[email protected]4942e4a2011-11-15 15:50:50159
160class S2Test(unittest.TestCase):
161 def setUp(self):
162 super(S2Test, self).setUp()
163 self.exe_path = __file__
164 self.exe = [sys.executable, self.exe_path, '--child']
165 self.states = {}
166 if fcntl:
167 for v in (sys.stdin, sys.stdout, sys.stderr):
168 fileno = v.fileno()
169 self.states[fileno] = fcntl.fcntl(fileno, fcntl.F_GETFL)
170
171 def tearDown(self):
172 for fileno, fl in self.states.iteritems():
173 self.assertEquals(fl, fcntl.fcntl(fileno, fcntl.F_GETFL))
174 super(S2Test, self).tearDown()
175
176 def _run_test(self, function):
177 """Runs tests in 6 combinations:
178 - LF output with universal_newlines=False
179 - CR output with universal_newlines=False
180 - CRLF output with universal_newlines=False
181 - LF output with universal_newlines=True
182 - CR output with universal_newlines=True
183 - CRLF output with universal_newlines=True
184
185 First |function| argument is the convertion for the origianl expected LF
186 string to the right EOL.
187 Second |function| argument is the executable and initial flag to run, to
188 control what EOL is used by the child process.
189 Third |function| argument is universal_newlines value.
190 """
191 noop = lambda x: x
192 function(noop, self.exe, False)
193 function(convert_to_cr, self.exe + ['--cr'], False)
194 function(convert_to_crlf, self.exe + ['--crlf'], False)
195 function(noop, self.exe, True)
196 function(noop, self.exe + ['--cr'], True)
197 function(noop, self.exe + ['--crlf'], True)
198
[email protected]f2dca4e2011-11-09 19:24:48199 def test_timeout(self):
200 out, returncode = subprocess2.communicate(
[email protected]4942e4a2011-11-15 15:50:50201 self.exe + ['--sleep_first', '--stdout'],
[email protected]f2dca4e2011-11-09 19:24:48202 timeout=0.01,
[email protected]4942e4a2011-11-15 15:50:50203 stdout=subprocess2.PIPE,
204 shell=False)
[email protected]f2dca4e2011-11-09 19:24:48205 self.assertEquals(subprocess2.TIMED_OUT, returncode)
[email protected]4942e4a2011-11-15 15:50:50206 self.assertEquals(('', None), out)
[email protected]f2dca4e2011-11-09 19:24:48207
[email protected]87e6d332011-09-09 19:01:28208 def test_check_output_no_stdout(self):
209 try:
210 subprocess2.check_output(self.exe, stdout=subprocess2.PIPE)
211 self.fail()
212 except TypeError:
213 pass
214
215 def test_stdout_void(self):
[email protected]4942e4a2011-11-15 15:50:50216 def fn(c, e, un):
217 (out, err), code = subprocess2.communicate(
218 e + ['--stdout', '--stderr'],
219 stdout=subprocess2.VOID,
220 stderr=subprocess2.PIPE,
221 universal_newlines=un)
222 self.assertEquals(None, out)
223 self.assertEquals(c('a\nbb\nccc\n'), err)
224 self.assertEquals(0, code)
225 self._run_test(fn)
[email protected]87e6d332011-09-09 19:01:28226
227 def test_stderr_void(self):
[email protected]4942e4a2011-11-15 15:50:50228 def fn(c, e, un):
229 (out, err), code = subprocess2.communicate(
230 e + ['--stdout', '--stderr'],
231 stdout=subprocess2.PIPE,
232 stderr=subprocess2.VOID,
233 universal_newlines=un)
234 self.assertEquals(c('A\nBB\nCCC\n'), out)
235 self.assertEquals(None, err)
236 self.assertEquals(0, code)
237 self._run_test(fn)
[email protected]eba40222011-04-05 14:52:48238
[email protected]93e21372011-11-24 15:57:19239 def test_check_output_redirect_stderr_to_stdout_pipe(self):
240 def fn(c, e, un):
241 (out, err), code = subprocess2.communicate(
242 e + ['--stderr'],
243 stdout=subprocess2.PIPE,
244 stderr=subprocess2.STDOUT,
245 universal_newlines=un)
246 # stderr output into stdout.
247 self.assertEquals(c('a\nbb\nccc\n'), out)
248 self.assertEquals(None, err)
249 self.assertEquals(0, code)
250 self._run_test(fn)
251
252 def test_check_output_redirect_stderr_to_stdout(self):
253 def fn(c, e, un):
254 (out, err), code = subprocess2.communicate(
255 e + ['--stderr'],
256 stderr=subprocess2.STDOUT,
257 universal_newlines=un)
258 # stderr output into stdout but stdout is not piped.
259 self.assertEquals(None, out)
260 self.assertEquals(None, err)
261 self.assertEquals(0, code)
262 self._run_test(fn)
263
[email protected]87e6d332011-09-09 19:01:28264 def test_check_output_throw_stdout(self):
[email protected]4942e4a2011-11-15 15:50:50265 def fn(c, e, un):
266 try:
267 subprocess2.check_output(
268 e + ['--fail', '--stdout'], universal_newlines=un)
269 self.fail()
270 except subprocess2.CalledProcessError, e:
271 self.assertEquals(c('A\nBB\nCCC\n'), e.stdout)
272 self.assertEquals(None, e.stderr)
273 self.assertEquals(64, e.returncode)
274 self._run_test(fn)
[email protected]87e6d332011-09-09 19:01:28275
276 def test_check_output_throw_no_stderr(self):
[email protected]4942e4a2011-11-15 15:50:50277 def fn(c, e, un):
278 try:
279 subprocess2.check_output(
280 e + ['--fail', '--stderr'], universal_newlines=un)
281 self.fail()
282 except subprocess2.CalledProcessError, e:
283 self.assertEquals(c(''), e.stdout)
284 self.assertEquals(None, e.stderr)
285 self.assertEquals(64, e.returncode)
286 self._run_test(fn)
[email protected]87e6d332011-09-09 19:01:28287
288 def test_check_output_throw_stderr(self):
[email protected]4942e4a2011-11-15 15:50:50289 def fn(c, e, un):
290 try:
291 subprocess2.check_output(
292 e + ['--fail', '--stderr'], stderr=subprocess2.PIPE,
293 universal_newlines=un)
294 self.fail()
295 except subprocess2.CalledProcessError, e:
296 self.assertEquals('', e.stdout)
297 self.assertEquals(c('a\nbb\nccc\n'), e.stderr)
298 self.assertEquals(64, e.returncode)
299 self._run_test(fn)
[email protected]87e6d332011-09-09 19:01:28300
301 def test_check_output_throw_stderr_stdout(self):
[email protected]4942e4a2011-11-15 15:50:50302 def fn(c, e, un):
303 try:
304 subprocess2.check_output(
305 e + ['--fail', '--stderr'], stderr=subprocess2.STDOUT,
306 universal_newlines=un)
307 self.fail()
308 except subprocess2.CalledProcessError, e:
309 self.assertEquals(c('a\nbb\nccc\n'), e.stdout)
310 self.assertEquals(None, e.stderr)
311 self.assertEquals(64, e.returncode)
312 self._run_test(fn)
[email protected]eba40222011-04-05 14:52:48313
314 def test_check_call_throw(self):
315 try:
316 subprocess2.check_call(self.exe + ['--fail', '--stderr'])
317 self.fail()
318 except subprocess2.CalledProcessError, e:
319 self.assertEquals(None, e.stdout)
320 self.assertEquals(None, e.stderr)
321 self.assertEquals(64, e.returncode)
322
323
324def child_main(args):
[email protected]4942e4a2011-11-15 15:50:50325 if sys.platform == 'win32':
326 # Annoying, make sure the output is not translated on Windows.
327 # pylint: disable=E1101,F0401
328 import msvcrt
329 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
330 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
331
[email protected]eba40222011-04-05 14:52:48332 parser = optparse.OptionParser()
333 parser.add_option(
334 '--fail',
335 dest='return_value',
336 action='store_const',
337 default=0,
338 const=64)
[email protected]4942e4a2011-11-15 15:50:50339 parser.add_option(
340 '--crlf', action='store_const', const='\r\n', dest='eol', default='\n')
341 parser.add_option(
342 '--cr', action='store_const', const='\r', dest='eol')
[email protected]eba40222011-04-05 14:52:48343 parser.add_option('--stdout', action='store_true')
344 parser.add_option('--stderr', action='store_true')
[email protected]4942e4a2011-11-15 15:50:50345 parser.add_option('--sleep_first', action='store_true')
346 parser.add_option('--sleep_last', action='store_true')
347 parser.add_option('--large', action='store_true')
348 parser.add_option('--read', action='store_true')
[email protected]eba40222011-04-05 14:52:48349 options, args = parser.parse_args(args)
350 if args:
351 parser.error('Internal error')
[email protected]4942e4a2011-11-15 15:50:50352 if options.sleep_first:
353 time.sleep(10)
[email protected]eba40222011-04-05 14:52:48354
355 def do(string):
356 if options.stdout:
[email protected]4942e4a2011-11-15 15:50:50357 sys.stdout.write(string.upper())
358 sys.stdout.write(options.eol)
[email protected]eba40222011-04-05 14:52:48359 if options.stderr:
[email protected]4942e4a2011-11-15 15:50:50360 sys.stderr.write(string.lower())
361 sys.stderr.write(options.eol)
[email protected]eba40222011-04-05 14:52:48362
363 do('A')
364 do('BB')
365 do('CCC')
[email protected]4942e4a2011-11-15 15:50:50366 if options.large:
367 # Print 128kb.
368 string = '0123456789abcdef' * (8*1024)
369 sys.stdout.write(string)
370 if options.read:
371 try:
372 while sys.stdin.read():
373 pass
374 except OSError:
375 pass
376 if options.sleep_last:
[email protected]f2dca4e2011-11-09 19:24:48377 time.sleep(10)
[email protected]eba40222011-04-05 14:52:48378 return options.return_value
379
380
381if __name__ == '__main__':
[email protected]4942e4a2011-11-15 15:50:50382 logging.basicConfig(level=
383 [logging.WARNING, logging.INFO, logging.DEBUG][
384 min(2, sys.argv.count('-v'))])
[email protected]eba40222011-04-05 14:52:48385 if len(sys.argv) > 1 and sys.argv[1] == '--child':
386 sys.exit(child_main(sys.argv[2:]))
387 unittest.main()