summaryrefslogtreecommitdiff
path: root/keystoneclient
diff options
context:
space:
mode:
authorDirk Mueller <dirk@dmllr.de>2015-02-13 15:34:47 +0100
committerRoman Bogorodskiy <bogorodskiy@gmail.com>2015-09-09 21:07:02 +0200
commit3e7f80608025166c35bcf97c630c0578e798b796 (patch)
tree947b619873f7a4be92633afaf7e235a2ee455cb6 /keystoneclient
parent28138b588224c6b0503620ac2e24bd37dad25370 (diff)
downloadpython-keystoneclient-3e7f80608025166c35bcf97c630c0578e798b796.tar.gz
Avoid message concatenation in error path
Recently, the error message in _process_communicate_handle_oserror() has been i18n'ed, which caused the regression as another code path appended a string to it, which causes the TypeError to be raised. Fix it by using string formatting instead of '+' to force it to convert to string before concatenating. Closes-Bug: 1421652 Change-Id: I7229b46888f798ac4a69c140ab389afed49b8c3c
Diffstat (limited to 'keystoneclient')
-rw-r--r--keystoneclient/common/cms.py21
-rw-r--r--keystoneclient/tests/unit/test_cms.py54
2 files changed, 64 insertions, 11 deletions
diff --git a/keystoneclient/common/cms.py b/keystoneclient/common/cms.py
index 1bd0f41..21cd394 100644
--- a/keystoneclient/common/cms.py
+++ b/keystoneclient/common/cms.py
@@ -85,9 +85,7 @@ def _check_files_accessible(files):
except IOError as e:
# Catching IOError means there is an issue with
# the given file.
- err = _('Hit OSError in _process_communicate_handle_oserror()\n'
- 'Likely due to %(file)s: %(error)s') % {'file': try_file,
- 'error': e.strerror}
+ err = try_file, e.strerror
# Emulate openssl behavior, which returns with code 2 when
# access to a file failed.
retcode = OpensslCmsExitStatus.INPUT_FILE_READ_ERROR
@@ -111,12 +109,25 @@ def _process_communicate_handle_oserror(process, data, files):
retcode, err = _check_files_accessible(files)
if process.stderr:
msg = process.stderr.read()
- err = err + msg.decode('utf-8')
+ if isinstance(msg, six.binary_type):
+ msg = msg.decode('utf-8')
+ if err:
+ err = (_('Hit OSError in '
+ '_process_communicate_handle_oserror(): '
+ '%(stderr)s\nLikely due to %(file)s: %(error)s') %
+ {'stderr': msg,
+ 'file': err[0],
+ 'error': err[1]})
+ else:
+ err = (_('Hit OSError in '
+ '_process_communicate_handle_oserror(): %s') % msg)
+
output = ''
else:
retcode = process.poll()
if err is not None:
- err = err.decode('utf-8')
+ if isinstance(err, six.binary_type):
+ err = err.decode('utf-8')
return output, err, retcode
diff --git a/keystoneclient/tests/unit/test_cms.py b/keystoneclient/tests/unit/test_cms.py
index 019730d..dc1d0d1 100644
--- a/keystoneclient/tests/unit/test_cms.py
+++ b/keystoneclient/tests/unit/test_cms.py
@@ -42,6 +42,11 @@ class CMSTest(utils.TestCase, testresources.ResourcedTestCase):
raise Exception('Your version of OpenSSL is not supported. '
'You will need to update it to 1.0 or later.')
+ def _raise_OSError(*args):
+ e = OSError()
+ e.errno = errno.EPIPE
+ raise e
+
def test_cms_verify(self):
self.assertRaises(exceptions.CertificateConfigError,
cms.cms_verify,
@@ -90,12 +95,8 @@ class CMSTest(utils.TestCase, testresources.ResourcedTestCase):
'/no/such/file', '/no/such/key')
def test_cms_verify_token_no_oserror(self):
- def raise_OSError(*args):
- e = OSError()
- e.errno = errno.EPIPE
- raise e
-
- with mock.patch('subprocess.Popen.communicate', new=raise_OSError):
+ with mock.patch('subprocess.Popen.communicate',
+ new=self._raise_OSError):
try:
cms.cms_verify("x", '/no/such/file', '/no/such/key')
except exceptions.CertificateConfigError as e:
@@ -155,6 +156,47 @@ class CMSTest(utils.TestCase, testresources.ResourcedTestCase):
# sha256 hash is 64 chars.
self.assertThat(token_id, matchers.HasLength(64))
+ @mock.patch('keystoneclient.common.cms._check_files_accessible')
+ def test_process_communicate_handle_oserror_epipe(self, files_acc_mock):
+ process_mock = mock.Mock()
+ process_mock.communicate = self._raise_OSError
+ process_mock.stderr = mock.Mock()
+ process_mock.stderr.read = mock.Mock(return_value='proc stderr')
+ files_acc_mock.return_value = 1, ('file_path', 'fileerror')
+ output, err, retcode = cms._process_communicate_handle_oserror(
+ process_mock, '', [])
+
+ self.assertEqual((output, retcode), ('', 1))
+ self.assertIn('file_path', err)
+ self.assertIn('fileerror', err)
+ self.assertIn('proc stderr', err)
+
+ @mock.patch('keystoneclient.common.cms._check_files_accessible')
+ def test_process_communicate_handle_oserror_epipe_files_ok(
+ self, files_acc_mock):
+ process_mock = mock.Mock()
+ process_mock.communicate = self._raise_OSError
+ process_mock.stderr = mock.Mock()
+ process_mock.stderr.read = mock.Mock(return_value='proc stderr')
+ files_acc_mock.return_value = -1, None
+ output, err, retcode = cms._process_communicate_handle_oserror(
+ process_mock, '', [])
+
+ self.assertEqual((output, retcode), ('', -1))
+ self.assertIn('proc stderr', err)
+
+ def test_process_communicate_handle_oserror_no_exception(self):
+ process_mock = mock.Mock()
+ process_mock.communicate.return_value = 'out', 'err'
+ process_mock.poll.return_value = 0
+
+ output, err, retcode = cms._process_communicate_handle_oserror(
+ process_mock, '', [])
+
+ self.assertEqual(output, 'out')
+ self.assertEqual(err, 'err')
+ self.assertEqual(retcode, 0)
+
def load_tests(loader, tests, pattern):
return testresources.OptimisingTestSuite(tests)