OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Unit tests for subprocess2.py.""" | 6 """Unit tests for subprocess2.py.""" |
7 | 7 |
8 import logging | 8 import logging |
9 import optparse | 9 import optparse |
10 import os | 10 import os |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 def _fake_Popen(self): | 70 def _fake_Popen(self): |
71 """Mocks the whole subprocess2.Popen class.""" | 71 """Mocks the whole subprocess2.Popen class.""" |
72 results = {} | 72 results = {} |
73 class fake_Popen(object): | 73 class fake_Popen(object): |
74 returncode = -8 | 74 returncode = -8 |
75 def __init__(self, args, **kwargs): | 75 def __init__(self, args, **kwargs): |
76 assert not results | 76 assert not results |
77 results.update(kwargs) | 77 results.update(kwargs) |
78 results['args'] = args | 78 results['args'] = args |
79 @staticmethod | 79 @staticmethod |
80 def communicate(): | 80 def communicate(input=None, timeout=None): # pylint: disable=W0622 |
81 return None, None | 81 return None, None |
82 self.mock(subprocess2, 'Popen', fake_Popen) | 82 self.mock(subprocess2, 'Popen', fake_Popen) |
83 return results | 83 return results |
84 | 84 |
85 def _fake_subprocess_Popen(self): | 85 def _fake_subprocess_Popen(self): |
86 """Mocks the base class subprocess.Popen only.""" | 86 """Mocks the base class subprocess.Popen only.""" |
87 results = {} | 87 results = {} |
88 def __init__(self, args, **kwargs): | 88 def __init__(self, args, **kwargs): |
89 assert not results | 89 assert not results |
90 results.update(kwargs) | 90 results.update(kwargs) |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 if fcntl: | 173 if fcntl: |
174 for v in (sys.stdin, sys.stdout, sys.stderr): | 174 for v in (sys.stdin, sys.stdout, sys.stderr): |
175 fileno = v.fileno() | 175 fileno = v.fileno() |
176 self.states[fileno] = fcntl.fcntl(fileno, fcntl.F_GETFL) | 176 self.states[fileno] = fcntl.fcntl(fileno, fcntl.F_GETFL) |
177 | 177 |
178 def tearDown(self): | 178 def tearDown(self): |
179 for fileno, fl in self.states.iteritems(): | 179 for fileno, fl in self.states.iteritems(): |
180 self.assertEquals(fl, fcntl.fcntl(fileno, fcntl.F_GETFL)) | 180 self.assertEquals(fl, fcntl.fcntl(fileno, fcntl.F_GETFL)) |
181 super(BaseTestCase, self).tearDown() | 181 super(BaseTestCase, self).tearDown() |
182 | 182 |
| 183 def _check_res(self, res, stdout, stderr, returncode): |
| 184 (out, err), code = res |
| 185 self.assertEquals(stdout, out) |
| 186 self.assertEquals(stderr, err) |
| 187 self.assertEquals(returncode, code) |
| 188 |
183 | 189 |
184 class RegressionTest(BaseTestCase): | 190 class RegressionTest(BaseTestCase): |
185 # Regression tests to ensure that subprocess and subprocess2 have the same | 191 # Regression tests to ensure that subprocess and subprocess2 have the same |
186 # behavior. | 192 # behavior. |
187 def _run_test(self, function): | 193 def _run_test(self, function): |
188 """Runs tests in 12 combinations: | 194 """Runs tests in 12 combinations: |
189 - LF output with universal_newlines=False | 195 - LF output with universal_newlines=False |
190 - CR output with universal_newlines=False | 196 - CR output with universal_newlines=False |
191 - CRLF output with universal_newlines=False | 197 - CRLF output with universal_newlines=False |
192 - LF output with universal_newlines=True | 198 - LF output with universal_newlines=True |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 self._run_test(fn) | 298 self._run_test(fn) |
293 | 299 |
294 def test_check_call_throw(self): | 300 def test_check_call_throw(self): |
295 for subp in (subprocess, subprocess2): | 301 for subp in (subprocess, subprocess2): |
296 try: | 302 try: |
297 subp.check_call(self.exe + ['--fail', '--stderr']) | 303 subp.check_call(self.exe + ['--fail', '--stderr']) |
298 self.fail() | 304 self.fail() |
299 except subp.CalledProcessError, e: | 305 except subp.CalledProcessError, e: |
300 self._check_exception(subp, e, None, None, 64) | 306 self._check_exception(subp, e, None, None, 64) |
301 | 307 |
| 308 def test_redirect_stderr_to_stdout_pipe(self): |
| 309 def fn(c, e, un, subp): |
| 310 # stderr output into stdout. |
| 311 proc = subp.Popen( |
| 312 e + ['--stderr'], |
| 313 stdout=subp.PIPE, |
| 314 stderr=subp.STDOUT, |
| 315 universal_newlines=un) |
| 316 res = proc.communicate(), proc.returncode |
| 317 self._check_res(res, c('a\nbb\nccc\n'), None, 0) |
| 318 self._run_test(fn) |
| 319 |
| 320 def test_redirect_stderr_to_stdout(self): |
| 321 def fn(c, e, un, subp): |
| 322 # stderr output into stdout but stdout is not piped. |
| 323 proc = subp.Popen( |
| 324 e + ['--stderr'], stderr=STDOUT, universal_newlines=un) |
| 325 res = proc.communicate(), proc.returncode |
| 326 self._check_res(res, None, None, 0) |
| 327 self._run_test(fn) |
| 328 |
302 | 329 |
303 class S2Test(BaseTestCase): | 330 class S2Test(BaseTestCase): |
304 # Tests that can only run in subprocess2, e.g. new functionalities. | 331 # Tests that can only run in subprocess2, e.g. new functionalities. |
305 # In particular, subprocess2.communicate() doesn't exist in subprocess. | 332 # In particular, subprocess2.communicate() doesn't exist in subprocess. |
306 def _run_test(self, function): | 333 def _run_test(self, function): |
307 """Runs tests in 6 combinations: | 334 """Runs tests in 6 combinations: |
308 - LF output with universal_newlines=False | 335 - LF output with universal_newlines=False |
309 - CR output with universal_newlines=False | 336 - CR output with universal_newlines=False |
310 - CRLF output with universal_newlines=False | 337 - CRLF output with universal_newlines=False |
311 - LF output with universal_newlines=True | 338 - LF output with universal_newlines=True |
312 - CR output with universal_newlines=True | 339 - CR output with universal_newlines=True |
313 - CRLF output with universal_newlines=True | 340 - CRLF output with universal_newlines=True |
314 | 341 |
315 First |function| argument is the convertion for the origianl expected LF | 342 First |function| argument is the convertion for the origianl expected LF |
316 string to the right EOL. | 343 string to the right EOL. |
317 Second |function| argument is the executable and initial flag to run, to | 344 Second |function| argument is the executable and initial flag to run, to |
318 control what EOL is used by the child process. | 345 control what EOL is used by the child process. |
319 Third |function| argument is universal_newlines value. | 346 Third |function| argument is universal_newlines value. |
320 """ | 347 """ |
321 noop = lambda x: x | 348 noop = lambda x: x |
322 function(noop, self.exe, False) | 349 function(noop, self.exe, False) |
323 function(convert_to_cr, self.exe + ['--cr'], False) | 350 function(convert_to_cr, self.exe + ['--cr'], False) |
324 function(convert_to_crlf, self.exe + ['--crlf'], False) | 351 function(convert_to_crlf, self.exe + ['--crlf'], False) |
325 function(noop, self.exe, True) | 352 function(noop, self.exe, True) |
326 function(noop, self.exe + ['--cr'], True) | 353 function(noop, self.exe + ['--cr'], True) |
327 function(noop, self.exe + ['--crlf'], True) | 354 function(noop, self.exe + ['--crlf'], True) |
328 | 355 |
329 def _check_res(self, res, stdout, stderr, returncode): | 356 def _check_exception(self, e, stdout, stderr, returncode): |
330 (out, err), code = res | 357 """On exception, look if the exception members are set correctly.""" |
331 self.assertEquals(stdout, out) | 358 self.assertEquals(returncode, e.returncode) |
332 self.assertEquals(stderr, err) | 359 self.assertEquals(stdout, e.stdout) |
333 self.assertEquals(returncode, code) | 360 self.assertEquals(stderr, e.stderr) |
334 | 361 |
335 def test_timeout(self): | 362 def test_timeout(self): |
336 # timeout doesn't exist in subprocess. | 363 # timeout doesn't exist in subprocess. |
337 def fn(c, e, un): | 364 def fn(c, e, un): |
338 res = subprocess2.communicate( | 365 res = subprocess2.communicate( |
339 self.exe + ['--sleep_first', '--stdout'], | 366 self.exe + ['--sleep_first', '--stdout'], |
340 timeout=0.01, | 367 timeout=0.01, |
341 stdout=PIPE, | 368 stdout=PIPE, |
342 shell=False) | 369 shell=False) |
343 self._check_res(res, '', None, TIMED_OUT) | 370 self._check_res(res, '', None, TIMED_OUT) |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 def test_stdout_void_stderr_redirect(self): | 403 def test_stdout_void_stderr_redirect(self): |
377 def fn(c, e, un): | 404 def fn(c, e, un): |
378 res = subprocess2.communicate( | 405 res = subprocess2.communicate( |
379 e + ['--stdout', '--stderr'], | 406 e + ['--stdout', '--stderr'], |
380 stdout=VOID, | 407 stdout=VOID, |
381 stderr=STDOUT, | 408 stderr=STDOUT, |
382 universal_newlines=un) | 409 universal_newlines=un) |
383 self._check_res(res, None, None, 0) | 410 self._check_res(res, None, None, 0) |
384 self._run_test(fn) | 411 self._run_test(fn) |
385 | 412 |
386 def test_check_output_redirect_stderr_to_stdout_pipe(self): | 413 def test_tee_stderr(self): |
387 def fn(c, e, un): | 414 def fn(c, e, un): |
388 # stderr output into stdout. | 415 stderr = [] |
389 res = subprocess2.communicate( | 416 res = subprocess2.communicate( |
390 e + ['--stderr'], | 417 e + ['--stderr'], stderr=stderr.append, universal_newlines=un) |
391 stdout=PIPE, | 418 self.assertEquals(c('a\nbb\nccc\n'), ''.join(stderr)) |
392 stderr=STDOUT, | 419 self._check_res(res, None, None, 0) |
393 universal_newlines=un) | |
394 self._check_res(res, c('a\nbb\nccc\n'), None, 0) | |
395 self._run_test(fn) | 420 self._run_test(fn) |
396 | 421 |
397 def test_check_output_redirect_stderr_to_stdout(self): | 422 def test_tee_stdout_stderr(self): |
398 def fn(c, e, un): | 423 def fn(c, e, un): |
399 # stderr output into stdout but stdout is not piped. | 424 stdout = [] |
| 425 stderr = [] |
400 res = subprocess2.communicate( | 426 res = subprocess2.communicate( |
401 e + ['--stderr'], stderr=STDOUT, universal_newlines=un) | 427 e + ['--stdout', '--stderr'], |
| 428 stdout=stdout.append, |
| 429 stderr=stderr.append, |
| 430 universal_newlines=un) |
| 431 self.assertEquals(c('A\nBB\nCCC\n'), ''.join(stdout)) |
| 432 self.assertEquals(c('a\nbb\nccc\n'), ''.join(stderr)) |
402 self._check_res(res, None, None, 0) | 433 self._check_res(res, None, None, 0) |
403 self._run_test(fn) | 434 self._run_test(fn) |
404 | 435 |
| 436 def test_tee_stdin(self): |
| 437 def fn(c, e, un): |
| 438 stdout = [] |
| 439 stdin = '0123456789' |
| 440 res = subprocess2.communicate( |
| 441 e + ['--stdout', '--read'], stdin=stdin, stdout=stdout.append, |
| 442 universal_newlines=un) |
| 443 self.assertEquals(c('A\nBB\nCCC\n'), ''.join(stdout)) |
| 444 self._check_res(res, None, None, 0) |
| 445 self._run_test(fn) |
| 446 |
| 447 def test_tee_throw(self): |
| 448 def fn(c, e, un): |
| 449 stderr = [] |
| 450 try: |
| 451 subprocess2.check_output( |
| 452 e + ['--stderr', '--fail'], stderr=stderr.append, |
| 453 universal_newlines=un) |
| 454 self.fail() |
| 455 except subprocess2.CalledProcessError, e: |
| 456 self._check_exception(e, '', None, 64) |
| 457 self.assertEquals(c('a\nbb\nccc\n'), ''.join(stderr)) |
| 458 self._run_test(fn) |
| 459 |
| 460 def test_tee_timeout_stdout_void(self): |
| 461 def fn(c, e, un): |
| 462 stderr = [] |
| 463 res = subprocess2.communicate( |
| 464 e + ['--stdout', '--stderr', '--fail'], |
| 465 stdout=VOID, |
| 466 stderr=stderr.append, |
| 467 shell=False, |
| 468 timeout=10, |
| 469 universal_newlines=un) |
| 470 self._check_res(res, None, None, 64) |
| 471 self.assertEquals(c('a\nbb\nccc\n'), ''.join(stderr)) |
| 472 self._run_test(fn) |
| 473 |
| 474 def test_tee_timeout_stderr_void(self): |
| 475 def fn(c, e, un): |
| 476 stdout = [] |
| 477 res = subprocess2.communicate( |
| 478 e + ['--stdout', '--stderr', '--fail'], |
| 479 stdout=stdout.append, |
| 480 stderr=VOID, |
| 481 shell=False, |
| 482 timeout=10, |
| 483 universal_newlines=un) |
| 484 self._check_res(res, None, None, 64) |
| 485 self.assertEquals(c('A\nBB\nCCC\n'), ''.join(stdout)) |
| 486 self._run_test(fn) |
| 487 |
| 488 def test_tee_timeout_stderr_stdout(self): |
| 489 def fn(c, e, un): |
| 490 stdout = [] |
| 491 res = subprocess2.communicate( |
| 492 e + ['--stdout', '--stderr', '--fail'], |
| 493 stdout=stdout.append, |
| 494 stderr=STDOUT, |
| 495 shell=False, |
| 496 timeout=10, |
| 497 universal_newlines=un) |
| 498 self._check_res(res, None, None, 64) |
| 499 # Ordering is random due to buffering. |
| 500 self.assertEquals( |
| 501 set(c('a\nbb\nccc\nA\nBB\nCCC\n').splitlines(True)), |
| 502 set(''.join(stdout).splitlines(True))) |
| 503 self._run_test(fn) |
| 504 |
| 505 def test_tee_large(self): |
| 506 stdout = [] |
| 507 # Read 128kb. On my workstation it takes >2s. Welcome to 2011. |
| 508 res = subprocess2.communicate(self.exe + ['--large'], stdout=stdout.append) |
| 509 self.assertEquals(128*1024, len(''.join(stdout))) |
| 510 self._check_res(res, None, None, 0) |
| 511 |
| 512 def test_tee_large_stdin(self): |
| 513 stdout = [] |
| 514 # Write 128kb. |
| 515 stdin = '0123456789abcdef' * (8*1024) |
| 516 res = subprocess2.communicate( |
| 517 self.exe + ['--large', '--read'], stdin=stdin, stdout=stdout.append) |
| 518 self.assertEquals(128*1024, len(''.join(stdout))) |
| 519 self._check_res(res, None, None, 0) |
| 520 |
| 521 def test_tee_cb_throw(self): |
| 522 # Having a callback throwing up should not cause side-effects. It's a bit |
| 523 # hard to measure. |
| 524 class Blow(Exception): |
| 525 pass |
| 526 def blow(_): |
| 527 raise Blow() |
| 528 proc = subprocess2.Popen(self.exe + ['--stdout'], stdout=blow) |
| 529 try: |
| 530 proc.communicate() |
| 531 self.fail() |
| 532 except Blow: |
| 533 self.assertNotEquals(0, proc.returncode) |
| 534 |
405 | 535 |
406 def child_main(args): | 536 def child_main(args): |
407 if sys.platform == 'win32': | 537 if sys.platform == 'win32': |
408 # Annoying, make sure the output is not translated on Windows. | 538 # Annoying, make sure the output is not translated on Windows. |
409 # pylint: disable=E1101,F0401 | 539 # pylint: disable=E1101,F0401 |
410 import msvcrt | 540 import msvcrt |
411 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) | 541 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) |
412 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY) | 542 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY) |
413 | 543 |
414 parser = optparse.OptionParser() | 544 parser = optparse.OptionParser() |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 return options.return_value | 590 return options.return_value |
461 | 591 |
462 | 592 |
463 if __name__ == '__main__': | 593 if __name__ == '__main__': |
464 logging.basicConfig(level= | 594 logging.basicConfig(level= |
465 [logging.WARNING, logging.INFO, logging.DEBUG][ | 595 [logging.WARNING, logging.INFO, logging.DEBUG][ |
466 min(2, sys.argv.count('-v'))]) | 596 min(2, sys.argv.count('-v'))]) |
467 if len(sys.argv) > 1 and sys.argv[1] == '--child': | 597 if len(sys.argv) > 1 and sys.argv[1] == '--child': |
468 sys.exit(child_main(sys.argv[2:])) | 598 sys.exit(child_main(sys.argv[2:])) |
469 unittest.main() | 599 unittest.main() |
OLD | NEW |