test_artifact_manager.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. """
  2. Copyright (c) Contributors to the Open 3D Engine Project.
  3. For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. SPDX-License-Identifier: Apache-2.0 OR MIT
  5. Unit Tests for WorkspaceManager class
  6. """
  7. import datetime
  8. import os
  9. import stat
  10. import unittest.mock as mock
  11. import unittest
  12. import os
  13. import pytest
  14. import ly_test_tools._internal.managers.artifact_manager
  15. TIMESTAMP_FORMAT = '%Y-%m-%dT%H-%M-%S-%f'
  16. DATE = datetime.datetime.now().strftime(TIMESTAMP_FORMAT)
  17. ROOT_LOG_FOLDER = os.path.join("TestResults", DATE, "pytest_results")
  18. class TestSetTestName(unittest.TestCase):
  19. def setUp(self):
  20. self.mock_root = ROOT_LOG_FOLDER
  21. self.mock_artifact_manager = ly_test_tools._internal.managers.artifact_manager.ArtifactManager(
  22. self.mock_root)
  23. @mock.patch('ly_test_tools._internal.managers.artifact_manager.ArtifactManager.set_dest_path')
  24. def test_Init_Called_CallsSetDestPath(self, mock_set_dest_path):
  25. self.mock_artifact_manager = ly_test_tools._internal.managers.artifact_manager.ArtifactManager(
  26. self.mock_root)
  27. assert mock_set_dest_path.called
  28. @mock.patch('os.makedirs', mock.MagicMock())
  29. @mock.patch('os.path.exists', mock.MagicMock(return_value=False))
  30. def test_SetDestPath_NoPathExists_CreatesPathSetsAttributes(self):
  31. create_amount = 1
  32. updated_path = "{}".format(self.mock_artifact_manager.artifact_path, create_amount)
  33. self.mock_artifact_manager.dest_path = None # Reset the value to test the function
  34. self.mock_artifact_manager.set_dest_path(test_name=None, amount=create_amount)
  35. assert self.mock_artifact_manager.artifact_path == self.mock_root
  36. assert self.mock_artifact_manager.dest_path == updated_path
  37. @mock.patch('os.path.exists', mock.MagicMock(return_value=True))
  38. @mock.patch('os.makedirs')
  39. def test_SetDestPath_PathExists_NoPathCreatedSetsAttributes(self, mock_makedirs):
  40. self.mock_artifact_manager.dest_path = None # Reset the value to test the function
  41. self.mock_artifact_manager.set_dest_path()
  42. assert self.mock_artifact_manager.artifact_path == self.mock_root
  43. assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path
  44. assert not mock_makedirs.called
  45. @mock.patch('os.makedirs', mock.MagicMock())
  46. @mock.patch('os.path.exists', mock.MagicMock(return_value=False))
  47. @mock.patch('ly_test_tools._internal.managers.artifact_manager.ArtifactManager._get_collision_handled_filename')
  48. def test_SetDestPathAmount_IsCalled_CallsGetCollision(self, mock_get_collision):
  49. create_amount = 2
  50. test_name = 'dummy'
  51. mock_get_collision.return_value = test_name
  52. self.mock_artifact_manager.set_dest_path(test_name, create_amount)
  53. mock_get_collision.assert_called_once_with(os.path.join(self.mock_root, test_name), create_amount)
  54. @mock.patch('os.makedirs', mock.MagicMock())
  55. @mock.patch('os.path.exists', mock.MagicMock(return_value=True))
  56. def test_SetDestPathAmount_ValidFilePathExists_NoFilePathCreatedSetsAttributes(self):
  57. test_name = 'dummy'
  58. expected_path = os.path.join(self.mock_artifact_manager.artifact_path, test_name)
  59. self.mock_artifact_manager.set_dest_path(test_name)
  60. assert self.mock_artifact_manager.dest_path == expected_path
  61. @mock.patch('os.makedirs', mock.MagicMock())
  62. class TestSaveArtifact(unittest.TestCase):
  63. def setUp(self):
  64. self.mock_root = ROOT_LOG_FOLDER
  65. self.mock_artifact_manager = ly_test_tools._internal.managers.artifact_manager.ArtifactManager(self.mock_root)
  66. @mock.patch('os.path.exists', mock.MagicMock(return_value=False))
  67. @mock.patch('shutil.copytree')
  68. @mock.patch('os.path.isdir')
  69. @mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
  70. def test_SaveArtifact_ArtifactNameIsNotNone_CopyTreeCalledCorrectly(self, mock_reducer, mock_path_isdir,
  71. mock_copy_tree):
  72. test_name = 'dummy'
  73. mock_artifact_name = 'mock_artifact_name'
  74. updated_path = "{}".format(os.path.join(self.mock_artifact_manager.artifact_path,
  75. test_name))
  76. mock_path_isdir.return_value = True
  77. mock_copy_tree.return_value = True
  78. mock_reducer.return_value = mock_artifact_name[:-5]
  79. self.mock_artifact_manager.set_dest_path(test_name)
  80. self.mock_artifact_manager.save_artifact(updated_path, mock_artifact_name)
  81. assert self.mock_artifact_manager.dest_path == updated_path
  82. mock_copy_tree.assert_called_once_with(updated_path, os.path.join(updated_path, mock_artifact_name[:-5]),
  83. dirs_exist_ok=True)
  84. mock_reducer.assert_called_once_with(file_name=mock_artifact_name, max_length=25)
  85. @mock.patch('os.path.exists', mock.MagicMock(return_value=False))
  86. @mock.patch('shutil.copytree')
  87. @mock.patch('os.path.isdir')
  88. @mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
  89. def test_SaveArtifact_ArtifactNameIsNone_CopyTreeCalledCorrectly(self, mock_reducer, mock_path_isdir,
  90. mock_copy_tree):
  91. mock_artifact_name = None
  92. mock_path_isdir.return_value = True
  93. mock_copy_tree.return_value = True
  94. self.mock_artifact_manager.save_artifact(self.mock_artifact_manager.artifact_path, mock_artifact_name)
  95. assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path
  96. mock_copy_tree.assert_called_once_with(
  97. self.mock_artifact_manager.artifact_path,
  98. os.path.join(self.mock_artifact_manager.artifact_path, 'pytest_results'), dirs_exist_ok=True)
  99. mock_reducer.assert_not_called()
  100. @mock.patch('os.path.exists', mock.MagicMock(return_value=False))
  101. @mock.patch('os.chmod', mock.MagicMock())
  102. @mock.patch('shutil.copy')
  103. @mock.patch('os.path.isdir')
  104. @mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
  105. def test_SaveArtifact_ArtifactNameIsNotNone_CopyCalledCorrectly(self, mock_reducer, mock_path_isdir,
  106. mock_copy):
  107. mock_artifact_name = 'mock_artifact_name'
  108. mock_path_isdir.return_value = False
  109. mock_reducer.return_value = mock_artifact_name[:-5]
  110. mock_copy.return_value = True
  111. self.mock_artifact_manager.save_artifact(self.mock_artifact_manager.artifact_path, mock_artifact_name)
  112. assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path
  113. mock_copy.assert_called_once_with(
  114. self.mock_artifact_manager.artifact_path,
  115. os.path.join(self.mock_artifact_manager.artifact_path, mock_artifact_name[:-5]))
  116. mock_reducer.assert_called_once_with(file_name=mock_artifact_name, max_length=25)
  117. @mock.patch('os.path.exists', mock.MagicMock(return_value=False))
  118. @mock.patch('os.chmod', mock.MagicMock())
  119. @mock.patch('shutil.copy')
  120. @mock.patch('os.path.isdir')
  121. @mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
  122. def test_SaveArtifact_ArtifactNameIsNone_CopyCalledCorrectly(self, mock_reducer, mock_path_isdir,
  123. mock_copy):
  124. mock_artifact_name = None
  125. mock_path_isdir.return_value = False
  126. mock_copy.return_value = True
  127. self.mock_artifact_manager.save_artifact(self.mock_artifact_manager.artifact_path, mock_artifact_name)
  128. assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path
  129. mock_copy.assert_called_once_with(
  130. self.mock_artifact_manager.artifact_path,
  131. os.path.join(self.mock_artifact_manager.artifact_path, 'pytest_results'))
  132. mock_reducer.assert_not_called()
  133. @mock.patch('os.path.exists', mock.MagicMock(return_value=False))
  134. @mock.patch('shutil.copy', mock.MagicMock())
  135. @mock.patch('os.chmod')
  136. @mock.patch('os.path.isdir')
  137. @mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
  138. def test_SaveArtifact_ArtifactNameIsNotNone_ChmodCalledCorrectly(self, mock_reducer, mock_path_isdir, mock_chmod):
  139. mock_artifact_name = 'mock_artifact_name'
  140. mock_path_isdir.return_value = False
  141. mock_reducer.return_value = mock_artifact_name[:-5]
  142. self.mock_artifact_manager.save_artifact(self.mock_artifact_manager.artifact_path, mock_artifact_name)
  143. mock_chmod.assert_called_once_with(
  144. os.path.join(self.mock_artifact_manager.artifact_path, mock_artifact_name[:-5]),
  145. stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC)
  146. assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path
  147. mock_reducer.assert_called_once_with(file_name=mock_artifact_name, max_length=25)
  148. @mock.patch('os.path.exists', mock.MagicMock(return_value=False))
  149. @mock.patch('shutil.copy', mock.MagicMock())
  150. @mock.patch('os.chmod')
  151. @mock.patch('os.path.isdir')
  152. @mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
  153. def test_SaveArtifact_ArtifactNameIsNone_ChmodCalledCorrectly(self, mock_reducer, mock_path_isdir, mock_chmod):
  154. mock_artifact_name = None
  155. mock_path_isdir.return_value = False
  156. self.mock_artifact_manager.save_artifact(self.mock_artifact_manager.artifact_path, mock_artifact_name)
  157. mock_chmod.assert_called_once_with(
  158. os.path.join(self.mock_artifact_manager.artifact_path, 'pytest_results'),
  159. stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC)
  160. assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path
  161. mock_reducer.assert_not_called()
  162. @mock.patch('os.path.exists', mock.MagicMock(return_value=True))
  163. @mock.patch('os.path.isdir', mock.MagicMock(return_value=False))
  164. @mock.patch('shutil.copy', mock.MagicMock())
  165. @mock.patch('os.chmod', mock.MagicMock())
  166. @mock.patch('ly_test_tools._internal.managers.artifact_manager.ArtifactManager._get_collision_handled_filename')
  167. def test_SaveArtifact_DestinationCollides_CallsGetCollisionHandledFilename(self, under_test):
  168. self.mock_artifact_manager.save_artifact(self.mock_artifact_manager.artifact_path)
  169. under_test.assert_called_once()
  170. @mock.patch('os.path.exists', mock.MagicMock(return_value=True))
  171. class TestGenerateArtifactFileName(unittest.TestCase):
  172. def setUp(self):
  173. self.mock_root = ROOT_LOG_FOLDER
  174. self.mock_artifact_manager = ly_test_tools._internal.managers.artifact_manager.ArtifactManager(self.mock_root)
  175. @mock.patch('os.path.isdir')
  176. @mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
  177. def test_GenerateFileName_HasArtifactName_ReturnsFilePath(self, mock_reducer, mock_path_isdir):
  178. mock_artifact_name = 'mock_artifact_name'
  179. mock_path_isdir.return_value = True
  180. mock_artifact_file = self.mock_artifact_manager.generate_artifact_file_name(mock_artifact_name)
  181. assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path, (
  182. 'dest_path does not match self.mock_artifact_manager.artifact_path')
  183. assert mock_artifact_file == os.path.join(self.mock_artifact_manager.artifact_path, mock_artifact_name), (
  184. 'mock_artifact_file does not match expected value from generate_artifact_file_name()')
  185. mock_reducer.assert_not_called()
  186. @mock.patch('os.path.isdir')
  187. @mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
  188. def test_GenerateFileName_ArtifactNameIsNone_ReturnsFilePath(self, mock_reducer, mock_path_isdir):
  189. mock_artifact_name = None
  190. mock_path_isdir.return_value = True
  191. with pytest.raises(ValueError):
  192. self.mock_artifact_manager.generate_artifact_file_name(mock_artifact_name)
  193. mock_reducer.assert_not_called()
  194. @mock.patch('os.path.exists', mock.MagicMock(return_value=True))
  195. class TestGatherArtifacts(unittest.TestCase):
  196. def setUp(self):
  197. self.mock_root = ROOT_LOG_FOLDER
  198. self.mock_artifact_manager = ly_test_tools._internal.managers.artifact_manager.ArtifactManager(self.mock_root)
  199. @mock.patch('shutil.make_archive')
  200. def test_TestGatherArtifacts_TestNameIsNone_MakeArchiveCalled(self, mock_make_archive):
  201. mock_destination = 'mock_destination'
  202. self.mock_artifact_manager.gather_artifacts(mock_destination)
  203. mock_make_archive.assert_called_once_with(mock_destination, 'zip', self.mock_artifact_manager.artifact_path)
  204. @mock.patch('ly_test_tools.environment.file_system.sanitize_file_name')
  205. @mock.patch('shutil.make_archive')
  206. def test_TestGatherArtifacts_TestNameIsNotNone_MakeArchiveCalled(self, mock_make_archive, mock_sanitize_file_name):
  207. test_name = 'dummy'
  208. mock_destination = 'mock_destination'
  209. mock_sanitize_file_name.return_value = test_name
  210. self.mock_artifact_manager.set_dest_path(test_name)
  211. self.mock_artifact_manager.gather_artifacts(mock_destination)
  212. mock_make_archive.assert_called_once_with(
  213. mock_destination, 'zip',
  214. os.path.join(self.mock_artifact_manager.artifact_path, test_name))
  215. class TestGetCollisionHandledFilename(unittest.TestCase):
  216. def setUp(self):
  217. self.mock_root = ROOT_LOG_FOLDER
  218. self.mock_artifact_manager = ly_test_tools._internal.managers.artifact_manager.ArtifactManager(self.mock_root)
  219. @mock.patch('os.path.exists', mock.MagicMock(return_value=False))
  220. def test_GetCollisionHandledFilename_FileNameExists_FileNameAppendsNumber(self):
  221. create_amount = 2
  222. test_name = 'dummy'
  223. updated_path = f"{test_name}_1"
  224. under_test = self.mock_artifact_manager._get_collision_handled_filename(test_name, create_amount)
  225. assert under_test == updated_path
  226. def test_GetCollisionHandledFilename_AmountOne_ReturnsParam(self):
  227. mock_file_path = 'foo'
  228. amount = 1
  229. under_test = self.mock_artifact_manager._get_collision_handled_filename(mock_file_path, amount)
  230. assert under_test == mock_file_path
  231. @mock.patch('os.path.exists', mock.MagicMock())
  232. def test_GetCollisionHandledFilename_HasExt_RenameWithExtProperly(self):
  233. mock_file_path = 'foo'
  234. mock_file_ext = '.ext'
  235. mock_file_with_ext = mock_file_path + mock_file_ext
  236. amount = 2
  237. under_test = self.mock_artifact_manager._get_collision_handled_filename(mock_file_with_ext, amount)
  238. assert under_test == f'{mock_file_path}_{amount-1}{mock_file_ext}'
  239. @mock.patch('os.path.exists', mock.MagicMock())
  240. def test_GetCollisionHandledFilename_HasNoExt_RenameWithoutExtProperly(self):
  241. mock_file_path = 'foo'
  242. amount = 2
  243. under_test = self.mock_artifact_manager._get_collision_handled_filename(mock_file_path, amount)
  244. assert under_test == f'{mock_file_path}_{amount-1}'
  245. @mock.patch('os.path.exists')
  246. def test_GetCollisionHandledFilename_HasLargeAmountAndNotPathExists_EndsLoopEarly(self, mock_path_exists):
  247. mock_file_path = 'foo'
  248. amount = 99
  249. mock_path_exists.side_effect = [True, True, False]
  250. under_test = self.mock_artifact_manager._get_collision_handled_filename(mock_file_path, amount)
  251. # The integer should be the index of False in mock_path_exists
  252. assert under_test == f'{mock_file_path}_{3}'
  253. @mock.patch('os.path.exists')
  254. def test_GetCollisionHandledFilename_HasLargeAmountAndCollides_ReachesMaxAmount(self, mock_path_exists):
  255. mock_file_path = 'foo'
  256. amount = 99
  257. mock_path_exists.return_value = True
  258. under_test = self.mock_artifact_manager._get_collision_handled_filename(mock_file_path, amount)
  259. assert under_test == f'{mock_file_path}_{amount-1}'