Merge "Augmenting the hashing strategy"

This commit is contained in:
Jenkins 2016-02-15 12:20:14 +00:00 committed by Gerrit Code Review
commit 6d8768e87c
2 changed files with 91 additions and 8 deletions

View File

@ -390,9 +390,36 @@ def file_open(*args, **kwargs):
return file(*args, **kwargs)
def hash_file(file_like_object):
"""Generate a hash for the contents of a file."""
checksum = hashlib.sha1()
def _get_hash_object(hash_algo_name):
"""Create a hash object based on given algorithm.
:param hash_algo_name: name of the hashing algorithm.
:raises: InvalidParameterValue, on unsupported or invalid input.
:returns: a hash object based on the given named algorithm.
"""
algorithms = (hashlib.algorithms_guaranteed if six.PY3
else hashlib.algorithms)
if hash_algo_name not in algorithms:
msg = (_("Unsupported/Invalid hash name '%s' provided.")
% hash_algo_name)
LOG.error(msg)
raise exception.InvalidParameterValue(msg)
return getattr(hashlib, hash_algo_name)()
def hash_file(file_like_object, hash_algo='md5'):
"""Generate a hash for the contents of a file.
It returns a hash of the file object as a string of double length,
containing only hexadecimal digits. It supports all the algorithms
hashlib does.
:param file_like_object: file like object whose hash to be calculated.
:param hash_algo: name of the hashing strategy, default being 'md5'.
:raises: InvalidParameterValue, on unsupported or invalid input.
:returns: a condensed digest of the bytes of contents.
"""
checksum = _get_hash_object(hash_algo)
for chunk in iter(lambda: file_like_object.read(32768), b''):
checksum.update(chunk)
return checksum.hexdigest()

View File

@ -261,12 +261,68 @@ class GenericUtilsTestCase(base.TestCase):
mock.ANY)
fake_context_manager.__enter__.assert_called_once_with()
def test_hash_file(self):
@mock.patch.object(utils, 'hashlib', autospec=True)
def test__get_hash_object(self, hashlib_mock):
algorithms_available = ('md5', 'sha1', 'sha224',
'sha256', 'sha384', 'sha512')
hashlib_mock.algorithms_guaranteed = algorithms_available
hashlib_mock.algorithms = algorithms_available
# | WHEN |
utils._get_hash_object('md5')
utils._get_hash_object('sha1')
utils._get_hash_object('sha224')
utils._get_hash_object('sha256')
utils._get_hash_object('sha384')
utils._get_hash_object('sha512')
# | THEN |
calls = [mock.call.md5(), mock.call.sha1(), mock.call.sha224(),
mock.call.sha256(), mock.call.sha384(), mock.call.sha512()]
hashlib_mock.assert_has_calls(calls)
def test__get_hash_object_throws_for_invalid_or_unsupported_hash_name(
self):
# | WHEN | & | THEN |
self.assertRaises(exception.InvalidParameterValue,
utils._get_hash_object,
'hickory-dickory-dock')
def test_hash_file_for_md5(self):
# | GIVEN |
data = b'Mary had a little lamb, its fleece as white as snow'
flo = six.BytesIO(data)
h1 = utils.hash_file(flo)
h2 = hashlib.sha1(data).hexdigest()
self.assertEqual(h1, h2)
file_like_object = six.BytesIO(data)
expected = hashlib.md5(data).hexdigest()
# | WHEN |
actual = utils.hash_file(file_like_object) # using default, 'md5'
# | THEN |
self.assertEqual(expected, actual)
def test_hash_file_for_sha1(self):
# | GIVEN |
data = b'Mary had a little lamb, its fleece as white as snow'
file_like_object = six.BytesIO(data)
expected = hashlib.sha1(data).hexdigest()
# | WHEN |
actual = utils.hash_file(file_like_object, 'sha1')
# | THEN |
self.assertEqual(expected, actual)
def test_hash_file_for_sha512(self):
# | GIVEN |
data = b'Mary had a little lamb, its fleece as white as snow'
file_like_object = six.BytesIO(data)
expected = hashlib.sha512(data).hexdigest()
# | WHEN |
actual = utils.hash_file(file_like_object, 'sha512')
# | THEN |
self.assertEqual(expected, actual)
def test_hash_file_throws_for_invalid_or_unsupported_hash(self):
# | GIVEN |
data = b'Mary had a little lamb, its fleece as white as snow'
file_like_object = six.BytesIO(data)
# | WHEN | & | THEN |
self.assertRaises(exception.InvalidParameterValue, utils.hash_file,
file_like_object, 'hickory-dickory-dock')
def test_is_valid_boolstr(self):
self.assertTrue(utils.is_valid_boolstr('true'))