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_fixtures.py

372 lines
16 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
Unit tests for ly_test_tools._internal.pytest_plugin.test_tools_fixtures
"""
import datetime
import os
import unittest.mock as mock
import pytest
import ly_test_tools._internal.pytest_plugin.test_tools_fixtures as test_tools_fixtures
pytestmark = pytest.mark.SUITE_smoke
class TestFixtures(object):
def test_AddOptionForLogs_MockParser_OptionAdded(self):
mock_parser = mock.MagicMock()
test_tools_fixtures.pytest_addoption(mock_parser)
mock_call = mock_parser.addoption.mock_calls[0]
"""
mock_call is the same as: call('--output_path', help='Set the folder name for the output logs.')
which results in a 3-tuple with (name, args, kwargs), so --output_path is in the list of args
"""
assert mock_call[1][0] == '--output-path'
def test_RecordSuiteProperty_MockRequestWithEmptyXml_PropertyAdded(self):
mock_request = mock.MagicMock()
mock_xml = mock.MagicMock()
mock_request.config._xml = mock_xml
func = test_tools_fixtures._record_suite_property(mock_request)
func('NewProperty', 'value')
mock_xml.add_global_property.assert_called_once_with('NewProperty', 'value')
def test_RecordSuiteProperty_MockRequestWithPropertyXml_PropertyUpdated(self):
mock_request = mock.MagicMock()
mock_xml = mock.MagicMock()
mock_xml.global_properties = [('ExistingProperty', 'old value')]
mock_request.config._xml = mock_xml
func = test_tools_fixtures._record_suite_property(mock_request)
func('ExistingProperty', 'new value')
assert mock_xml.global_properties[0] == ('ExistingProperty', 'new value')
mock_xml.add_global_property.assert_not_called()
@mock.patch('ly_test_tools._internal.pytest_plugin.test_tools_fixtures.logger')
def test_RecordSuiteProperty_MockRequestWithoutXml_NoOpReturned(self, mock_logger):
mock_request = mock.MagicMock()
mock_request.config._xml = None
func = test_tools_fixtures._record_suite_property(mock_request)
mock_logger.debug.assert_not_called()
func('SomeProperty', 'some value')
mock_logger.debug.assert_called_once()
@mock.patch('os.makedirs')
def test_LogsPath_CustomPathOption_CustomPathCreated(self, mock_makedirs):
expected = 'SomePath'
mock_config = mock.MagicMock()
mock_config.getoption.return_value = expected
actual = test_tools_fixtures._get_output_path(mock_config)
assert actual == expected
mock_makedirs.assert_called_once_with('SomePath', exist_ok=True)
@mock.patch('ly_test_tools._internal.pytest_plugin.test_tools_fixtures.datetime',
mock.Mock(now=lambda: datetime.datetime(2019, 10, 11)))
@mock.patch('os.getcwd')
@mock.patch('os.makedirs')
def test_LogsPath_NoPathOption_DefaultPathCreated(self, mock_makedirs, mock_getcwd):
mock_config = mock.MagicMock()
mock_cwd = 'C:/foo'
mock_getcwd.return_value = mock_cwd
mock_config.getoption.return_value = None
expected = os.path.join(mock_cwd,
'TestResults',
'2019-10-11T00-00-00-000000',
'pytest_results')
actual = test_tools_fixtures._get_output_path(mock_config)
assert actual == expected
mock_makedirs.assert_called_once_with(expected, exist_ok=True)
def test_RecordBuildName_MockRecordFunction_MockFunctionCalled(self):
mock_fn = mock.MagicMock()
func = test_tools_fixtures._record_build_name(mock_fn)
func('MyBuild')
mock_fn.assert_called_once_with('build', 'MyBuild')
@mock.patch('ly_test_tools._internal.pytest_plugin.test_tools_fixtures.datetime',
mock.Mock(now=lambda: datetime.datetime(2019, 10, 11)))
def test_RecordTimeStamp_MockRecordFunction_MockFunctionCalled(self):
mock_fn = mock.MagicMock()
test_tools_fixtures._record_test_timestamp(mock_fn)
mock_fn.assert_called_once_with('timestamp', '2019-10-11T00-00-00-000000')
@mock.patch('ly_test_tools._internal.pytest_plugin.test_tools_fixtures.datetime',
mock.Mock(now=lambda: datetime.datetime(2019, 10, 11)))
@mock.patch('socket.gethostname')
@mock.patch('getpass.getuser')
def test_RecordSuiteData_MockRecordFunction_MockFunctionCalled(self, mock_getuser, mock_gethostname):
mock_getuser.return_value = 'foo@bar.baz'
mock_gethostname.return_value = 'bar.baz'
mock_fn = mock.MagicMock()
test_tools_fixtures._record_suite_data(mock_fn)
expected_calls = [mock.call('timestamp', '2019-10-11T00-00-00-000000'),
mock.call('hostname', 'bar.baz'),
mock.call('username', 'foo@bar.baz')]
mock_fn.assert_has_calls(expected_calls)
@mock.patch("ly_test_tools._internal.log.py_logging_util.initialize_logging", mock.MagicMock())
@mock.patch("ly_test_tools.builtin.helpers.setup_builtin_workspace")
@mock.patch("ly_test_tools.builtin.helpers.create_builtin_workspace")
def test_Workspace_MockFixturesAndExecTeardown_ReturnWorkspaceRegisterTeardown(self, mock_create, mock_setup):
test_module = 'example.tests.test_system_example'
test_class = ('TestSystemExample.test_SystemTestExample_AllSupportedPlatforms_LaunchAutomatedTesting'
'[120-simple_jacklocomotion-AutomatedTesting-all-profile-win_x64_vs2017]')
test_method = 'test_SystemTestExample_AllSupportedPlatforms_LaunchAutomatedTesting'
artifact_folder_name = 'TheArtifactFolder'
artifact_path = "PathToArtifacts"
mock_request = mock.MagicMock()
mock_request.addfinalizer = mock.MagicMock()
mock_request.node.module.__name__ = test_module
mock_request.node.getmodpath.return_value = test_class
mock_request.node.originalname = test_method
mock_workspace = mock.MagicMock()
mock_workspace.artifact_manager.generate_folder_name.return_value = artifact_folder_name
mock_workspace.artifact_manager.artifact_path = artifact_path
mock_workspace.artifact_manager.gather_artifacts.return_value = os.path.join(artifact_path, 'foo.zip')
mock_create.return_value = mock_workspace
mock_property = mock.MagicMock()
mock_build_name = mock.MagicMock()
mock_logs = "foo"
under_test = test_tools_fixtures._workspace(
request=mock_request,
build_directory='foo',
project="",
record_property=mock_property,
record_build_name=mock_build_name,
output_path=mock_logs,
asset_processor_platform='ap_platform'
)
assert under_test is mock_workspace
# verify additional commands are called
mock_create.assert_called_once()
mock_setup.assert_called_once_with(under_test, artifact_folder_name, mock_request.session.testscollected)
# verify teardown was hooked but not called
mock_request.addfinalizer.assert_called_once()
mock_workspace.teardown.assert_not_called()
# execute teardown hook from recorded call, and verify called
mock_request.addfinalizer.call_args[0][0]()
mock_workspace.teardown.assert_called_once()
mock_workspace.artifact_manager.generate_folder_name.assert_called_with(
test_module.split('.')[-1], # 'example.tests.test_system_example' -> 'test_system_example'
test_class.split('.')[0], # 'TestSystemExample.test_SystemTestExample_...' -> 'TestSystemExample'
test_method # 'test_SystemTestExample_AllSupportedPlatforms_LaunchAutomatedTesting'
)
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
@mock.patch("ly_test_tools.launchers.launcher_helper.create_launcher")
def test_Launcher_MockHelper_Passthrough(self, mock_create):
retval = mock.MagicMock()
mock_create.return_value = retval
mock_workspace = mock.MagicMock()
mock_workspace.paths.waf.return_value = "dummy"
mock_workspace.paths.autoexec_file.return_value = "dummy2"
file_handler = mock.mock_open()
with mock.patch('ly_test_tools._internal.pytest_plugin.test_tools_fixtures.open', file_handler, create=True):
with open(mock_workspace.paths.autoexec_file(), 'w') as autoexec_file:
autoexec_file.write('map ' + 'level')
under_test = test_tools_fixtures._launcher(mock.MagicMock(), mock_workspace, 'windows', 'level')
mock_create.assert_called_once()
assert retval is under_test
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
@mock.patch("ly_test_tools.launchers.launcher_helper.create_launcher")
def test_Launcher_MockHelper_TeardownCalled(self, mock_create):
retval = mock.MagicMock()
retval.stop = mock.MagicMock()
mock_create.return_value = retval
mock_request = mock.MagicMock()
mock_workspace = mock.MagicMock()
mock_workspace.paths.waf.return_value = "dummy"
mock_workspace.paths.autoexec_file.return_value = "dummy2"
file_handler = mock.mock_open()
def _fail_finalizer():
assert False, "teardown should have been added to finalizer"
def _capture_finalizer(func):
nonlocal _finalizer
_finalizer = func
_finalizer = _fail_finalizer
mock_request.addfinalizer = _capture_finalizer
with mock.patch('ly_test_tools._internal.pytest_plugin.test_tools_fixtures.open', file_handler, create=True):
with open(mock_workspace.paths.autoexec_file(), 'w') as autoexec_file:
autoexec_file.write('map ' + 'level')
under_test = test_tools_fixtures._launcher(mock_request, mock_workspace, 'windows', 'level')
assert retval is under_test
assert _finalizer is not None
_finalizer()
retval.stop.assert_called_once()
@mock.patch("ly_test_tools.launchers.launcher_helper.create_dedicated_launcher")
def test_DedicatedLauncher_MockHelper_Passthrough(self, mock_create):
retval = mock.MagicMock()
mock_create.return_value = retval
under_test = test_tools_fixtures._dedicated_launcher(mock.MagicMock(), mock.MagicMock(), 'windows')
mock_create.assert_called_once()
assert retval is under_test
@mock.patch("ly_test_tools.launchers.launcher_helper.create_dedicated_launcher")
def test_DedicatedLauncher_MockHelper_TeardownCalled(self, mock_create):
retval = mock.MagicMock()
retval.stop = mock.MagicMock()
mock_request = mock.MagicMock()
mock_create.return_value = retval
def _fail_finalizer():
assert False, "teardown should have been added to finalizer"
def _capture_finalizer(func):
nonlocal _finalizer
_finalizer = func
_finalizer = _fail_finalizer
mock_request.addfinalizer = _capture_finalizer
under_test = test_tools_fixtures._dedicated_launcher(mock_request, mock.MagicMock(), 'windows')
mock_create.assert_called_once()
assert retval is under_test
assert _finalizer is not None
_finalizer()
retval.stop.assert_called_once()
@mock.patch("ly_test_tools.launchers.launcher_helper.create_editor")
def test_Editor_MockHelper_Passthrough(self, mock_create):
retval = mock.MagicMock()
mock_create.return_value = retval
under_test = test_tools_fixtures._editor(mock.MagicMock(), mock.MagicMock(), 'windows_editor')
mock_create.assert_called_once()
assert retval is under_test
@mock.patch("ly_test_tools.launchers.launcher_helper.create_editor")
def test_Editor_MockHelper_TeardownCalled(self, mock_create):
retval = mock.MagicMock()
retval.stop = mock.MagicMock()
mock_request = mock.MagicMock()
mock_create.return_value = retval
def _fail_finalizer():
assert False, "teardown should have been added to finalizer"
def _capture_finalizer(func):
nonlocal _finalizer
_finalizer = func
_finalizer = _fail_finalizer
mock_request.addfinalizer = _capture_finalizer
under_test = test_tools_fixtures._editor(mock_request, mock.MagicMock(), 'windows_editor')
mock_create.assert_called_once()
assert retval is under_test
assert _finalizer is not None
_finalizer()
retval.stop.assert_called_once()
@mock.patch('ly_test_tools._internal.pytest_plugin.test_tools_fixtures.get_fixture_argument')
@mock.patch('ly_test_tools._internal.managers.ly_process_killer.detect_lumberyard_processes')
@mock.patch('ly_test_tools._internal.managers.ly_process_killer.kill_processes', mock.MagicMock())
def test_AutomaticProcessKiller_ProcessKillList_KillsDetectedProcesses(self, mock_detect_processes,
mock_get_fixture_argument):
mock_processes_list = ['foo', 'bar', 'foobar']
mock_detected_processes = ['foo', 'bar']
mock_detect_processes.return_value = mock_detected_processes
mock_get_fixture_argument.return_value = mock_processes_list
under_test = test_tools_fixtures._automatic_process_killer(mock_processes_list)
under_test.detect_lumberyard_processes.assert_called_with(processes_list=mock_processes_list)
under_test.kill_processes.assert_called_with(processes_list=mock_detected_processes)
@mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog.start', mock.MagicMock())
@mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog')
def test_CrashLogWatchdog_Instantiates_CreatesWatchdog(self, under_test):
mock_workspace = mock.MagicMock()
mock_path = 'C:/foo'
mock_workspace.paths.project_log.return_value = mock_path
mock_request = mock.MagicMock()
mock_request.addfinalizer = mock.MagicMock()
mock_raise_on_crash = mock.MagicMock()
mock_watchdog = test_tools_fixtures._crash_log_watchdog(mock_request, mock_workspace, mock_raise_on_crash)
under_test.assert_called_once_with(os.path.join(mock_path, 'error.log'), raise_on_condition=mock_raise_on_crash)
@mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog.start')
def test_CrashLogWatchdog_Instantiates_StartsThread(self, under_test):
mock_workspace = mock.MagicMock()
mock_path = 'C:/foo'
mock_workspace.paths.project_log.return_value = mock_path
mock_request = mock.MagicMock()
mock_request.addfinalizer = mock.MagicMock()
mock_raise_on_crash = mock.MagicMock()
test_tools_fixtures._crash_log_watchdog(mock_request, mock_workspace, mock_raise_on_crash)
under_test.assert_called_once()
@mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog.start', mock.MagicMock())
def test_CrashLogWatchdog_Instantiates_AddsTeardown(self):
mock_workspace = mock.MagicMock()
mock_path = 'C:/foo'
mock_workspace.paths.project_log.return_value = mock_path
mock_request = mock.MagicMock()
mock_request.addfinalizer = mock.MagicMock()
mock_raise_on_crash = mock.MagicMock()
mock_watchdog = test_tools_fixtures._crash_log_watchdog(mock_request, mock_workspace, mock_raise_on_crash)
mock_request.addfinalizer.assert_called_once()
@mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog.start', mock.MagicMock())
@mock.patch('ly_test_tools.environment.watchdog.CrashLogWatchdog.stop')
def test_CrashLogWatchdog_Teardown_CallsStop(self, mock_stop):
mock_workspace = mock.MagicMock()
mock_path = 'C:/foo'
mock_workspace.paths.project_log.return_value = mock_path
mock_request = mock.MagicMock()
mock_request.addfinalizer = mock.MagicMock()
mock_raise_condition = mock.MagicMock()
mock_watchdog = test_tools_fixtures._crash_log_watchdog(mock_request, mock_workspace, mock_raise_condition)
mock_request.addfinalizer.call_args[0][0]()
mock_stop.assert_called_once()