blob: 55936e5582bac65d1583dae2c9ca21777b6dcc91 [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
[email protected]db59bfc2011-11-30 14:03:1422import subprocess
[email protected]eba40222011-04-05 14:52:4823import subprocess2
24
[email protected]7bb06bb2011-11-29 15:22:0625from testing_support import auto_stub
26
[email protected]4942e4a2011-11-15 15:50:5027# Method could be a function
28# pylint: disable=R0201
29
30
[email protected]a8e81632011-12-01 00:35:2431# Create aliases for subprocess2 specific tests. They shouldn't be used for
32# regression tests.
33TIMED_OUT = subprocess2.TIMED_OUT
34VOID = subprocess2.VOID
35PIPE = subprocess2.PIPE
36STDOUT = subprocess2.STDOUT
37
38
[email protected]4942e4a2011-11-15 15:50:5039def convert_to_crlf(string):
40 """Unconditionally convert LF to CRLF."""
41 return string.replace('\n', '\r\n')
42
43
44def convert_to_cr(string):
45 """Unconditionally convert LF to CR."""
46 return string.replace('\n', '\r')
47
48
49def convert_win(string):
50 """Converts string to CRLF on Windows only."""
51 if sys.platform == 'win32':
52 return string.replace('\n', '\r\n')
53 return string
54
55
[email protected]7bb06bb2011-11-29 15:22:0656class DefaultsTest(auto_stub.TestCase):
57 # TODO(maruel): Do a reopen() on sys.__stdout__ and sys.__stderr__ so they
58 # can be trapped in the child process for better coverage.
59 def _fake_communicate(self):
[email protected]ef77f9e2011-11-24 15:24:0260 """Mocks subprocess2.communicate()."""
[email protected]eba40222011-04-05 14:52:4861 results = {}
[email protected]1f063db2011-04-18 19:04:5262 def fake_communicate(args, **kwargs):
[email protected]f08b09c2011-04-06 13:14:2763 assert not results
[email protected]eba40222011-04-05 14:52:4864 results.update(kwargs)
65 results['args'] = args
[email protected]ef77f9e2011-11-24 15:24:0266 return ('stdout', 'stderr'), 0
[email protected]7bb06bb2011-11-29 15:22:0667 self.mock(subprocess2, 'communicate', fake_communicate)
[email protected]eba40222011-04-05 14:52:4868 return results
69
[email protected]7bb06bb2011-11-29 15:22:0670 def _fake_Popen(self):
[email protected]ef77f9e2011-11-24 15:24:0271 """Mocks the whole subprocess2.Popen class."""
[email protected]f08b09c2011-04-06 13:14:2772 results = {}
73 class fake_Popen(object):
74 returncode = -8
75 def __init__(self, args, **kwargs):
76 assert not results
77 results.update(kwargs)
78 results['args'] = args
[email protected]428342a2011-11-10 15:46:3379 @staticmethod
80 def communicate():
[email protected]f08b09c2011-04-06 13:14:2781 return None, None
[email protected]7bb06bb2011-11-29 15:22:0682 self.mock(subprocess2, 'Popen', fake_Popen)
[email protected]f08b09c2011-04-06 13:14:2783 return results
84
[email protected]7bb06bb2011-11-29 15:22:0685 def _fake_subprocess_Popen(self):
[email protected]ef77f9e2011-11-24 15:24:0286 """Mocks the base class subprocess.Popen only."""
[email protected]f08b09c2011-04-06 13:14:2787 results = {}
[email protected]ef77f9e2011-11-24 15:24:0288 def __init__(self, args, **kwargs):
89 assert not results
90 results.update(kwargs)
91 results['args'] = args
92 def communicate():
93 return None, None
[email protected]db59bfc2011-11-30 14:03:1494 self.mock(subprocess.Popen, '__init__', __init__)
95 self.mock(subprocess.Popen, 'communicate', communicate)
[email protected]f08b09c2011-04-06 13:14:2796 return results
97
[email protected]eba40222011-04-05 14:52:4898 def test_check_call_defaults(self):
[email protected]1f063db2011-04-18 19:04:5299 results = self._fake_communicate()
[email protected]eba40222011-04-05 14:52:48100 self.assertEquals(
[email protected]ef77f9e2011-11-24 15:24:02101 ('stdout', 'stderr'), subprocess2.check_call_out(['foo'], a=True))
[email protected]eba40222011-04-05 14:52:48102 expected = {
103 'args': ['foo'],
104 'a':True,
105 }
106 self.assertEquals(expected, results)
107
[email protected]87e6d332011-09-09 19:01:28108 def test_capture_defaults(self):
109 results = self._fake_communicate()
110 self.assertEquals(
111 'stdout', subprocess2.capture(['foo'], a=True))
112 expected = {
113 'args': ['foo'],
114 'a':True,
115 'stdin': subprocess2.VOID,
116 'stdout': subprocess2.PIPE,
117 }
118 self.assertEquals(expected, results)
119
[email protected]1f063db2011-04-18 19:04:52120 def test_communicate_defaults(self):
[email protected]f08b09c2011-04-06 13:14:27121 results = self._fake_Popen()
[email protected]1f063db2011-04-18 19:04:52122 self.assertEquals(
123 ((None, None), -8), subprocess2.communicate(['foo'], a=True))
[email protected]f08b09c2011-04-06 13:14:27124 expected = {
125 'args': ['foo'],
126 'a': True,
127 }
128 self.assertEquals(expected, results)
129
130 def test_Popen_defaults(self):
131 results = self._fake_subprocess_Popen()
132 proc = subprocess2.Popen(['foo'], a=True)
[email protected]ef77f9e2011-11-24 15:24:02133 # Cleanup code in subprocess.py needs this member to be set.
134 # pylint: disable=W0201
135 proc._child_created = None
[email protected]f08b09c2011-04-06 13:14:27136 expected = {
137 'args': ['foo'],
138 'a': True,
139 'shell': bool(sys.platform=='win32'),
[email protected]f08b09c2011-04-06 13:14:27140 }
[email protected]c98c0c52011-04-06 13:39:43141 if sys.platform != 'win32':
142 env = os.environ.copy()
143 is_english = lambda name: env.get(name, 'en').startswith('en')
144 if not is_english('LANG'):
145 env['LANG'] = 'en_US.UTF-8'
146 expected['env'] = env
147 if not is_english('LANGUAGE'):
148 env['LANGUAGE'] = 'en_US.UTF-8'
149 expected['env'] = env
[email protected]f08b09c2011-04-06 13:14:27150 self.assertEquals(expected, results)
[email protected]dd9837f2011-11-30 01:55:22151 self.assertTrue(time.time() >= proc.start)
[email protected]f08b09c2011-04-06 13:14:27152
[email protected]eba40222011-04-05 14:52:48153 def test_check_output_defaults(self):
[email protected]1f063db2011-04-18 19:04:52154 results = self._fake_communicate()
[email protected]eba40222011-04-05 14:52:48155 # It's discarding 'stderr' because it assumes stderr=subprocess2.STDOUT but
[email protected]1f063db2011-04-18 19:04:52156 # fake_communicate() doesn't 'implement' that.
[email protected]eba40222011-04-05 14:52:48157 self.assertEquals('stdout', subprocess2.check_output(['foo'], a=True))
158 expected = {
159 'args': ['foo'],
160 'a':True,
[email protected]4a982272011-04-12 20:49:37161 'stdin': subprocess2.VOID,
[email protected]eba40222011-04-05 14:52:48162 'stdout': subprocess2.PIPE,
[email protected]eba40222011-04-05 14:52:48163 }
164 self.assertEquals(expected, results)
165
[email protected]4942e4a2011-11-15 15:50:50166
[email protected]db59bfc2011-11-30 14:03:14167class BaseTestCase(unittest.TestCase):
[email protected]4942e4a2011-11-15 15:50:50168 def setUp(self):
[email protected]db59bfc2011-11-30 14:03:14169 super(BaseTestCase, self).setUp()
[email protected]4942e4a2011-11-15 15:50:50170 self.exe_path = __file__
171 self.exe = [sys.executable, self.exe_path, '--child']
172 self.states = {}
173 if fcntl:
174 for v in (sys.stdin, sys.stdout, sys.stderr):
175 fileno = v.fileno()
176 self.states[fileno] = fcntl.fcntl(fileno, fcntl.F_GETFL)
177
178 def tearDown(self):
179 for fileno, fl in self.states.iteritems():
180 self.assertEquals(fl, fcntl.fcntl(fileno, fcntl.F_GETFL))
[email protected]db59bfc2011-11-30 14:03:14181 super(BaseTestCase, self).tearDown()
[email protected]4942e4a2011-11-15 15:50:50182
[email protected]db59bfc2011-11-30 14:03:14183
184class RegressionTest(BaseTestCase):
185 # Regression tests to ensure that subprocess and subprocess2 have the same
186 # behavior.
187 def _run_test(self, function):
188 """Runs tests in 12 combinations:
189 - LF output with universal_newlines=False
190 - CR output with universal_newlines=False
191 - CRLF output with universal_newlines=False
192 - LF output with universal_newlines=True
193 - CR output with universal_newlines=True
194 - CRLF output with universal_newlines=True
195
196 Once with subprocess, once with subprocess2.
197
198 First |function| argument is the conversion for the original expected LF
199 string to the right EOL.
200 Second |function| argument is the executable and initial flag to run, to
201 control what EOL is used by the child process.
202 Third |function| argument is universal_newlines value.
203 """
204 noop = lambda x: x
205 for subp in (subprocess, subprocess2):
206 function(noop, self.exe, False, subp)
207 function(convert_to_cr, self.exe + ['--cr'], False, subp)
208 function(convert_to_crlf, self.exe + ['--crlf'], False, subp)
209 function(noop, self.exe, True, subp)
210 function(noop, self.exe + ['--cr'], True, subp)
211 function(noop, self.exe + ['--crlf'], True, subp)
212
[email protected]a8e81632011-12-01 00:35:24213 def _check_exception(self, subp, e, stdout, stderr, returncode):
[email protected]db59bfc2011-11-30 14:03:14214 """On exception, look if the exception members are set correctly."""
[email protected]a8e81632011-12-01 00:35:24215 self.assertEquals(returncode, e.returncode)
[email protected]db59bfc2011-11-30 14:03:14216 if subp is subprocess:
217 # subprocess never save the output.
218 self.assertFalse(hasattr(e, 'stdout'))
219 self.assertFalse(hasattr(e, 'stderr'))
220 elif subp is subprocess2:
221 self.assertEquals(stdout, e.stdout)
222 self.assertEquals(stderr, e.stderr)
223 else:
224 self.fail()
225
226 def test_check_output_no_stdout(self):
227 try:
228 subprocess2.check_output(self.exe, stdout=subprocess2.PIPE)
229 self.fail()
230 except ValueError:
231 pass
232
233 if (sys.version_info[0] * 10 + sys.version_info[1]) >= 27:
234 # python 2.7+
235 try:
236 # pylint: disable=E1101
237 subprocess.check_output(self.exe, stdout=subprocess.PIPE)
238 self.fail()
239 except ValueError:
240 pass
241
242 def test_check_output_throw_stdout(self):
243 def fn(c, e, un, subp):
244 if not hasattr(subp, 'check_output'):
245 return
246 try:
247 subp.check_output(
248 e + ['--fail', '--stdout'], universal_newlines=un)
249 self.fail()
250 except subp.CalledProcessError, e:
[email protected]a8e81632011-12-01 00:35:24251 self._check_exception(subp, e, c('A\nBB\nCCC\n'), None, 64)
[email protected]db59bfc2011-11-30 14:03:14252 self._run_test(fn)
253
254 def test_check_output_throw_no_stderr(self):
255 def fn(c, e, un, subp):
256 if not hasattr(subp, 'check_output'):
257 return
258 try:
259 subp.check_output(
260 e + ['--fail', '--stderr'], universal_newlines=un)
261 self.fail()
262 except subp.CalledProcessError, e:
[email protected]a8e81632011-12-01 00:35:24263 self._check_exception(subp, e, c(''), None, 64)
[email protected]db59bfc2011-11-30 14:03:14264 self._run_test(fn)
265
266 def test_check_output_throw_stderr(self):
267 def fn(c, e, un, subp):
268 if not hasattr(subp, 'check_output'):
269 return
270 try:
271 subp.check_output(
272 e + ['--fail', '--stderr'],
273 stderr=subp.PIPE,
274 universal_newlines=un)
275 self.fail()
276 except subp.CalledProcessError, e:
[email protected]a8e81632011-12-01 00:35:24277 self._check_exception(subp, e, '', c('a\nbb\nccc\n'), 64)
[email protected]db59bfc2011-11-30 14:03:14278 self._run_test(fn)
279
280 def test_check_output_throw_stderr_stdout(self):
281 def fn(c, e, un, subp):
282 if not hasattr(subp, 'check_output'):
283 return
284 try:
285 subp.check_output(
286 e + ['--fail', '--stderr'],
287 stderr=subp.STDOUT,
288 universal_newlines=un)
289 self.fail()
290 except subp.CalledProcessError, e:
[email protected]a8e81632011-12-01 00:35:24291 self._check_exception(subp, e, c('a\nbb\nccc\n'), None, 64)
[email protected]db59bfc2011-11-30 14:03:14292 self._run_test(fn)
293
294 def test_check_call_throw(self):
295 for subp in (subprocess, subprocess2):
296 try:
297 subp.check_call(self.exe + ['--fail', '--stderr'])
298 self.fail()
299 except subp.CalledProcessError, e:
[email protected]a8e81632011-12-01 00:35:24300 self._check_exception(subp, e, None, None, 64)
[email protected]db59bfc2011-11-30 14:03:14301
302
303class S2Test(BaseTestCase):
304 # Tests that can only run in subprocess2, e.g. new functionalities.
305 # In particular, subprocess2.communicate() doesn't exist in subprocess.
[email protected]4942e4a2011-11-15 15:50:50306 def _run_test(self, function):
307 """Runs tests in 6 combinations:
308 - LF output with universal_newlines=False
309 - CR output with universal_newlines=False
310 - CRLF output with universal_newlines=False
311 - LF output with universal_newlines=True
312 - CR output with universal_newlines=True
313 - CRLF output with universal_newlines=True
314
315 First |function| argument is the convertion for the origianl expected LF
316 string to the right EOL.
317 Second |function| argument is the executable and initial flag to run, to
318 control what EOL is used by the child process.
319 Third |function| argument is universal_newlines value.
320 """
321 noop = lambda x: x
322 function(noop, self.exe, False)
323 function(convert_to_cr, self.exe + ['--cr'], False)
324 function(convert_to_crlf, self.exe + ['--crlf'], False)
325 function(noop, self.exe, True)
326 function(noop, self.exe + ['--cr'], True)
327 function(noop, self.exe + ['--crlf'], True)
328
[email protected]a8e81632011-12-01 00:35:24329 def _check_res(self, res, stdout, stderr, returncode):
330 (out, err), code = res
331 self.assertEquals(stdout, out)
332 self.assertEquals(stderr, err)
333 self.assertEquals(returncode, code)
334
[email protected]f2dca4e2011-11-09 19:24:48335 def test_timeout(self):
[email protected]db59bfc2011-11-30 14:03:14336 # timeout doesn't exist in subprocess.
337 def fn(c, e, un):
[email protected]a8e81632011-12-01 00:35:24338 res = subprocess2.communicate(
[email protected]db59bfc2011-11-30 14:03:14339 self.exe + ['--sleep_first', '--stdout'],
340 timeout=0.01,
[email protected]a8e81632011-12-01 00:35:24341 stdout=PIPE,
[email protected]db59bfc2011-11-30 14:03:14342 shell=False)
[email protected]a8e81632011-12-01 00:35:24343 self._check_res(res, '', None, TIMED_OUT)
344 self._run_test(fn)
345
346 def test_timeout_shell_throws(self):
347 def fn(c, e, un):
348 try:
349 # With shell=True, it needs a string.
350 subprocess2.communicate(' '.join(self.exe), timeout=0.01, shell=True)
351 self.fail()
352 except TypeError:
353 pass
[email protected]db59bfc2011-11-30 14:03:14354 self._run_test(fn)
[email protected]87e6d332011-09-09 19:01:28355
356 def test_stdout_void(self):
[email protected]4942e4a2011-11-15 15:50:50357 def fn(c, e, un):
[email protected]a8e81632011-12-01 00:35:24358 res = subprocess2.communicate(
[email protected]4942e4a2011-11-15 15:50:50359 e + ['--stdout', '--stderr'],
[email protected]a8e81632011-12-01 00:35:24360 stdout=VOID,
361 stderr=PIPE,
[email protected]4942e4a2011-11-15 15:50:50362 universal_newlines=un)
[email protected]a8e81632011-12-01 00:35:24363 self._check_res(res, None, c('a\nbb\nccc\n'), 0)
[email protected]4942e4a2011-11-15 15:50:50364 self._run_test(fn)
[email protected]87e6d332011-09-09 19:01:28365
366 def test_stderr_void(self):
[email protected]4942e4a2011-11-15 15:50:50367 def fn(c, e, un):
[email protected]a8e81632011-12-01 00:35:24368 res = subprocess2.communicate(
[email protected]4942e4a2011-11-15 15:50:50369 e + ['--stdout', '--stderr'],
[email protected]a8e81632011-12-01 00:35:24370 stdout=PIPE,
371 stderr=VOID,
[email protected]4942e4a2011-11-15 15:50:50372 universal_newlines=un)
[email protected]a8e81632011-12-01 00:35:24373 self._check_res(res, c('A\nBB\nCCC\n'), None, 0)
374 self._run_test(fn)
375
376 def test_stdout_void_stderr_redirect(self):
377 def fn(c, e, un):
378 res = subprocess2.communicate(
379 e + ['--stdout', '--stderr'],
380 stdout=VOID,
381 stderr=STDOUT,
382 universal_newlines=un)
383 self._check_res(res, None, None, 0)
[email protected]4942e4a2011-11-15 15:50:50384 self._run_test(fn)
[email protected]eba40222011-04-05 14:52:48385
[email protected]93e21372011-11-24 15:57:19386 def test_check_output_redirect_stderr_to_stdout_pipe(self):
387 def fn(c, e, un):
[email protected]93e21372011-11-24 15:57:19388 # stderr output into stdout.
[email protected]a8e81632011-12-01 00:35:24389 res = subprocess2.communicate(
390 e + ['--stderr'],
391 stdout=PIPE,
392 stderr=STDOUT,
393 universal_newlines=un)
394 self._check_res(res, c('a\nbb\nccc\n'), None, 0)
[email protected]93e21372011-11-24 15:57:19395 self._run_test(fn)
396
397 def test_check_output_redirect_stderr_to_stdout(self):
398 def fn(c, e, un):
[email protected]93e21372011-11-24 15:57:19399 # stderr output into stdout but stdout is not piped.
[email protected]a8e81632011-12-01 00:35:24400 res = subprocess2.communicate(
401 e + ['--stderr'], stderr=STDOUT, universal_newlines=un)
402 self._check_res(res, None, None, 0)
[email protected]93e21372011-11-24 15:57:19403 self._run_test(fn)
404
[email protected]eba40222011-04-05 14:52:48405
406def child_main(args):
[email protected]4942e4a2011-11-15 15:50:50407 if sys.platform == 'win32':
408 # Annoying, make sure the output is not translated on Windows.
409 # pylint: disable=E1101,F0401
410 import msvcrt
411 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
412 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
413
[email protected]eba40222011-04-05 14:52:48414 parser = optparse.OptionParser()
415 parser.add_option(
416 '--fail',
417 dest='return_value',
418 action='store_const',
419 default=0,
420 const=64)
[email protected]4942e4a2011-11-15 15:50:50421 parser.add_option(
422 '--crlf', action='store_const', const='\r\n', dest='eol', default='\n')
423 parser.add_option(
424 '--cr', action='store_const', const='\r', dest='eol')
[email protected]eba40222011-04-05 14:52:48425 parser.add_option('--stdout', action='store_true')
426 parser.add_option('--stderr', action='store_true')
[email protected]4942e4a2011-11-15 15:50:50427 parser.add_option('--sleep_first', action='store_true')
428 parser.add_option('--sleep_last', action='store_true')
429 parser.add_option('--large', action='store_true')
430 parser.add_option('--read', action='store_true')
[email protected]eba40222011-04-05 14:52:48431 options, args = parser.parse_args(args)
432 if args:
433 parser.error('Internal error')
[email protected]4942e4a2011-11-15 15:50:50434 if options.sleep_first:
435 time.sleep(10)
[email protected]eba40222011-04-05 14:52:48436
437 def do(string):
438 if options.stdout:
[email protected]4942e4a2011-11-15 15:50:50439 sys.stdout.write(string.upper())
440 sys.stdout.write(options.eol)
[email protected]eba40222011-04-05 14:52:48441 if options.stderr:
[email protected]4942e4a2011-11-15 15:50:50442 sys.stderr.write(string.lower())
443 sys.stderr.write(options.eol)
[email protected]eba40222011-04-05 14:52:48444
445 do('A')
446 do('BB')
447 do('CCC')
[email protected]4942e4a2011-11-15 15:50:50448 if options.large:
449 # Print 128kb.
450 string = '0123456789abcdef' * (8*1024)
451 sys.stdout.write(string)
452 if options.read:
453 try:
454 while sys.stdin.read():
455 pass
456 except OSError:
457 pass
458 if options.sleep_last:
[email protected]f2dca4e2011-11-09 19:24:48459 time.sleep(10)
[email protected]eba40222011-04-05 14:52:48460 return options.return_value
461
462
463if __name__ == '__main__':
[email protected]4942e4a2011-11-15 15:50:50464 logging.basicConfig(level=
465 [logging.WARNING, logging.INFO, logging.DEBUG][
466 min(2, sys.argv.count('-v'))])
[email protected]eba40222011-04-05 14:52:48467 if len(sys.argv) > 1 and sys.argv[1] == '--child':
468 sys.exit(child_main(sys.argv[2:]))
469 unittest.main()