You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Tools/LyTestTools/tests/unit/test_file_system.py

903 lines
35 KiB
Python

"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import errno
import logging
import os
import stat
import psutil
import subprocess
import sys
import tarfile
import unittest.mock as mock
import unittest
import zipfile
import pytest
from ly_test_tools.environment import file_system
logger = logging.getLogger(__name__)
pytestmark = pytest.mark.SUITE_smoke
class TestCheckFreeSpace(unittest.TestCase):
def setUp(self):
# sdiskusage is: (total, used, free, percent)
self.disk_usage = psutil._common.sdiskusage(100 * file_system.ONE_GIB, 0, 100 * file_system.ONE_GIB, 100)
def tearDown(self):
self.disk_usage = None
@mock.patch('psutil.disk_usage')
def test_CheckFreeSpace_NoSpace_RaisesIOError(self, mock_disk_usage):
total = 100 * file_system.ONE_GIB
used = total
mock_disk_usage.return_value = psutil._common.sdiskusage(total, used, total - used, used / total)
with self.assertRaises(IOError):
file_system.check_free_space('', 1, 'Raise')
@mock.patch('psutil.disk_usage')
def test_CheckFreeSpace_EnoughSpace_NoRaise(self, mock_disk_usage):
total = 100 * file_system.ONE_GIB
needed = 1
used = total - needed
mock_disk_usage.return_value = psutil._common.sdiskusage(total, used, total - used, used / total)
dest_path = 'dest'
file_system.check_free_space(dest_path, needed, 'No Raise')
mock_disk_usage.assert_called_once_with(dest_path)
class TestSafeMakedirs(unittest.TestCase):
@mock.patch('os.makedirs')
def test_SafeMakedirs_RaisedOSErrorErrnoEEXIST_DoesNotPropagate(self, mock_makedirs):
error = OSError()
error.errno = errno.EEXIST
mock_makedirs.side_effect = error
file_system.safe_makedirs('')
@mock.patch('os.makedirs')
def test_SafeMakedirs_RaisedOSErrorNotErrnoEEXIST_Propagates(self, mock_makedirs):
error = OSError()
error.errno = errno.EINTR
mock_makedirs.side_effect = error
with self.assertRaises(OSError):
file_system.safe_makedirs('')
@mock.patch('os.makedirs')
def test_SafeMakedirs_RootDir_DoesNotPropagate(self, mock_makedirs):
error = OSError()
error.errno = errno.EACCES
if sys.platform == 'win32':
mock_makedirs.side_effect = error
file_system.safe_makedirs('C:\\')
class TestGetNewestFileInDir(unittest.TestCase):
@mock.patch('glob.iglob')
def test_GetNewestFileInDir_NoResultsFound_ReturnsNone(self, mock_glob):
mock_glob.return_value.iglob = None
result = file_system.get_newest_file_in_dir('', '')
self.assertEqual(result, None)
@mock.patch('os.path.getctime')
@mock.patch('glob.iglob')
def test_GetNewestFileInDir_TwoResultsFound_ReturnsNewer(self, mock_glob, mock_ctime):
mock_glob.return_value = ['fileA.zip', 'fileB.zip']
mock_ctime.side_effect = [1, 2]
result = file_system.get_newest_file_in_dir('', [''])
self.assertEqual(result, 'fileB.zip')
@mock.patch('os.path.getctime')
@mock.patch('glob.iglob')
def test_GetNewestFileInDir_ThreeResultsTwoExts_CtimeCalledSixTimes(self, mock_glob, mock_ctime):
mock_glob.return_value = ['fileA.zip', 'fileB.zip', 'fileC.zip']
mock_ctime.side_effect = range(6)
file_system.get_newest_file_in_dir('', ['.zip', '.tgz'])
self.assertEqual(len(mock_ctime.mock_calls), 6)
class TestUnZip(unittest.TestCase):
decomp_obj_name = 'zipfile.ZipFile'
def setUp(self):
self.file_list = []
for i in range(25):
new_src_info = zipfile.ZipInfo('{}.txt'.format(i))
new_src_info.file_size = i
self.file_list.append(new_src_info)
self.mock_handle = mock.MagicMock()
self.mock_handle.infolist.return_value = self.file_list
self.mock_handle.__enter__.return_value = self.mock_handle
self.mock_decomp = mock.MagicMock()
self.mock_decomp.return_value = self.mock_handle
self.src_path = 'src.zip'
self.dest_path = 'dest'
self.exists = False
def tearDown(self):
self.mock_handle = None
self.mock_decomp = None
def call_decomp(self, dest, src, force=True, allow_exists=False):
return file_system.unzip(dest, src, force, allow_exists)
@mock.patch('os.path.exists')
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
@mock.patch(decomp_obj_name)
def test_Unzip_DefaultArgs_CallsDecompressorWithSrc(self, mock_decomp, mock_join, mock_check_free, mock_exists):
mock_exists.return_value = self.exists
self.call_decomp(self.dest_path, self.src_path)
mock_decomp.assert_called_once_with(self.src_path, 'r')
@mock.patch('os.path.exists')
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
def test_Unzip_DefaultArgs_CheckFreeSpaceCalledOnceWithOneGiBAdded(self, mock_join,
mock_check_free, mock_exists):
mock_exists.return_value = self.exists
total_size = sum(info.file_size for info in self.file_list)
with mock.patch(self.decomp_obj_name, self.mock_decomp):
self.call_decomp(self.dest_path, self.src_path)
mock_check_free.assert_called_once_with(self.dest_path,
total_size + file_system.ONE_GIB,
'Not enough space to safely extract: ')
@mock.patch('os.path.exists')
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
def test_Unzip_DefaultArgs_JoinCalledWithNoPathNoExtension(self, mock_join, mock_check_free, mock_exists):
expected_name, _ = os.path.splitext(self.src_path)
mock_exists.return_value = self.exists
with mock.patch(self.decomp_obj_name, self.mock_decomp):
self.call_decomp(self.dest_path, self.src_path)
mock_join.assert_called_once_with(self.dest_path, expected_name)
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
def test_Unzip_DefaultArgs_ReturnsCorrectPath(self, mock_join, mock_check_free):
build_name = 'build_name'
expected_path = self.dest_path+'\\'+build_name
mock_join.return_value = expected_path
path = ''
with mock.patch(self.decomp_obj_name, self.mock_decomp):
path = self.call_decomp(self.dest_path, self.src_path)
self.assertEqual(path, expected_path)
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
def test_Unzip_ReleaseBuild_ReturnsCorrectPath(self, mock_join, mock_check_free):
build_name = 'lumberyard-1.2.0.3-54321-pc-1234'
expected_path = self.dest_path + '\\' + build_name
mock_join.return_value = expected_path
path = ''
self.src_path = r'C:\packages\lumberyard-1.2.0.3-54321-pc-1234.zip'
with mock.patch(self.decomp_obj_name, self.mock_decomp):
path = self.call_decomp(self.dest_path, self.src_path)
self.assertEqual(path, expected_path)
@mock.patch('ly_test_tools.environment.file_system.logger')
@mock.patch('os.path.exists')
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
def test_Unzip_BuildDirExistsForceAndAllowExistsNotSet_CRITICALLogged(self, mock_join, mock_check_free,
mock_exists, mock_log):
force = False
allow_exists = False
self.exists = True
mock_exists.return_value = self.exists
level = logging.getLevelName("CRITICAL")
with mock.patch(self.decomp_obj_name, self.mock_decomp):
path = self.call_decomp(self.dest_path, self.src_path, force)
mock_log.log.assert_called_with(level, 'Found existing {}. Will not overwrite.'.format(path))
@mock.patch('ly_test_tools.environment.file_system.logger')
@mock.patch('os.path.exists')
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
def test_Unzip_AllowExistsSet_INFOLogged(self, mock_join, mock_check_free, mock_exists, mock_log):
force = False
allow_exists = True
self.exists = True
mock_exists.return_value = self.exists
level = logging.getLevelName("INFO")
with mock.patch(self.decomp_obj_name, self.mock_decomp):
path = self.call_decomp(self.dest_path, self.src_path, force, allow_exists)
mock_log.log.assert_called_with(level, 'Found existing {}. Will not overwrite.'.format(path))
@mock.patch('ly_test_tools.environment.file_system.logger')
@mock.patch('os.path.exists')
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
def test_Unzip_BuildDirExistsForceSetTrue_INFOLogged(self, mock_join, mock_check_free, mock_exists, mock_log):
path = ''
self.exists = True
mock_exists.return_value = self.exists
with mock.patch(self.decomp_obj_name, self.mock_decomp):
path = self.call_decomp(self.dest_path, self.src_path)
mock_log.info.assert_called_once()
class TestUnTgz(unittest.TestCase):
decomp_obj_name = 'tarfile.open'
def setUp(self):
self.file_list = []
for i in range(25):
new_src_info = tarfile.TarInfo('{}.txt'.format(i))
new_src_info.size = i
self.file_list.append(new_src_info)
self.mock_handle = mock.MagicMock()
self.mock_handle.__iter__.return_value = self.file_list
self.mock_handle.__enter__.return_value = self.mock_handle
self.mock_decomp = mock.MagicMock()
self.mock_decomp.return_value = self.mock_handle
self.src_path = 'src.tgz'
self.dest_path = 'dest'
# os.stat_result is (mode, inode, device, hard links, owner uid, size, atime, mtime, ctime)
self.src_stat = os.stat_result((0, 0, 0, 0, 0, 0, file_system.ONE_GIB, 0, 0, 0))
def tearDown(self):
self.mock_decomp = None
self.mock_handle = None
def call_decomp(self, dest, src, exact=False, force=True, allow_exists=False):
return file_system.untgz(dest, src, exact, force, allow_exists)
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
@mock.patch(decomp_obj_name)
@mock.patch('os.stat')
def test_UnTgz_DefaultArgs_CallsDecompressorWithSrc(self, mock_stat, mock_decomp, mock_join, mock_check_free):
mock_stat.return_value = self.src_stat
self.call_decomp(self.dest_path, self.src_path)
mock_decomp.assert_called_once_with(self.src_path)
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
@mock.patch('os.stat')
def test_UnTgz_DefaultArgs_CheckFreeSpaceCalledOnceWithOneGiBAdded(self, mock_stat, mock_join, mock_check_free):
mock_stat.return_value = self.src_stat
total_size = sum(info.size for info in self.file_list)
with mock.patch(self.decomp_obj_name, self.mock_decomp):
self.call_decomp(self.dest_path, self.src_path, True)
mock_check_free.assert_called_once_with(self.dest_path,
total_size + file_system.ONE_GIB,
'Not enough space to safely extract: ')
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
@mock.patch('os.stat')
def test_UnTgz_DefaultArgs_JoinCalledWithNoPathNoExtension(self, mock_stat, mock_join, mock_check_free):
expected_path, _ = os.path.splitext(os.path.basename(self.src_path))
mock_stat.return_value = self.src_stat
with mock.patch(self.decomp_obj_name, self.mock_decomp):
self.call_decomp(self.dest_path, self.src_path)
mock_join.assert_called_once_with(self.dest_path, expected_path)
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
@mock.patch('os.stat')
def test_Untgz_DefaultArgs_ReturnsCorrectPath(self, mock_stat, mock_join, mock_check_free):
build_name = 'build_name'
expected_path = self.dest_path+'\\'+build_name
mock_join.return_value = expected_path
mock_stat.return_value = self.src_stat
path = ''
with mock.patch(self.decomp_obj_name, self.mock_decomp):
path = self.call_decomp(self.dest_path, self.src_path)
self.assertEqual(path, expected_path)
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
@mock.patch('os.stat')
def test_Untgz_ReleaseBuild_ReturnsCorrectPath(self, mock_stat, mock_join, mock_check_free):
build_name = 'lumberyard-1.2.0.3-54321-pc-1234'
expected_path = self.dest_path + '\\' + build_name
mock_join.return_value = expected_path
mock_stat.return_value = self.src_stat
path = ''
self.src_path = r'C:\packages\lumberyard-1.2.0.3-54321-pc-1234.zip'
with mock.patch(self.decomp_obj_name, self.mock_decomp):
path = self.call_decomp(self.dest_path, self.src_path)
self.assertEqual(path, expected_path)
@mock.patch('ly_test_tools.environment.file_system.logger')
@mock.patch('os.path.exists')
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
@mock.patch('os.stat')
def test_Untgz_BuildDirExistsForceAndAllowExistsNotSet_CRITICALLogged(self, mock_stat, mock_join,
mock_check_free, mock_exists, mock_log):
force = False
mock_exists.return_value = True
mock_stat.return_value = self.src_stat
with mock.patch(self.decomp_obj_name, self.mock_decomp):
path = self.call_decomp(self.dest_path, self.src_path, False, force)
level = logging.getLevelName("CRITICAL")
mock_log.log.assert_called_with(level, 'Found existing {}. Will not overwrite.'.format(path))
@mock.patch('ly_test_tools.environment.file_system.logger')
@mock.patch('os.path.exists')
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
@mock.patch('os.stat')
def test_Untgz_AllowExiststSet_INFOLogged(self, mock_stat, mock_join, mock_check_free, mock_exists, mock_log):
allow_exists = True
force = False
mock_exists.return_value = True
mock_stat.return_value = self.src_stat
level = logging.getLevelName("INFO")
with mock.patch(self.decomp_obj_name, self.mock_decomp):
path = self.call_decomp(self.dest_path, self.src_path, False, force, allow_exists)
mock_log.log.assert_called_with(level, 'Found existing {}. Will not overwrite.'.format(path))
@mock.patch('ly_test_tools.environment.file_system.logger')
@mock.patch('os.path.exists')
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
@mock.patch('os.stat')
def test_Untgz_BuildDirExistsForceSetTrue_INFOLogged(self, mock_stat, mock_join,
mock_check_free, mock_exists, mock_log):
path = ''
mock_exists.return_value = True
mock_stat.return_value = self.src_stat
with mock.patch(self.decomp_obj_name, self.mock_decomp):
path = self.call_decomp(self.dest_path, self.src_path)
mock_log.info.assert_called_once()
class TestChangePermissions(unittest.TestCase):
def setUp(self):
# Create a mock of a os.walk return iterable.
self.root = 'root'
self.dirs = ['dir1', 'dir2']
self.files = ['file1', 'file2']
self.walk_iter = iter([(self.root, self.dirs, self.files)])
def tearDown(self):
self.root = None
self.dirs = None
self.files = None
self.walk_iter = None
@mock.patch('os.walk')
@mock.patch('os.chmod')
def test_ChangePermissions_DefaultValues_ChmodCalledCorrectly(self, mock_chmod, mock_walk):
os.walk.return_value = self.walk_iter
file_system.change_permissions('.', 0o777)
self.assertEqual(mock_chmod.mock_calls, [mock.call(os.path.join(self.root, self.dirs[0]), 0o777),
mock.call(os.path.join(self.root, self.dirs[1]), 0o777),
mock.call(os.path.join(self.root, self.files[0]), 0o777),
mock.call(os.path.join(self.root, self.files[1]), 0o777)])
@mock.patch('os.walk')
@mock.patch('os.chmod')
def test_ChangePermissions_DefaultValues_ReturnsTrueOnSuccess(self, mock_chmod, mock_walk):
os.walk.return_value = self.walk_iter
self.assertEqual(file_system.change_permissions('.', 0o777), True)
@mock.patch('os.walk')
@mock.patch('os.chmod')
def test_ChangePermissions_OSErrorRaised_ReturnsFalse(self, mock_chmod, mock_walk):
os.walk.return_value = self.walk_iter
os.chmod.side_effect = OSError()
self.assertEqual(file_system.change_permissions('.', 0o777), False)
class MockStatResult():
def __init__(self, st_mode):
self.st_mode = st_mode
class TestUnlockFile(unittest.TestCase):
def setUp(self):
self.file_name = 'file'
@mock.patch('os.stat')
@mock.patch('os.chmod')
@mock.patch('os.access')
def test_UnlockFile_WriteLocked_UnlockFile(self, mock_access, mock_chmod, mock_stat):
mock_access.return_value = False
os.stat.return_value = MockStatResult(stat.S_IREAD)
success = file_system.unlock_file(self.file_name)
mock_chmod.assert_called_once_with(self.file_name, stat.S_IREAD | stat.S_IWRITE)
self.assertTrue(success)
@mock.patch('os.stat')
@mock.patch('os.chmod')
@mock.patch('os.access')
def test_UnlockFile_AlreadyUnlocked_LogAlreadyUnlocked(self, mock_access, mock_chmod, mock_stat):
mock_access.return_value = True
os.stat.return_value = MockStatResult(stat.S_IREAD | stat.S_IWRITE)
success = file_system.unlock_file(self.file_name)
self.assertFalse(success)
class TestLockFile(unittest.TestCase):
def setUp(self):
self.file_name = 'file'
@mock.patch('os.stat')
@mock.patch('os.chmod')
@mock.patch('os.access')
def test_LockFile_UnlockedFile_FileLockedSuccessReturnsTrue(self, mock_access, mock_chmod, mock_stat):
mock_access.return_value = True
os.stat.return_value = MockStatResult(stat.S_IREAD | stat.S_IWRITE)
success = file_system.lock_file(self.file_name)
mock_chmod.assert_called_once_with(self.file_name, stat.S_IREAD)
self.assertTrue(success)
@mock.patch('os.stat')
@mock.patch('os.chmod')
@mock.patch('os.access')
def test_LockFile_AlreadyLocked_FileLockedFailedReturnsFalse(self, mock_access, mock_chmod, mock_stat):
mock_access.return_value = False
os.stat.return_value = MockStatResult(stat.S_IREAD)
success = file_system.lock_file(self.file_name)
self.assertFalse(success)
class TestRemoveSymlinks(unittest.TestCase):
def setUp(self):
# Create a mock of a os.walk return iterable.
self.root = 'root'
self.dirs = ['dir1', 'dir2']
self.files = ['file1', 'file2']
self.walk_iter = iter([(self.root, self.dirs, self.files)])
@mock.patch('os.walk')
@mock.patch('os.rmdir')
def test_RemoveSymlinks_DefaultValues_RmdirCalledCorrectly(self, mock_rmdir, mock_walk):
os.walk.return_value = self.walk_iter
file_system.remove_symlinks('.')
self.assertEqual(mock_rmdir.mock_calls, [mock.call(os.path.join(self.root, self.dirs[0])),
mock.call(os.path.join(self.root, self.dirs[1]))])
@mock.patch('os.walk')
@mock.patch('os.rmdir')
def test_RemoveSymlinks_OSErrnoEEXISTRaised_RaiseOSError(self, mock_rmdir, mock_walk):
os.walk.return_value = self.walk_iter
error = OSError()
error.errno = errno.EEXIST
mock_rmdir.side_effect = error
with self.assertRaises(OSError):
file_system.remove_symlinks('.')
class TestDelete(unittest.TestCase):
def setUp(self):
self.path_list = ['file1', 'file2', 'dir1', 'dir2']
def tearDown(self):
self.path_list = None
@mock.patch('os.path.isdir')
@mock.patch('os.path.isfile')
@mock.patch('ly_test_tools.environment.file_system.change_permissions', mock.MagicMock())
@mock.patch('shutil.rmtree', mock.MagicMock())
@mock.patch('os.remove', mock.MagicMock())
def test_Delete_StringArg_ConvertsToList(self, mock_isfile, mock_isdir):
mock_file_str = 'foo'
mock_isdir.return_value = False
mock_isfile.return_value = False
file_system.delete(mock_file_str, del_files=True, del_dirs=True)
mock_isfile.assert_called_once_with(mock_file_str)
mock_isdir.assert_called_once_with(mock_file_str)
@mock.patch('ly_test_tools.environment.file_system.change_permissions')
@mock.patch('shutil.rmtree')
@mock.patch('os.remove')
@mock.patch('os.path.isdir')
@mock.patch('os.path.isfile')
def test_ChangePermissions_OSErrorRaised_ReturnsZero(self, mock_isfile, mock_isdir, mock_remove, mock_rmtree, mock_chper):
mock_rmtree.side_effect = OSError()
self.assertEqual(file_system.delete(self.path_list, del_files=True, del_dirs=True), False)
@mock.patch('ly_test_tools.environment.file_system.change_permissions')
@mock.patch('shutil.rmtree')
@mock.patch('os.remove')
@mock.patch('os.path.isdir')
@mock.patch('os.path.isfile')
def test_ChangePermissions_DefaultValues_ReturnsLenOfList(self,
mock_isfile, mock_isdir, mock_remove, mock_rmtree, mock_chper):
self.assertEqual(file_system.delete(self.path_list, del_files=True, del_dirs=True), True)
@mock.patch('os.chmod')
@mock.patch('ly_test_tools.environment.file_system.change_permissions')
@mock.patch('shutil.rmtree')
@mock.patch('os.remove')
@mock.patch('os.path.isdir')
@mock.patch('os.path.isfile')
def test_ChangePermissions_DirsFalse_RMTreeNotCalled(self,
mock_isfile, mock_isdir, mock_remove, mock_rmtree, mock_chper,
mock_chmod):
file_system.delete(self.path_list, del_files=True, del_dirs=False)
self.assertEqual(mock_rmtree.called, False)
self.assertEqual(mock_chmod.called, True)
self.assertEqual(mock_remove.called, True)
@mock.patch('ly_test_tools.environment.file_system.change_permissions')
@mock.patch('shutil.rmtree')
@mock.patch('os.remove')
@mock.patch('os.path.isdir')
@mock.patch('os.path.isfile')
def test_ChangePermissions_NoDirs_RMTreeNotCalled(self,
mock_isfile, mock_isdir, mock_remove, mock_rmtree, mock_chper):
mock_isdir.return_value = False
file_system.delete(self.path_list, del_files=False, del_dirs=True)
self.assertEqual(mock_rmtree.called, False)
@mock.patch('ly_test_tools.environment.file_system.change_permissions')
@mock.patch('shutil.rmtree')
@mock.patch('os.remove')
@mock.patch('os.path.isdir')
@mock.patch('os.path.isfile')
def test_ChangePermissions_FilesFalse_RemoveNotCalled(self,
mock_isfile, mock_isdir, mock_remove, mock_rmtree, mock_chper):
file_system.delete(self.path_list, del_files=False, del_dirs=True)
self.assertEqual(mock_rmtree.called, True)
self.assertEqual(mock_remove.called, False)
@mock.patch('ly_test_tools.environment.file_system.change_permissions')
@mock.patch('shutil.rmtree')
@mock.patch('os.remove')
@mock.patch('os.path.isdir')
@mock.patch('os.path.isfile')
def test_ChangePermissions_NoFiles_RemoveNotCalled(self,
mock_isfile, mock_isdir, mock_remove, mock_rmtree, mock_chper):
mock_isfile.return_value = False
file_system.delete(self.path_list, del_files=True, del_dirs=False)
self.assertEqual(mock_remove.called, False)
class TestDeleteOldest(unittest.TestCase):
def setUp(self):
self.path_list = ['file1', 'file2', 'dir1', 'dir2']
self.age_list = [4, 3, 2, 1]
def tearDown(self):
self.path_list = None
self.age_list = None
@mock.patch('glob.iglob')
@mock.patch('os.path.getctime')
@mock.patch('ly_test_tools.environment.file_system.delete')
def test_DeleteOldest_DefaultValuesKeepAll_DeleteCalledWithEmptyList(self, mock_delete, mock_ctime, mock_glob):
mock_glob.return_value = self.path_list
mock_ctime.side_effect = self.age_list
# Nothing will be deleted because it's keeping everything.
file_system.delete_oldest('', len(self.path_list), del_files=True, del_dirs=False)
mock_delete.assert_called_once_with([], True, False)
@mock.patch('glob.iglob')
@mock.patch('os.path.getctime')
@mock.patch('ly_test_tools.environment.file_system.delete')
def test_DeleteOldest_DefaultValuesKeepNone_DeleteCalledWithList(self, mock_delete, mock_ctime, mock_glob):
mock_glob.return_value = self.path_list
mock_ctime.side_effect = self.age_list
# Everything will be deleted because it's keeping nothing.
file_system.delete_oldest('', 0, del_files=True, del_dirs=False)
mock_delete.assert_called_once_with(self.path_list, True, False)
@mock.patch('glob.iglob')
@mock.patch('os.path.getctime')
@mock.patch('ly_test_tools.environment.file_system.delete')
def test_DeleteOldest_DefaultValuesKeepOne_DeleteCalledWithoutNewest(self, mock_delete, mock_ctime, mock_glob):
mock_glob.return_value = self.path_list
mock_ctime.side_effect = self.age_list
file_system.delete_oldest('', 1, del_files=True, del_dirs=False)
self.path_list.pop(0)
mock_delete.assert_called_once_with(self.path_list, True, False)
@mock.patch('glob.iglob')
@mock.patch('os.path.getctime')
@mock.patch('ly_test_tools.environment.file_system.delete')
def test_DeleteOldest_UnsortedListDeleteOldest_DeleteCalledWithOldest(self, mock_delete, mock_ctime, mock_glob):
mock_glob.return_value = ['newest', 'old', 'newer']
mock_ctime.side_effect = [100, 0, 50]
file_system.delete_oldest('', 2, del_files=True, del_dirs=False)
mock_delete.assert_called_once_with(['old'], True, False)
class TestMakeJunction(unittest.TestCase):
def test_MakeJunction_Nondir_RaisesIOError(self):
with self.assertRaises(IOError):
file_system.make_junction('', '')
@mock.patch('os.path.isdir')
@mock.patch('sys.platform', 'linux2')
def test_MakeJunction_NoSupportPlatform_RaisesIOError(self, mock_isdir):
mock_isdir.return_value = True
with self.assertRaises(IOError):
file_system.make_junction('', '')
@mock.patch('subprocess.check_call')
@mock.patch('os.path.isdir')
@mock.patch('sys.platform', 'win32')
def test_MakeJunction_Win32_SubprocessFails_RaiseSubprocessError(self, mock_isdir, mock_sub_call):
mock_isdir.return_value = True
mock_sub_call.side_effect = subprocess.CalledProcessError(1, 'cmd', 'output')
with self.assertRaises(subprocess.CalledProcessError):
file_system.make_junction('', '')
@mock.patch('subprocess.check_output')
@mock.patch('os.path.isdir')
@mock.patch('sys.platform', 'darwin')
def test_MakeJunction_Darwin_SubprocessFails_RaiseSubprocessError(self, mock_isdir, mock_sub_call):
mock_isdir.return_value = True
mock_sub_call.side_effect = subprocess.CalledProcessError(1, 'cmd', 'output')
with self.assertRaises(subprocess.CalledProcessError):
file_system.make_junction('', '')
@mock.patch('subprocess.check_output')
@mock.patch('os.path.isdir')
@mock.patch('sys.platform', 'win32')
def test_MakeJunction_Win32_SubprocessCall_Calls(self, mock_isdir, mock_sub_call):
mock_isdir.return_value = True
src = 'source'
dest = 'destination'
file_system.make_junction(dest, src)
mock_sub_call.assert_called_once_with(['mklink', '/J', dest, src], shell=True)
@mock.patch('subprocess.check_output')
@mock.patch('os.path.isdir')
@mock.patch('sys.platform', 'darwin')
def test_MakeJunction_Darwin_SubprocessCall_Calls(self, mock_isdir, mock_sub_call):
mock_isdir.return_value = True
src = 'source'
dest = 'destination'
file_system.make_junction(dest, src)
mock_sub_call.assert_called_once_with(['ln', dest, src])
class TestFileBackup(unittest.TestCase):
def setUp(self):
self._dummy_dir = os.path.join('somewhere', 'something')
self._dummy_file = 'dummy.txt'
self._dummy_backup_file = os.path.join(self._dummy_dir, '{}.bak'.format(self._dummy_file))
@mock.patch('shutil.copy')
@mock.patch('os.path.exists')
@mock.patch('os.path.isdir')
def test_BackupSettings_SourceExists_BackupCreated(self, mock_path_isdir, mock_backup_exists, mock_copy):
mock_path_isdir.return_value = True
mock_backup_exists.side_effect = [True, False]
file_system.create_backup(self._dummy_file, self._dummy_dir)
mock_copy.assert_called_with(self._dummy_file, self._dummy_backup_file)
@mock.patch('ly_test_tools.environment.file_system.logger.warning')
@mock.patch('shutil.copy')
@mock.patch('os.path.exists')
@mock.patch('os.path.isdir')
def test_BackupSettings_BackupExists_WarningLogged(self, mock_path_isdir, mock_backup_exists, mock_copy, mock_logger_warning):
mock_path_isdir.return_value = True
mock_backup_exists.return_value = True
file_system.create_backup(self._dummy_file, self._dummy_dir)
mock_copy.assert_called_with(self._dummy_file, self._dummy_backup_file)
mock_logger_warning.assert_called_once()
@mock.patch('ly_test_tools.environment.file_system.logger.warning')
@mock.patch('shutil.copy')
@mock.patch('os.path.exists')
@mock.patch('os.path.isdir')
def test_BackupSettings_SourceNotExists_WarningLogged(self, mock_path_isdir, mock_backup_exists, mock_copy, mock_logger_warning):
mock_path_isdir.return_value = True
mock_backup_exists.return_value = False
file_system.create_backup(self._dummy_file, self._dummy_dir)
mock_copy.assert_not_called()
mock_logger_warning.assert_called_once()
@mock.patch('ly_test_tools.environment.file_system.logger.warning')
@mock.patch('shutil.copy')
@mock.patch('os.path.exists')
@mock.patch('os.path.isdir')
def test_BackupSettings_CannotCopy_WarningLogged(self, mock_path_isdir, mock_backup_exists, mock_copy, mock_logger_warning):
mock_path_isdir.return_value = True
mock_backup_exists.side_effect = [True, False]
mock_copy.side_effect = Exception('some error')
file_system.create_backup(self._dummy_file, self._dummy_dir)
mock_copy.assert_called_with(self._dummy_file, self._dummy_backup_file)
mock_logger_warning.assert_called_once()
@mock.patch('ly_test_tools.environment.file_system.logger.error')
@mock.patch('os.path.exists')
@mock.patch('os.path.isdir')
def test_BackupSettings_InvalidDir_ErrorLogged(self, mock_path_isdir, mock_backup_exists, mock_logger_error):
mock_path_isdir.return_value = False
mock_backup_exists.return_value = False
file_system.create_backup(self._dummy_file, None)
mock_logger_error.assert_called_once()
class TestFileBackupRestore(unittest.TestCase):
def setUp(self):
self._dummy_dir = os.path.join('somewhere', 'something')
self._dummy_file = 'dummy.txt'
self._dummy_backup_file = os.path.join(self._dummy_dir, '{}.bak'.format(self._dummy_file))
@mock.patch('shutil.copy')
@mock.patch('os.path.exists')
@mock.patch('os.path.isdir')
def test_RestoreSettings_BackupRestore_Success(self, mock_path_isdir, mock_exists, mock_copy):
mock_path_isdir.return_value = True
mock_exists.return_value = True
file_system.restore_backup(self._dummy_file, self._dummy_dir)
mock_copy.assert_called_with(self._dummy_backup_file, self._dummy_file)
@mock.patch('ly_test_tools.environment.file_system.logger.warning')
@mock.patch('shutil.copy')
@mock.patch('os.path.exists')
@mock.patch('os.path.isdir')
def test_RestoreSettings_CannotCopy_WarningLogged(self, mock_path_isdir, mock_exists, mock_copy, mock_logger_warning):
mock_path_isdir.return_value = True
mock_exists.return_value = True
mock_copy.side_effect = Exception('some error')
file_system.restore_backup(self._dummy_file, self._dummy_dir)
mock_copy.assert_called_with(self._dummy_backup_file, self._dummy_file)
mock_logger_warning.assert_called_once()
@mock.patch('ly_test_tools.environment.file_system.logger.warning')
@mock.patch('shutil.copy')
@mock.patch('os.path.exists')
@mock.patch('os.path.isdir')
def test_RestoreSettings_BackupNotExists_WarningLogged(self, mock_path_isdir, mock_exists, mock_copy, mock_logger_warning):
mock_path_isdir.return_value = True
mock_exists.return_value = False
file_system.restore_backup(self._dummy_file, self._dummy_dir)
mock_copy.assert_not_called()
mock_logger_warning.assert_called_once()
@mock.patch('ly_test_tools.environment.file_system.logger.error')
def test_RestoreSettings_InvalidDir_ErrorLogged(self, mock_logger_error):
file_system.restore_backup(self._dummy_file, None)
mock_logger_error.assert_called_once()
@mock.patch('ly_test_tools.environment.file_system.logger.error')
@mock.patch('os.path.isdir')
def test_RestoreSettings_InvalidDir_ErrorLogged(self, mock_path_isdir, mock_logger_error):
mock_path_isdir.return_value = False
file_system.restore_backup(self._dummy_file, self._dummy_dir)
mock_logger_error.assert_called_once()
class TestReduceFileName(unittest.TestCase):
def test_Reduce_LongString_ReturnsReducedString(self):
target_name = 'really_long_string_that_needs_reduction' # len(mock_file_name) == 39
max_length = 25
under_test = file_system.reduce_file_name_length(target_name, max_length)
assert len(under_test) == max_length
def test_Reduce_ShortString_ReturnsSameString(self):
target_name = 'less_than_max' # len(mock_file_name) == 13
max_length = 25
under_test = file_system.reduce_file_name_length(target_name, max_length)
assert under_test == target_name
def test_Reduce_NoString_RaisesTypeError(self):
with pytest.raises(TypeError):
file_system.reduce_file_name_length(max_length=25)
def test_Reduce_NoMaxLength_RaisesTypeError(self):
target_name = 'raises_type_error'
with pytest.raises(TypeError):
file_system.reduce_file_name_length(file_name=target_name)