mirror of
https://github.com/certbot/certbot.git
synced 2026-04-11 12:08:15 -04:00
Add check_output function and tests.
This commit is contained in:
parent
dfd1cceb9b
commit
5beaae3b65
2 changed files with 99 additions and 0 deletions
49
certbot-postfix/certbot_postfix/util.py
Normal file
49
certbot-postfix/certbot_postfix/util.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
"""Utility functions for use in the Postfix installer."""
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def check_output(*args, **kwargs):
|
||||
"""Backported version of subprocess.check_output for Python 2.6+.
|
||||
|
||||
This is the same as subprocess.check_output from newer versions of
|
||||
Python, except:
|
||||
|
||||
1. The return value is a string rather than a byte string. To
|
||||
accomplish this, the caller cannot set the parameter
|
||||
universal_newlines.
|
||||
2. If the command exits with a nonzero status, output is not
|
||||
included in the raised subprocess.CalledProcessError because
|
||||
subprocess.CalledProcessError on Python 2.6 does not support this.
|
||||
Instead, the failure including the output is logged.
|
||||
|
||||
:param tuple args: positional arguments for Popen
|
||||
:param dict kwargs: keyword arguments for Popen
|
||||
|
||||
:returns: data printed to stdout
|
||||
:rtype: str
|
||||
|
||||
"""
|
||||
for keyword in ('stdout', 'universal_newlines',):
|
||||
if keyword in kwargs:
|
||||
raise ValueError(
|
||||
keyword + ' argument not allowed, it will be overridden.')
|
||||
|
||||
kwargs['stdout'] = subprocess.PIPE
|
||||
kwargs['universal_newlines'] = True
|
||||
|
||||
process = subprocess.Popen(*args, **kwargs)
|
||||
output, unused_err = process.communicate()
|
||||
retcode = process.poll()
|
||||
if retcode:
|
||||
cmd = kwargs.get('args')
|
||||
if cmd is None:
|
||||
cmd = args[0]
|
||||
logger.debug(
|
||||
"'%s' exited with %d. Output was:\n%s", cmd, retcode, output)
|
||||
raise subprocess.CalledProcessError(retcode, cmd)
|
||||
return output
|
||||
50
certbot-postfix/certbot_postfix/util_test.py
Normal file
50
certbot-postfix/certbot_postfix/util_test.py
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
"""Tests for certbot_postfix.util."""
|
||||
|
||||
import subprocess
|
||||
import unittest
|
||||
|
||||
import mock
|
||||
|
||||
class CheckOutputTest(unittest.TestCase):
|
||||
"""Tests for certbot_postfix.util.check_output."""
|
||||
|
||||
@classmethod
|
||||
def _call(cls, *args, **kwargs):
|
||||
from certbot_postfix.util import check_output
|
||||
return check_output(*args, **kwargs)
|
||||
|
||||
@mock.patch('certbot_postfix.util.logger')
|
||||
@mock.patch('certbot_postfix.util.subprocess.Popen')
|
||||
def test_command_error(self, mock_popen, mock_logger):
|
||||
command = 'foo'
|
||||
retcode = 42
|
||||
output = 'bar'
|
||||
|
||||
mock_popen().communicate.return_value = (output, '')
|
||||
mock_popen().poll.return_value = 42
|
||||
|
||||
self.assertRaises(subprocess.CalledProcessError, self._call, command)
|
||||
|
||||
log_args = mock_logger.debug.call_args[0]
|
||||
self.assertTrue(command in log_args)
|
||||
self.assertTrue(retcode in log_args)
|
||||
self.assertTrue(output in log_args)
|
||||
|
||||
@mock.patch('certbot_postfix.util.subprocess.Popen')
|
||||
def test_success(self, mock_popen):
|
||||
command = 'foo'
|
||||
output = 'bar'
|
||||
mock_popen().communicate.return_value = (output, '')
|
||||
mock_popen().poll.return_value = 0
|
||||
|
||||
self.assertEqual(self._call(command), output)
|
||||
|
||||
def test_stdout_error(self):
|
||||
self.assertRaises(ValueError, self._call, stdout=None)
|
||||
|
||||
def test_universal_newlines_error(self):
|
||||
self.assertRaises(ValueError, self._call, universal_newlines=False)
|
||||
|
||||
|
||||
if __name__ == '__main__': # pragma: no cover
|
||||
unittest.main()
|
||||
Loading…
Reference in a new issue