diff --git a/awscli/customizations/s3/utils.py b/awscli/customizations/s3/utils.py index 7e06168e4ebd..2ffe9ac376fa 100644 --- a/awscli/customizations/s3/utils.py +++ b/awscli/customizations/s3/utils.py @@ -112,8 +112,12 @@ def get_file_stat(path): This is a helper function that given a local path return the size of the file in bytes and time of last modification. """ - stats = os.stat(path) - update_time = datetime.fromtimestamp(stats.st_mtime, tzlocal()) + try: + stats = os.stat(path) + update_time = datetime.fromtimestamp(stats.st_mtime, tzlocal()) + except (ValueError, IOError) as e: + raise ValueError('Could not retrieve file stat of "%s": %s' % ( + path, e)) return stats.st_size, update_time diff --git a/tests/unit/customizations/s3/test_utils.py b/tests/unit/customizations/s3/test_utils.py index 055af863fa11..0807c8653b23 100644 --- a/tests/unit/customizations/s3/test_utils.py +++ b/tests/unit/customizations/s3/test_utils.py @@ -1,10 +1,13 @@ -from awscli.testutils import unittest +from awscli.testutils import unittest, temporary_file import os import tempfile import shutil import ntpath +import time +import datetime import mock +from dateutil.tz import tzlocal from botocore.hooks import HierarchicalEmitter from awscli.customizations.s3.utils import find_bucket_key, find_chunksize @@ -13,6 +16,7 @@ from awscli.customizations.s3.utils import StablePriorityQueue from awscli.customizations.s3.utils import BucketLister from awscli.customizations.s3.utils import ScopedEventHandler +from awscli.customizations.s3.utils import get_file_stat from awscli.customizations.s3.constants import MAX_SINGLE_UPLOAD_SIZE @@ -270,5 +274,30 @@ def test_scoped_session_handler(self): session.unregister.assert_called_with('eventname', 'handler') +class TestGetFileStat(unittest.TestCase): + + def test_get_file_stat(self): + now = datetime.datetime.now(tzlocal()) + epoch_now = time.mktime(now.timetuple()) + with temporary_file('w') as f: + f.write('foo') + f.flush() + os.utime(f.name, (epoch_now, epoch_now)) + size, update_time = get_file_stat(f.name) + self.assertEqual(size, 3) + self.assertEqual(time.mktime(update_time.timetuple()), epoch_now) + + def test_get_file_stat_error_message(self): + patch_attribute = 'awscli.customizations.s3.utils.datetime' + with mock.patch(patch_attribute) as f: + with mock.patch('os.stat'): + f.fromtimestamp.side_effect = ValueError( + "timestamp out of range for platform " + "localtime()/gmtime() function") + with self.assertRaisesRegexp( + ValueError, 'myfilename\.txt'): + get_file_stat('myfilename.txt') + + if __name__ == "__main__": unittest.main()