Merge "Augmenting the hashing strategy"
This commit is contained in:
commit
6d8768e87c
@ -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()
|
||||
|
@ -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'))
|
||||
|
Loading…
x
Reference in New Issue
Block a user