test_fixtures.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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 ly_test_tools._internal.pytest_plugin.test_tools_fixtures
  6. """
  7. import datetime
  8. import os
  9. import unittest.mock as mock
  10. import pytest
  11. import ly_test_tools._internal.pytest_plugin.test_tools_fixtures as test_tools_fixtures
  12. pytestmark = pytest.mark.SUITE_smoke
  13. class TestFixtures(object):
  14. def test_AddOptionForLogs_MockParser_OptionAdded(self):
  15. mock_parser = mock.MagicMock()
  16. test_tools_fixtures.pytest_addoption(mock_parser)
  17. mock_call = mock_parser.addoption.mock_calls[0]
  18. """
  19. mock_call is the same as: call('--output_path', help='Set the folder name for the output logs.')
  20. which results in a 3-tuple with (name, args, kwargs), so --output_path is in the list of args
  21. """
  22. assert mock_call[1][0] == '--output-path'
  23. def test_RecordSuiteProperty_MockRequestWithEmptyXml_PropertyAdded(self):
  24. mock_request = mock.MagicMock()
  25. mock_xml = mock.MagicMock()
  26. mock_request.config._xml = mock_xml
  27. func = test_tools_fixtures._record_suite_property(mock_request)
  28. func('NewProperty', 'value')
  29. mock_xml.add_global_property.assert_called_once_with('NewProperty', 'value')
  30. def test_RecordSuiteProperty_MockRequestWithPropertyXml_PropertyUpdated(self):
  31. mock_request = mock.MagicMock()
  32. mock_xml = mock.MagicMock()
  33. mock_xml.global_properties = [('ExistingProperty', 'old value')]
  34. mock_request.config._xml = mock_xml
  35. func = test_tools_fixtures._record_suite_property(mock_request)
  36. func('ExistingProperty', 'new value')
  37. assert mock_xml.global_properties[0] == ('ExistingProperty', 'new value')
  38. mock_xml.add_global_property.assert_not_called()
  39. @mock.patch('ly_test_tools._internal.pytest_plugin.test_tools_fixtures.logger')
  40. def test_RecordSuiteProperty_MockRequestWithoutXml_NoOpReturned(self, mock_logger):
  41. mock_request = mock.MagicMock()
  42. mock_request.config._xml = None
  43. func = test_tools_fixtures._record_suite_property(mock_request)
  44. mock_logger.debug.assert_not_called()
  45. func('SomeProperty', 'some value')
  46. mock_logger.debug.assert_called_once()
  47. @mock.patch('os.makedirs')
  48. def test_LogsPath_CustomPathOption_CustomPathCreated(self, mock_makedirs):
  49. expected = 'SomePath'
  50. mock_config = mock.MagicMock()
  51. mock_config.getoption.return_value = expected
  52. actual = test_tools_fixtures._get_output_path(mock_config)
  53. assert actual == expected
  54. mock_makedirs.assert_called_once_with('SomePath', exist_ok=True)
  55. @mock.patch('ly_test_tools._internal.pytest_plugin.test_tools_fixtures.datetime',
  56. mock.Mock(now=lambda: datetime.datetime(2019, 10, 11)))
  57. @mock.patch('os.getcwd')
  58. @mock.patch('os.makedirs')
  59. def test_LogsPath_NoPathOption_DefaultPathCreated(self, mock_makedirs, mock_getcwd):
  60. mock_config = mock.MagicMock()
  61. mock_cwd = 'C:/foo'
  62. mock_getcwd.return_value = mock_cwd
  63. mock_config.getoption.return_value = None
  64. expected = os.path.join(mock_cwd,
  65. 'pytest_results',
  66. '2019-10-11T00-00-00-000000')
  67. actual = test_tools_fixtures._get_output_path(mock_config)
  68. assert actual == expected
  69. mock_makedirs.assert_called_once_with(expected, exist_ok=True)
  70. def test_RecordBuildName_MockRecordFunction_MockFunctionCalled(self):
  71. mock_fn = mock.MagicMock()
  72. func = test_tools_fixtures._record_build_name(mock_fn)
  73. func('MyBuild')
  74. mock_fn.assert_called_once_with('build', 'MyBuild')
  75. @mock.patch('ly_test_tools._internal.pytest_plugin.test_tools_fixtures.datetime',
  76. mock.Mock(now=lambda: datetime.datetime(2019, 10, 11)))
  77. def test_RecordTimeStamp_MockRecordFunction_MockFunctionCalled(self):
  78. mock_fn = mock.MagicMock()
  79. test_tools_fixtures._record_test_timestamp(mock_fn)
  80. mock_fn.assert_called_once_with('timestamp', '2019-10-11T00-00-00-000000')
  81. @mock.patch('ly_test_tools._internal.pytest_plugin.test_tools_fixtures.datetime',
  82. mock.Mock(now=lambda: datetime.datetime(2019, 10, 11)))
  83. @mock.patch('socket.gethostname')
  84. @mock.patch('getpass.getuser')
  85. def test_RecordSuiteData_MockRecordFunction_MockFunctionCalled(self, mock_getuser, mock_gethostname):
  86. mock_getuser.return_value = 'foo@bar.baz'
  87. mock_gethostname.return_value = 'bar.baz'
  88. mock_fn = mock.MagicMock()
  89. test_tools_fixtures._record_suite_data(mock_fn)
  90. expected_calls = [mock.call('timestamp', '2019-10-11T00-00-00-000000'),
  91. mock.call('hostname', 'bar.baz'),
  92. mock.call('username', 'foo@bar.baz')]
  93. mock_fn.assert_has_calls(expected_calls)
  94. @mock.patch("ly_test_tools._internal.log.py_logging_util.initialize_logging", mock.MagicMock())
  95. @mock.patch("ly_test_tools.builtin.helpers.setup_builtin_workspace")
  96. @mock.patch("ly_test_tools.builtin.helpers.create_builtin_workspace")
  97. def test_Workspace_MockFixturesAndExecTeardown_ReturnWorkspaceRegisterTeardown(self, mock_create, mock_setup):
  98. test_module = 'example.tests.test_system_example'
  99. test_class = ('TestSystemExample.test_SystemTestExample_AllSupportedPlatforms_LaunchAutomatedTesting'
  100. '[120-simple_jacklocomotion-AutomatedTesting-all-profile-win_x64_vs2017]')
  101. test_method = 'test_SystemTestExample_AllSupportedPlatforms_LaunchAutomatedTesting'
  102. artifact_folder_name = 'TheArtifactFolder'
  103. artifact_path = "PathToArtifacts"
  104. mock_request = mock.MagicMock()
  105. mock_request.addfinalizer = mock.MagicMock()
  106. mock_request.node.module.__name__ = test_module
  107. mock_request.node.getmodpath.return_value = test_class
  108. mock_request.node.originalname = test_method
  109. mock_workspace = mock.MagicMock()
  110. mock_workspace.artifact_manager.generate_folder_name.return_value = artifact_folder_name
  111. mock_workspace.artifact_manager.artifact_path = artifact_path
  112. mock_workspace.artifact_manager.gather_artifacts.return_value = os.path.join(artifact_path, 'foo.zip')
  113. mock_create.return_value = mock_workspace
  114. mock_property = mock.MagicMock()
  115. mock_build_name = mock.MagicMock()
  116. mock_logs = "foo"
  117. under_test = test_tools_fixtures._workspace(
  118. request=mock_request,
  119. build_directory='foo',
  120. project="",
  121. record_property=mock_property,
  122. record_build_name=mock_build_name,
  123. output_path=mock_logs,
  124. asset_processor_platform='ap_platform'
  125. )
  126. assert under_test is mock_workspace
  127. # verify additional commands are called
  128. mock_create.assert_called_once()
  129. mock_setup.assert_called_once_with(under_test, artifact_folder_name, mock_request.session.testscollected)
  130. # verify teardown was hooked but not called
  131. mock_request.addfinalizer.assert_called_once()
  132. mock_workspace.teardown.assert_not_called()
  133. # execute teardown hook from recorded call, and verify called
  134. mock_request.addfinalizer.call_args[0][0]()
  135. mock_workspace.teardown.assert_called_once()
  136. mock_workspace.artifact_manager.generate_folder_name.assert_called_with(
  137. test_module.split('.')[-1], # 'example.tests.test_system_example' -> 'test_system_example'
  138. test_class.split('.')[0], # 'TestSystemExample.test_SystemTestExample_...' -> 'TestSystemExample'
  139. test_method # 'test_SystemTestExample_AllSupportedPlatforms_LaunchAutomatedTesting'
  140. )
  141. @mock.patch('os.path.exists', mock.MagicMock(return_value=True))
  142. @mock.patch("ly_test_tools.launchers.launcher_helper.create_game_launcher")
  143. def test_Launcher_MockHelper_Passthrough(self, mock_create):
  144. retval = mock.MagicMock()
  145. mock_create.return_value = retval
  146. mock_workspace = mock.MagicMock()
  147. under_test = test_tools_fixtures._launcher(mock.MagicMock(), mock_workspace, 'windows', 'level')
  148. mock_create.assert_called_once()
  149. assert retval is under_test
  150. @mock.patch('os.path.exists', mock.MagicMock(return_value=True))
  151. @mock.patch("ly_test_tools.launchers.launcher_helper.create_game_launcher")
  152. def test_Launcher_MockHelper_TeardownCalled(self, mock_create):
  153. retval = mock.MagicMock()
  154. retval.stop = mock.MagicMock()
  155. mock_create.return_value = retval
  156. mock_request = mock.MagicMock()
  157. mock_workspace = mock.MagicMock()
  158. def _fail_finalizer():
  159. assert False, "teardown should have been added to finalizer"
  160. def _capture_finalizer(func):
  161. nonlocal _finalizer
  162. _finalizer = func
  163. _finalizer = _fail_finalizer
  164. mock_request.addfinalizer = _capture_finalizer
  165. under_test = test_tools_fixtures._launcher(mock_request, mock_workspace, 'windows', 'level')
  166. assert retval is under_test
  167. assert _finalizer is not None
  168. _finalizer()
  169. retval.stop.assert_called_once()
  170. @mock.patch("ly_test_tools.launchers.launcher_helper.create_editor")
  171. def test_Editor_MockHelper_Passthrough(self, mock_create):
  172. retval = mock.MagicMock()
  173. mock_create.return_value = retval
  174. under_test = test_tools_fixtures._editor(mock.MagicMock(), mock.MagicMock(), 'windows_editor')
  175. mock_create.assert_called_once()
  176. assert retval is under_test
  177. @mock.patch("ly_test_tools.launchers.launcher_helper.create_editor")
  178. def test_Editor_MockHelper_TeardownCalled(self, mock_create):
  179. retval = mock.MagicMock()
  180. retval.stop = mock.MagicMock()
  181. mock_request = mock.MagicMock()
  182. mock_create.return_value = retval
  183. def _fail_finalizer():
  184. assert False, "teardown should have been added to finalizer"
  185. def _capture_finalizer(func):
  186. nonlocal _finalizer
  187. _finalizer = func
  188. _finalizer = _fail_finalizer
  189. mock_request.addfinalizer = _capture_finalizer
  190. under_test = test_tools_fixtures._editor(mock_request, mock.MagicMock(), 'windows_editor')
  191. mock_create.assert_called_once()
  192. assert retval is under_test
  193. assert _finalizer is not None
  194. _finalizer()
  195. retval.stop.assert_called_once()
  196. @mock.patch('ly_test_tools._internal.pytest_plugin.test_tools_fixtures.get_fixture_argument')
  197. @mock.patch('ly_test_tools._internal.managers.ly_process_killer.detect_lumberyard_processes')
  198. @mock.patch('ly_test_tools._internal.managers.ly_process_killer.kill_processes', mock.MagicMock())
  199. def test_AutomaticProcessKiller_ProcessKillList_KillsDetectedProcesses(self, mock_detect_processes,
  200. mock_get_fixture_argument):
  201. mock_processes_list = ['foo', 'bar', 'foobar']
  202. mock_detected_processes = ['foo', 'bar']
  203. mock_detect_processes.return_value = mock_detected_processes
  204. mock_get_fixture_argument.return_value = mock_processes_list
  205. under_test = test_tools_fixtures._automatic_process_killer(mock_processes_list)
  206. under_test.detect_lumberyard_processes.assert_called_with(processes_list=mock_processes_list)
  207. under_test.kill_processes.assert_called_with(processes_list=mock_detected_processes)
  208. @mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog.start', mock.MagicMock())
  209. @mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog')
  210. def test_CrashLogWatchdog_Instantiates_CreatesWatchdog(self, under_test):
  211. mock_workspace = mock.MagicMock()
  212. mock_workspace.paths.crash_log.return_value = mock.MagicMock()
  213. mock_request = mock.MagicMock()
  214. mock_request.addfinalizer = mock.MagicMock()
  215. mock_raise_on_crash = mock.MagicMock()
  216. mock_watchdog = test_tools_fixtures._crash_log_watchdog(mock_request, mock_workspace, mock_raise_on_crash)
  217. under_test.assert_called_once_with(mock_workspace.paths.crash_log.return_value, raise_on_condition=mock_raise_on_crash)
  218. @mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog.start')
  219. def test_CrashLogWatchdog_Instantiates_StartsThread(self, under_test):
  220. mock_workspace = mock.MagicMock()
  221. mock_path = 'C:/foo'
  222. mock_workspace.paths.crash_log.return_value = mock_path
  223. mock_request = mock.MagicMock()
  224. mock_request.addfinalizer = mock.MagicMock()
  225. mock_raise_on_crash = mock.MagicMock()
  226. test_tools_fixtures._crash_log_watchdog(mock_request, mock_workspace, mock_raise_on_crash)
  227. under_test.assert_called_once()
  228. @mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog.start', mock.MagicMock())
  229. def test_CrashLogWatchdog_Instantiates_AddsTeardown(self):
  230. mock_workspace = mock.MagicMock()
  231. mock_path = 'C:/foo'
  232. mock_workspace.paths.crash_log.return_value = mock_path
  233. mock_request = mock.MagicMock()
  234. mock_request.addfinalizer = mock.MagicMock()
  235. mock_raise_on_crash = mock.MagicMock()
  236. mock_watchdog = test_tools_fixtures._crash_log_watchdog(mock_request, mock_workspace, mock_raise_on_crash)
  237. mock_request.addfinalizer.assert_called_once()
  238. @mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog.start', mock.MagicMock())
  239. @mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog.stop')
  240. def test_CrashLogWatchdog_Teardown_CallsStop(self, mock_stop):
  241. mock_workspace = mock.MagicMock()
  242. mock_path = 'C:/foo'
  243. mock_workspace.paths.crash_log.return_value = mock_path
  244. mock_request = mock.MagicMock()
  245. mock_request.addfinalizer = mock.MagicMock()
  246. mock_raise_condition = mock.MagicMock()
  247. mock_watchdog = test_tools_fixtures._crash_log_watchdog(mock_request, mock_workspace, mock_raise_condition)
  248. mock_request.addfinalizer.call_args[0][0]()
  249. mock_stop.assert_called_once()