Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
@@ -0,0 +1,239 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit Tests for ly_test_tools._internal.managers.abstract_resource_locator
"""
import os
import unittest.mock as mock
import pytest
import ly_test_tools._internal.managers.abstract_resource_locator as abstract_resource_locator
pytestmark = pytest.mark.SUITE_smoke
mock_initial_path = "mock_initial_path"
mock_engine_root = "mock_engine_root"
mock_dev_path = "mock_dev_path"
mock_build_directory = 'mock_build_directory'
mock_project = 'mock_project'
class TestFindEngineRoot(object):
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator.os.path.abspath')
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator.os.path.exists')
def test_FindEngineRoot_InitialPathExists_ReturnsTuple(self, mock_path_exists, mock_abspath):
mock_path_exists.return_value = True
mock_abspath.return_value = mock_engine_root
engine_root, dev_path = abstract_resource_locator._find_engine_root(mock_initial_path)
assert engine_root == mock_engine_root
assert dev_path == mock_initial_path
mock_path_exists.assert_called_once()
mock_abspath.assert_called_once()
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator.os.path.abspath')
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator.os.path.exists')
def test_FindEngineRoot_InitialPathDoesntExist_RaisesOSError(self, mock_path_exists, mock_abspath):
mock_path_exists.return_value = False
mock_abspath.return_value = mock_engine_root
with pytest.raises(OSError):
abstract_resource_locator._find_engine_root(mock_initial_path)
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator.os.path.abspath',
mock.MagicMock(return_value=mock_initial_path))
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator._find_engine_root',
mock.MagicMock(return_value=(mock_engine_root, mock_dev_path)))
class TestAbstractResourceLocator(object):
def test_Init_HasEngineRoot_SetsAttrs(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
assert mock_abstract_resource_locator._build_directory == mock_build_directory
assert mock_abstract_resource_locator._engine_root == mock_engine_root
assert mock_abstract_resource_locator._dev_path == mock_dev_path
assert mock_abstract_resource_locator._project == mock_project
def test_BasePath_IsCalled_ReturnsBasePath(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
assert mock_abstract_resource_locator.engine_root() == mock_engine_root
def test_Dev_IsCalled_ReturnsDevPath(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
assert mock_abstract_resource_locator.dev() == mock_dev_path
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator.os.path.isfile')
def test_3rdParty_IsCalledHasTxtFile_Returns3rdPartyPath(self, mock_isfile):
mock_isfile.return_value = True
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_abstract_resource_locator._engine_root, '3rdParty')
assert mock_abstract_resource_locator.third_party() == expected_path
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator.os.path.isfile')
def test_3rdParty_IsCalledNoTxtFile_RaisesFileNotFoundError(self, mock_isfile):
mock_isfile.return_value = False
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
with pytest.raises(FileNotFoundError):
mock_abstract_resource_locator.third_party()
mock_isfile.assert_called_once()
def test_BuildDirectory_IsCalled_ReturnsBuildDirectoryPath(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
assert mock_abstract_resource_locator.build_directory() == mock_build_directory
def test_Project_IsCalled_ReturnsProjectPath(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_abstract_resource_locator.dev(), mock_project)
assert mock_abstract_resource_locator.project() == expected_path
def test_AssetProcessor_IsCalled_ReturnsAssetProcessorPath(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_abstract_resource_locator.build_directory(), 'AssetProcessor')
assert mock_abstract_resource_locator.asset_processor() == expected_path
def test_AssetProcessorBatch_IsCalled_ReturnsAssetProcessorBatchPath(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_abstract_resource_locator.build_directory(), 'AssetProcessorBatch')
assert mock_abstract_resource_locator.asset_processor_batch() == expected_path
def test_Editor_IsCalled_ReturnsEditorPath(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_abstract_resource_locator.build_directory(), 'Editor')
assert mock_abstract_resource_locator.editor() == expected_path
def test_Cache_IsCalled_ReturnsCachePath(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_abstract_resource_locator.dev(), 'Cache')
assert mock_abstract_resource_locator.cache() == expected_path
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator.os.path.exists')
def test_GetShaderCompilerPath_IsCalledExecutablePathExists_ReturnsGetShaderCompilerPath(self, mock_path_exists):
mock_path_exists.return_value = True
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_abstract_resource_locator.build_directory(), 'CrySCompileServer')
assert mock_abstract_resource_locator.get_shader_compiler_path() == expected_path
def test_GetShaderCompilerDir_IsCalled_ReturnsShaderCompilerDir(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = mock_abstract_resource_locator.build_directory()
assert mock_build_directory == expected_path
def test_ShaderCompilerConfigFile_IsCalled_ReturnsShaderCompilerConfigPath(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_abstract_resource_locator.build_directory(), 'config.ini')
assert mock_abstract_resource_locator.shader_compiler_config_file() == expected_path
def test_ShaderCache_IsCalled_ReturnsShaderCacheDir(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_abstract_resource_locator.build_directory(), 'Cache')
assert mock_abstract_resource_locator.shader_cache() == expected_path
def test_BootstrapConfigFile_IsCalled_ReturnBootstrapConfigFilePath(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_abstract_resource_locator.dev(), 'bootstrap.cfg')
assert mock_abstract_resource_locator.bootstrap_config_file() == expected_path
def test_AssetProcessorConfigFile_IsCalled_ReturnsAssetProcessorConfigFilePath(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_abstract_resource_locator.dev(), 'AssetProcessorPlatformConfig.ini')
assert mock_abstract_resource_locator.asset_processor_config_file() == expected_path
def test_AutoexecFile_IsCalled_ReturnsAutoexecFilePath(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_abstract_resource_locator.dev(),
mock_abstract_resource_locator._project,
'autoexec.cfg')
assert mock_abstract_resource_locator.autoexec_file() == expected_path
def test_TestResults_IsCalled_TestResultsPath(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_abstract_resource_locator.dev(), 'TestResults')
assert mock_abstract_resource_locator.test_results() == expected_path
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator.os.path.expanduser')
def test_DevicesFile_IsCalled_ReturnsDevicesFilePath(self, mock_expanduser):
mock_expanded_path = 'C:/somepath/'
mock_expanduser.return_value = mock_expanded_path
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
expected_path = os.path.join(mock_expanded_path, 'ly_test_tools', 'devices.ini')
assert mock_abstract_resource_locator.devices_file() == expected_path
def test_PlatformConfigFile_NotImplemented_RaisesNotImplementedError(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
with pytest.raises(NotImplementedError):
mock_abstract_resource_locator.platform_config_file()
def test_PlatformCache_NotImplemented_RaisesNotImplementedError(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
with pytest.raises(NotImplementedError):
mock_abstract_resource_locator.platform_cache()
def test_ProjectLog_NotImplemented_RaisesNotImplementedError(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
with pytest.raises(NotImplementedError):
mock_abstract_resource_locator.project_log()
def test_ProjectScreenshots_NotImplemented_RaisesNotImplementedError(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
with pytest.raises(NotImplementedError):
mock_abstract_resource_locator.project_screenshots()
def test_EditorLog_NotImplemented_RaisesNotImplementedError(self):
mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator(
mock_build_directory, mock_project)
with pytest.raises(NotImplementedError):
mock_abstract_resource_locator.editor_log()
@@ -0,0 +1,321 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit Tests for WorkspaceManager class
"""
import datetime
import os
import stat
import unittest.mock as mock
import unittest
import os
import pytest
import ly_test_tools._internal.managers.artifact_manager
pytestmark = pytest.mark.SUITE_smoke
TIMESTAMP_FORMAT = '%Y-%m-%dT%H-%M-%S-%f'
DATE = datetime.datetime.now().strftime(TIMESTAMP_FORMAT)
ROOT_LOG_FOLDER = os.path.join("TestResults", DATE, "pytest_results")
@mock.patch('os.makedirs', mock.MagicMock())
class TestSetTestName(unittest.TestCase):
def setUp(self):
self.mock_root = ROOT_LOG_FOLDER
self.mock_artifact_manager = ly_test_tools._internal.managers.artifact_manager.ArtifactManager(
self.mock_root)
@mock.patch('os.path.exists', mock.MagicMock(return_value=False))
def test_Init_NoPathExists_CreatesPathSetsAttributes(self):
create_amount = 1
updated_path = "{}".format(self.mock_artifact_manager.artifact_path, create_amount)
assert self.mock_artifact_manager.artifact_path == self.mock_root, (
'artifact_path does not match self.mock_root')
assert self.mock_artifact_manager.dest_path == updated_path, (
'dest_path does not match updated_path')
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_Init_PathExists_NoPathCreatedSetsAttributes(self):
assert self.mock_artifact_manager.artifact_path == self.mock_root, (
'artifact_path does not match self.mock_root')
assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path, (
'dest_path does not match artifact_path')
@mock.patch('os.path.exists', mock.MagicMock(return_value=False))
def test_SetTestNameAmount_ValidNameNoPathExists_CreatesPathSetsAttributes(self):
create_amount = 5
test_name = 'dummy'
updated_path = "{}_1".format(os.path.join(self.mock_artifact_manager.artifact_path,
test_name))
self.mock_artifact_manager.set_test_name(test_name, create_amount)
assert self.mock_artifact_manager.dest_path == updated_path, (
'dest_path does not match updated_path')
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_SetTestNameAmount_ValidNamePathExists_NoPathCreatedSetsAttributes(self):
test_name = 'dummy'
create_amount = 5 # Ignored because the path already exists.
updated_path = "{}".format(os.path.join(self.mock_artifact_manager.artifact_path, test_name),
create_amount)
self.mock_artifact_manager.set_test_name(test_name, create_amount)
assert self.mock_artifact_manager.dest_path == updated_path, (
'dest_path does not match updated_path')
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
class TestSaveArtifact(unittest.TestCase):
def setUp(self):
self.mock_root = ROOT_LOG_FOLDER
self.mock_artifact_manager = ly_test_tools._internal.managers.artifact_manager.ArtifactManager(self.mock_root)
@mock.patch('shutil.copytree')
@mock.patch('os.path.isdir')
@mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
def test_SaveArtifact_ArtifactNameIsNotNone_CopyTreeCalledCorrectly(self, mock_reducer, mock_path_isdir,
mock_copy_tree):
test_name = 'dummy'
mock_artifact_name = 'mock_artifact_name'
updated_path = "{}".format(os.path.join(self.mock_artifact_manager.artifact_path,
test_name))
mock_path_isdir.return_value = True
mock_copy_tree.return_value = True
mock_reducer.return_value = mock_artifact_name[:-5]
self.mock_artifact_manager.set_test_name(test_name)
self.mock_artifact_manager.save_artifact(updated_path, mock_artifact_name)
assert self.mock_artifact_manager.dest_path == updated_path, (
'dest_path does not match updated_path')
mock_copy_tree.assert_called_once_with(
updated_path, os.path.join(updated_path, mock_artifact_name[:-5]))
mock_reducer.assert_called_once_with(file_name=mock_artifact_name, max_length=25)
@mock.patch('shutil.copytree')
@mock.patch('os.path.isdir')
@mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
def test_SaveArtifact_ArtifactNameIsNone_CopyTreeCalledCorrectly(self, mock_reducer, mock_path_isdir,
mock_copy_tree):
mock_artifact_name = None
mock_path_isdir.return_value = True
mock_copy_tree.return_value = True
self.mock_artifact_manager.save_artifact(self.mock_artifact_manager.artifact_path, mock_artifact_name)
assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path, (
'dest_path does not match self.mock_artifact_manager.artifact_path')
mock_copy_tree.assert_called_once_with(
self.mock_artifact_manager.artifact_path,
os.path.join(self.mock_artifact_manager.artifact_path, 'pytest_results'))
mock_reducer.assert_not_called()
@mock.patch('os.chmod', mock.MagicMock())
@mock.patch('shutil.copy')
@mock.patch('os.path.isdir')
@mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
def test_SaveArtifact_ArtifactNameIsNotNone_CopyCalledCorrectly(self, mock_reducer, mock_path_isdir,
mock_copy):
mock_artifact_name = 'mock_artifact_name'
mock_path_isdir.return_value = False
mock_reducer.return_value = mock_artifact_name[:-5]
mock_copy.return_value = True
self.mock_artifact_manager.save_artifact(self.mock_artifact_manager.artifact_path, mock_artifact_name)
assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path, (
'dest_path does not match self.mock_artifact_manager.artifact_path')
mock_copy.assert_called_once_with(
self.mock_artifact_manager.artifact_path,
os.path.join(self.mock_artifact_manager.artifact_path, mock_artifact_name[:-5]))
mock_reducer.assert_called_once_with(file_name=mock_artifact_name, max_length=25)
@mock.patch('os.chmod', mock.MagicMock())
@mock.patch('shutil.copy')
@mock.patch('os.path.isdir')
@mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
def test_SaveArtifact_ArtifactNameIsNone_CopyCalledCorrectly(self, mock_reducer, mock_path_isdir,
mock_copy):
mock_artifact_name = None
mock_path_isdir.return_value = False
mock_copy.return_value = True
self.mock_artifact_manager.save_artifact(self.mock_artifact_manager.artifact_path, mock_artifact_name)
assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path, (
'dest_path does not match self.mock_artifact_manager.artifact_path')
mock_copy.assert_called_once_with(
self.mock_artifact_manager.artifact_path,
os.path.join(self.mock_artifact_manager.artifact_path, 'pytest_results'))
mock_reducer.assert_not_called()
@mock.patch('shutil.copy', mock.MagicMock())
@mock.patch('os.chmod')
@mock.patch('os.path.isdir')
@mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
def test_SaveArtifact_ArtifactNameIsNotNone_ChmodCalledCorrectly(self, mock_reducer, mock_path_isdir, mock_chmod):
mock_artifact_name = 'mock_artifact_name'
mock_path_isdir.return_value = False
mock_reducer.return_value = mock_artifact_name[:-5]
self.mock_artifact_manager.save_artifact(self.mock_artifact_manager.artifact_path, mock_artifact_name)
mock_chmod.assert_called_once_with(
os.path.join(self.mock_artifact_manager.artifact_path, mock_artifact_name[:-5]),
stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC)
assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path, (
'dest_path does not match self.mock_artifact_manager.artifact_path')
mock_reducer.assert_called_once_with(file_name=mock_artifact_name, max_length=25)
@mock.patch('shutil.copy', mock.MagicMock())
@mock.patch('os.chmod')
@mock.patch('os.path.isdir')
@mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
def test_SaveArtifact_ArtifactNameIsNone_ChmodCalledCorrectly(self, mock_reducer, mock_path_isdir, mock_chmod):
mock_artifact_name = None
mock_path_isdir.return_value = False
self.mock_artifact_manager.save_artifact(self.mock_artifact_manager.artifact_path, mock_artifact_name)
mock_chmod.assert_called_once_with(
os.path.join(self.mock_artifact_manager.artifact_path, 'pytest_results'),
stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC)
assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path, (
'dest_path does not match self.mock_artifact_manager.artifact_path')
mock_reducer.assert_not_called()
@mock.patch('shutil.copy', mock.MagicMock())
@mock.patch('os.chmod', mock.MagicMock())
@mock.patch('ly_test_tools._internal.managers.artifact_manager.ArtifactManager._get_collision_handled_filename')
@mock.patch('os.path.isdir')
def test_SaveArtifact_DestinationCollides_CallsGetCollisionHandledFilename(self, mock_path_isdir, under_test):
mock_path_isdir.return_value = False
self.mock_artifact_manager.save_artifact(self.mock_artifact_manager.artifact_path)
under_test.assert_called_once()
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
class TestGenerateArtifactFileName(unittest.TestCase):
def setUp(self):
self.mock_root = ROOT_LOG_FOLDER
self.mock_artifact_manager = ly_test_tools._internal.managers.artifact_manager.ArtifactManager(self.mock_root)
@mock.patch('os.path.isdir')
@mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
def test_GenerateFileName_HasArtifactName_ReturnsFilePath(self, mock_reducer, mock_path_isdir):
mock_artifact_name = 'mock_artifact_name'
mock_path_isdir.return_value = True
mock_artifact_file = self.mock_artifact_manager.generate_artifact_file_name(mock_artifact_name)
assert self.mock_artifact_manager.dest_path == self.mock_artifact_manager.artifact_path, (
'dest_path does not match self.mock_artifact_manager.artifact_path')
assert mock_artifact_file == os.path.join(self.mock_artifact_manager.artifact_path, mock_artifact_name), (
'mock_artifact_file does not match expected value from generate_artifact_file_name()')
mock_reducer.assert_not_called()
@mock.patch('os.path.isdir')
@mock.patch('ly_test_tools.environment.file_system.reduce_file_name_length')
def test_GenerateFileName_ArtifactNameIsNone_ReturnsFilePath(self, mock_reducer, mock_path_isdir):
mock_artifact_name = None
mock_path_isdir.return_value = True
with pytest.raises(ValueError):
self.mock_artifact_manager.generate_artifact_file_name(mock_artifact_name)
mock_reducer.assert_not_called()
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
class TestGatherArtifacts(unittest.TestCase):
def setUp(self):
self.mock_root = ROOT_LOG_FOLDER
self.mock_artifact_manager = ly_test_tools._internal.managers.artifact_manager.ArtifactManager(self.mock_root)
@mock.patch('shutil.make_archive')
def test_TestGatherArtifacts_TestNameIsNone_MakeArchiveCalled(self, mock_make_archive):
mock_destination = 'mock_destination'
self.mock_artifact_manager.gather_artifacts(mock_destination)
mock_make_archive.assert_called_once_with(mock_destination, 'zip', self.mock_artifact_manager.artifact_path)
@mock.patch('ly_test_tools.environment.file_system.sanitize_file_name')
@mock.patch('shutil.make_archive')
def test_TestGatherArtifacts_TestNameIsNotNone_MakeArchiveCalled(self, mock_make_archive, mock_sanitize_file_name):
test_name = 'dummy'
mock_destination = 'mock_destination'
mock_sanitize_file_name.return_value = test_name
self.mock_artifact_manager.set_test_name(test_name)
self.mock_artifact_manager.gather_artifacts(mock_destination)
mock_make_archive.assert_called_once_with(
mock_destination, 'zip',
os.path.join(self.mock_artifact_manager.artifact_path, test_name))
class TestGetCollisionHandledFilename(unittest.TestCase):
def setUp(self):
self.mock_root = ROOT_LOG_FOLDER
self.mock_artifact_manager = ly_test_tools._internal.managers.artifact_manager.ArtifactManager(self.mock_root)
def test_GetCollisionHandledFilename_AmountOne_ReturnsParam(self):
mock_file_path = 'foo'
amount = 1
under_test = self.mock_artifact_manager._get_collision_handled_filename(mock_file_path, amount)
assert under_test == mock_file_path
@mock.patch('os.path.exists', mock.MagicMock())
def test_GetCollisionHandledFilename_HasExt_RenameWithExtProperly(self):
mock_file_path = 'foo'
mock_file_ext = '.ext'
mock_file_with_ext = mock_file_path + mock_file_ext
amount = 2
under_test = self.mock_artifact_manager._get_collision_handled_filename(mock_file_with_ext, amount)
assert under_test == f'{mock_file_path}_{amount-1}{mock_file_ext}'
@mock.patch('os.path.exists', mock.MagicMock())
def test_GetCollisionHandledFilename_HasNoExt_RenameWithoutExtProperly(self):
mock_file_path = 'foo'
amount = 2
under_test = self.mock_artifact_manager._get_collision_handled_filename(mock_file_path, amount)
assert under_test == f'{mock_file_path}_{amount-1}'
@mock.patch('os.path.exists')
def test_GetCollisionHandledFilename_HasLargeAmountAndNotPathExists_EndsLoopEarly(self, mock_path_exists):
mock_file_path = 'foo'
amount = 99
mock_path_exists.side_effect = [True, True, False]
under_test = self.mock_artifact_manager._get_collision_handled_filename(mock_file_path, amount)
# The integer should be the index of False in mock_path_exists
assert under_test == f'{mock_file_path}_{3}'
@mock.patch('os.path.exists')
def test_GetCollisionHandledFilename_HasLargeAmountAndCollides_ReachesMaxAmount(self, mock_path_exists):
mock_file_path = 'foo'
amount = 99
mock_path_exists.return_value = True
under_test = self.mock_artifact_manager._get_collision_handled_filename(mock_file_path, amount)
assert under_test == f'{mock_file_path}_{amount-1}'
@@ -0,0 +1,216 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit tests for ly_test_tools.lumberyard.asset_processor
"""
import datetime
import unittest.mock as mock
import os
import pytest
import ly_test_tools._internal.managers.workspace
import ly_test_tools._internal.managers.abstract_resource_locator
import ly_test_tools.lumberyard.asset_processor
pytestmark = pytest.mark.SUITE_smoke
mock_initial_path = "mock_initial_path"
mock_engine_root = "mock_engine_root"
mock_dev_path = "mock_dev_path"
mock_build_directory = 'mock_build_directory'
mock_project = 'mock_project'
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator.os.path.abspath',
mock.MagicMock(return_value=mock_initial_path))
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator._find_engine_root',
mock.MagicMock(return_value=(mock_engine_root, mock_dev_path)))
@mock.patch('ly_test_tools.lumberyard.asset_processor.logger.warning', mock.MagicMock())
class TestAssetProcessor(object):
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
def test_Init_DefaultParams_MembersSetCorrectly(self, mock_workspace):
under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace)
assert under_test._workspace == mock_workspace
assert under_test._port is not None
assert under_test._ap_proc is None
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@mock.patch('subprocess.Popen')
@mock.patch('ly_test_tools.lumberyard.asset_processor.AssetProcessor.connect_socket')
@mock.patch('ly_test_tools.lumberyard.asset_processor.ASSET_PROCESSOR_PLATFORM_MAP', {'foo': 'bar'})
def test_Start_NoneRunning_ProcStarted(self, mock_connect, mock_popen, mock_workspace):
mock_ap_path = 'mock_ap_path'
mock_workspace.asset_processor_platform = 'foo'
mock_workspace.paths.asset_processor.return_value = mock_ap_path
mock_workspace.project = 'AutomatedTesting'
under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace)
under_test.enable_asset_processor_platform = mock.MagicMock()
under_test.wait_for_idle = mock.MagicMock()
under_test.start(connect_to_ap=True)
assert under_test._ap_proc is not None
mock_popen.assert_called_once_with([mock_ap_path, '--zeroAnalysisMode', '--gamefolder', 'AutomatedTesting',
'--acceptInput', '--platforms', 'bar'], cwd=os.path.dirname(mock_ap_path))
mock_connect.assert_called()
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@mock.patch('subprocess.Popen')
@mock.patch('os.path.basename', mock.MagicMock(return_value=""))
@mock.patch('os.path.dirname', mock.MagicMock(return_value=""))
@mock.patch('ly_test_tools.environment.process_utils.kill_processes_with_name_not_started_from', mock.MagicMock(return_value=None))
@mock.patch('ly_test_tools.environment.process_utils.process_exists', mock.MagicMock(return_value=True))
@mock.patch('socket.socket.connect')
def test_Start_ProcAlreadyRunning_ProcNotChanged(self, mock_connect, mock_popen, mock_workspace):
under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace)
under_test.process_exists = mock.MagicMock(return_value=True)
under_test.asset_processor_platform = mock.MagicMock(return_value=ly_test_tools.HOST_OS_PLATFORM)
mock_proc = mock.MagicMock()
under_test._ap_proc = mock_proc
under_test.start(connect_to_ap=True)
assert under_test._ap_proc == mock_proc
mock_popen.assert_not_called()
mock_connect.assert_not_called()
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@mock.patch('ly_test_tools.lumberyard.asset_processor.waiter.wait_for')
def test_Stop_ProcAlreadyRunning_ProcStopped(self, mock_waiter, mock_workspace):
under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace)
under_test.get_process_list = mock.MagicMock(return_value=[mock.MagicMock()])
under_test._control_connection = mock.MagicMock()
under_test.get_pid = mock.MagicMock(return_value=0)
under_test.send_quit = mock.MagicMock(return_value=True)
mock_proc = mock.MagicMock()
under_test._ap_proc = mock_proc
under_test.stop()
under_test.send_quit.assert_called_once()
mock_waiter.assert_called_once()
assert under_test._ap_proc is None
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@mock.patch('subprocess.run')
def test_BatchProcess_NoFastscanBatchCompletes_Success(self, mock_run, mock_workspace):
under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace)
mock_workspace.project = None
apb_path = mock_workspace.paths.asset_processor_batch()
mock_run.return_value.returncode = 0
result, _ = under_test.batch_process(1, False)
assert result
mock_run.assert_called_once_with([apb_path], close_fds=True, capture_output=False,
timeout=1)
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@mock.patch('subprocess.run')
def test_BatchProcess_FastscanBatchCompletes_Success(self, mock_run, mock_workspace):
under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace)
mock_workspace.project = 'AutomatedTesting'
apb_path = mock_workspace.paths.asset_processor_batch()
mock_run.return_value.returncode = 0
result = under_test.batch_process(1, True)
assert result
mock_run.assert_called_once_with([apb_path, '--zeroAnalysisMode', '--gamefolder', 'AutomatedTesting'],
close_fds=True, capture_output=False,
timeout=1)
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@mock.patch('subprocess.run')
def test_BatchProcess_ReturnCodeFail_Failure(self, mock_run, mock_workspace):
under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace)
mock_workspace.project = None
apb_path = mock_workspace.paths.asset_processor_batch()
mock_run.return_value.returncode = 1
result, _ = under_test.batch_process(None, False)
assert not result
mock_run.assert_called_once_with([apb_path], close_fds=True, capture_output=False, timeout=28800.0)
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@mock.patch('os.path.isfile')
@mock.patch('ly_test_tools.lumberyard.asset_processor.file_system.unlock_file')
def test_EnableAssetProcessorPlatform_PlatformInConfig_ConfigUpdated(self, mock_unlock, mock_isfile,
mock_workspace):
mock_isfile.return_value = True
under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace)
apconfig_path = mock_workspace.paths.asset_processor_config_file()
mock_config_content = '[Platforms]\n;foo\n;bar\n[Other]\nsomething\n'
mock_open_config = mock.mock_open(read_data=mock_config_content)
patcher = mock.patch('builtins.open', mock_open_config)
patcher.start()
under_test.enable_asset_processor_platform('foo')
mock_unlock.assert_called_once_with(apconfig_path)
mock_open_config.assert_called_once_with(apconfig_path, 'r+')
file_handle = mock_open_config()
file_handle.writelines.assert_called_once_with(['[Platforms]\n', 'foo\n', ';bar\n', '[Other]\n', 'something\n'])
patcher.stop()
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@mock.patch('os.path.isfile')
@mock.patch('ly_test_tools.lumberyard.asset_processor.file_system.unlock_file')
def test_EnableAssetProcessorPlatform_FileDoesNotExist_ErrorRaised(self, mock_unlock, mock_isfile, mock_workspace):
mock_isfile.return_value = False
under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace)
apconfig_path = mock_workspace.paths.asset_processor_config_file()
with pytest.raises(IOError):
under_test.enable_asset_processor_platform('foo')
mock_isfile.assert_called_once_with(apconfig_path)
mock_unlock.assert_not_called()
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
def test_BackupAPSettings_Called_CallsBackupAPSettings(self, mock_workspace):
mock_temp_path = 'foo_path'
mock_asset_processor = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace)
mock_workspace.settings.get_temp_path.return_value = mock_temp_path
mock_asset_processor.backup_ap_settings()
mock_workspace.settings.backup_asset_processor_settings.assert_called_with(mock_temp_path)
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
def test_RestoreAPSettings_Called_CallsRestoreAPSettings(self, mock_workspace):
mock_temp_path = 'foo_path'
mock_asset_processor = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace)
mock_workspace.settings.get_temp_path.return_value = mock_temp_path
mock_asset_processor.restore_ap_settings()
mock_workspace.settings.restore_asset_processor_settings.assert_called_with(mock_temp_path)
@mock.patch('ly_test_tools.lumberyard.asset_processor.AssetProcessor.restore_ap_settings')
@mock.patch('ly_test_tools.lumberyard.asset_processor.AssetProcessor.stop')
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
def test_Teardown_Called_CallsRestoreAPSettingsAndStop(self, mock_workspace, mock_stop, mock_restore_ap):
mock_asset_processor = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace)
mock_asset_processor.teardown()
mock_stop.assert_called()
mock_restore_ap.assert_called()
@@ -0,0 +1,149 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit tests for ly_test_tools.builtin.helpers functions.
"""
import unittest.mock as mock
import pytest
import ly_test_tools.builtin.helpers
import ly_test_tools._internal.managers.abstract_resource_locator
import ly_test_tools._internal.managers.workspace
import ly_test_tools._internal.managers.platforms.mac
import ly_test_tools._internal.managers.platforms.windows
from ly_test_tools import MAC, WINDOWS
pytestmark = pytest.mark.SUITE_smoke
class MockedAbstractResourceLocator(ly_test_tools._internal.managers.abstract_resource_locator.AbstractResourceLocator):
def __init__(self, build_directory, project):
super(MockedAbstractResourceLocator, self).__init__(
build_directory=build_directory,
project=project,
)
class MockedWorkspaceManager(ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager):
def __init__(
self, resource_locator, project, tmp_path, output_path
):
super(MockedWorkspaceManager, self).__init__(
resource_locator=resource_locator,
project=project,
tmp_path=tmp_path,
output_path=output_path
)
@mock.patch(
'ly_test_tools._internal.managers.abstract_resource_locator.AbstractResourceLocator',
mock.MagicMock(return_value=MockedAbstractResourceLocator)
)
@mock.patch('os.remove', mock.MagicMock(return_value=True))
class TestBuiltinHelpers(object):
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager',
mock.MagicMock(return_value=MockedWorkspaceManager))
@mock.patch('ly_test_tools.builtin.helpers.WINDOWS', True)
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_CreateBuiltinWorkspace_WindowsOS_ReturnsWindowsWorkspaceManager(self):
expected_workspace = ly_test_tools._internal.managers.platforms.windows.WindowsWorkspaceManager
under_test = ly_test_tools.builtin.helpers.create_builtin_workspace(
build_directory='build_directory',
project='mock_project',
tmp_path='mock_tmp_path',
output_path='mock_output_path',
)
assert type(under_test) == expected_workspace
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager',
mock.MagicMock(return_value=MockedWorkspaceManager))
@mock.patch('ly_test_tools.builtin.helpers.MAC', True)
@mock.patch('ly_test_tools.builtin.helpers.WINDOWS', False)
def test_CreateBuiltinWorkspace_MacOS_ReturnsMacWorkspaceManager(self):
expected_workspace = ly_test_tools._internal.managers.platforms.mac.MacWorkspaceManager
under_test = ly_test_tools.builtin.helpers.create_builtin_workspace(
build_directory='build_directory',
project='mock_project',
tmp_path='mock_tmp_path',
output_path='mock_output_path',
)
assert type(under_test) == expected_workspace
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager',
mock.MagicMock(return_value=MockedWorkspaceManager))
@mock.patch('ly_test_tools._internal.pytest_plugin.build_directory', None)
def test_CreateBuiltinWorkspace_InvalidPlatform_RaisesValueError(self):
with pytest.raises(ValueError):
ly_test_tools.builtin.helpers.create_builtin_workspace(
build_directory=None,
project='mock_project',
tmp_path='mock_tmp_path',
output_path='mock_output_path',
)
@mock.patch('os.path.abspath', mock.MagicMock(return_value='mock_base_dir'))
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_FindEngineRoot_HasRootFile_ReturnsTuple(self):
under_test = ly_test_tools._internal.managers.abstract_resource_locator._find_engine_root(
initial_path='mock_dev_dir')
assert under_test == ('mock_base_dir', 'mock_dev_dir')
@mock.patch('os.path.abspath', mock.MagicMock(return_value='mock_base_dir'))
@mock.patch('os.path.exists', mock.MagicMock(return_value=False))
def test_FindEngineRoot_NoRootFile_RaisesOSError(self):
with pytest.raises(OSError):
ly_test_tools._internal.managers.abstract_resource_locator._find_engine_root(
initial_path='mock_dev_dir')
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager.setup')
@mock.patch('ly_test_tools._internal.managers.artifact_manager.NullArtifactManager', mock.MagicMock())
@mock.patch('ly_test_tools.builtin.helpers.setup_bootstrap_project', mock.MagicMock(return_value=None))
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_SetupBuiltinWorkspace_ValidWorkspaceSetup_ReturnsWorkspaceObject(self, mock_setup):
mock_test_name = 'mock_test_name'
mock_test_amount = 10
mock_workspace = ly_test_tools.builtin.helpers.create_builtin_workspace(
build_directory='build_directory',
project='mock_project',
tmp_path='mock_tmp_path',
output_path='mock_output_path',
)
under_test = ly_test_tools.builtin.helpers.setup_builtin_workspace(
mock_workspace, mock_test_name, mock_test_amount)
assert under_test == mock_workspace
assert mock_setup.call_count == 1
mock_workspace.artifact_manager.set_test_name.assert_called_with(
test_name=mock_test_name, amount=mock_test_amount)
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager.teardown')
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_TeardownBuiltinWorkspace_ValidWorkspaceSetup_ReturnsWorkspaceObject(self, mock_teardown):
mock_workspace = ly_test_tools.builtin.helpers.create_builtin_workspace(
build_directory='build_directory',
project='mock_project',
tmp_path='mock_tmp_path',
output_path='mock_output_path',
)
under_test = ly_test_tools.builtin.helpers.teardown_builtin_workspace(mock_workspace)
assert under_test == mock_workspace
assert mock_teardown.call_count == 1
@@ -0,0 +1,139 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit tests for ly_test_tools._internal.pytest_plugin.case_id
"""
import unittest.mock as mock
import pytest
import ly_test_tools._internal.pytest_plugin.case_id as case_id
pytestmark = pytest.mark.SUITE_smoke
class TestCaseId(object):
def test_Configure_MockConfig_ValuesAdded(self):
mock_config = mock.MagicMock()
case_id.pytest_configure(mock_config)
mock_config.addinivalue_line.assert_called_once()
def test_AddOption_MockParser_OptionsAdded(self):
mock_parser = mock.MagicMock()
case_id.pytest_addoption(mock_parser)
mock_parser.addoption.assert_called_once()
def test_MakeReportImpl_MarkerSimpleItem_TestCaseIdAdded(self):
mock_report = mock.MagicMock()
mock_report.when = 'call'
mock_item = mock.MagicMock()
mock_marker = mock.MagicMock()
test_case = 123
test_case_list = [str(test_case)]
mock_marker.args = test_case_list
mock_item.get_marker.return_value = mock_marker
mock_xml = mock.MagicMock()
mock_item.config._xml = mock_xml
mock_node = mock.MagicMock()
mock_xml.node_reporter.return_value = mock_node
case_id._pytest_runtest_makereport_imp(mock_report, mock_item)
mock_node.add_property.assert_called_once_with('test_case_id', test_case)
def test_MakeReportImpl_ClosestMarkerSimpleItem_TestCaseIdAdded(self):
mock_report = mock.MagicMock()
mock_report.when = 'call'
mock_item = mock.MagicMock()
mock_marker = mock.MagicMock()
test_case = 123
test_case_list = [str(test_case)]
mock_marker.args = test_case_list
mock_item.get_marker.side_effect = AttributeError()
mock_item.get_closest_marker.return_value = mock_marker
mock_xml = mock.MagicMock()
mock_item.config._xml = mock_xml
mock_node = mock.MagicMock()
mock_xml.node_reporter.return_value = mock_node
case_id._pytest_runtest_makereport_imp(mock_report, mock_item)
mock_item.get_closest_marker.assert_called_once()
mock_node.add_property.assert_called_once_with('test_case_id', test_case)
@mock.patch('ly_test_tools._internal.pytest_plugin.case_id.log')
def test_MakeReportImpl_XmlReportError_WarningLogged(self, mock_logger):
mock_report = mock.MagicMock()
mock_report.when = 'call'
mock_item = mock.MagicMock()
mock_marker = mock.MagicMock()
test_case = '123'
test_case_list = [str(test_case)]
mock_marker.args = test_case_list
mock_item.get_marker.return_value = mock_marker
mock_item.config = ''
case_id._pytest_runtest_makereport_imp(mock_report, mock_item)
mock_logger.warning.assert_called_once()
def test_CollectionModifyItems_SingleTestCase_ItemsUpdated(self):
ids = [12, 34, 56]
id_to_filter = 34
items = []
deselected_items = []
for id in ids:
mock_item = mock.MagicMock()
mock_marker = mock.MagicMock()
mock_marker.args = [str(id)]
mock_item.get_marker.return_value = mock_marker
items.append(mock_item)
if id != id_to_filter:
deselected_items.append(mock_item)
mock_config = mock.MagicMock()
mock_config.option.test_case_ids = str(id_to_filter)
case_id.pytest_collection_modifyitems(items, mock_config)
assert len(items) == 1
assert items[0].get_marker().args[0] == str(id_to_filter)
mock_config.hook.pytest_deselected.assert_called_once_with(items=set(deselected_items))
def test_ParseTestCaseIds_ValidStringIds_IdsParsed(self):
ids = ['12', '34', '56']
expected = {12, 34, 56}
actual = case_id._parse_test_case_ids(ids)
assert expected == actual
def test_ParseTestCaseIds_ValidIntIds_IdsParsed(self):
ids = [12, 34, 56]
expected = {12, 34, 56}
actual = case_id._parse_test_case_ids(ids)
assert expected == actual
def test_ParseTestCaseIds_InvalidIds_ExceptionRaised(self):
ids = ['']
with pytest.raises(case_id.TestCaseIDException):
case_id._parse_test_case_ids(ids)
@@ -0,0 +1,144 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit tests for ly_test_tools._internal.pytest_plugin.failed_test_rerun_command
"""
import os
import pytest
import unittest.mock as mock
import ly_test_tools._internal.pytest_plugin.failed_test_rerun_command as failed_test_rerun_command
pytestmark = pytest.mark.SUITE_smoke
class TestRerunCommand(object):
MOCK_FOO_EXE = os.path.join('foo', 'path')
@mock.patch('os.path.join')
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_GetLauncherCommand_PythonScriptFound_CmdReturned(self, mock_join):
mock_python = 'python'
mock_join.return_value = mock_python
expected = f"{mock_python} -m pytest "
under_test = failed_test_rerun_command._get_test_launcher_cmd()
assert under_test == expected
@mock.patch('os.path.abspath', mock.MagicMock())
@mock.patch('os.path.join', mock.MagicMock())
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.sys.executable', MOCK_FOO_EXE)
@mock.patch('os.path.exists', mock.MagicMock(return_value=False))
def test_GetLauncherCommand_PythonScriptNotFound_ExeReturned(self):
expected = f"{TestRerunCommand.MOCK_FOO_EXE} -m pytest "
under_test = failed_test_rerun_command._get_test_launcher_cmd()
assert under_test == expected
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.sys.executable', MOCK_FOO_EXE)
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.WINDOWS', True)
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_GetLauncherCommand_WindowsPythonInterpreter_WindowsPythonEntrypointReturned(self):
python_script = 'python3.cmd'
expected = f"{os.path.join(TestRerunCommand.MOCK_FOO_EXE, python_script)} -m pytest "
under_test = failed_test_rerun_command._get_test_launcher_cmd()
assert under_test == expected
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.sys.executable', MOCK_FOO_EXE)
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.WINDOWS', False)
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_GetLauncherCommand_NonWindowsPythonInterpreter_NonWindowsPythonEntrypointReturned(self):
python_script = 'python3.sh'
expected = f"{os.path.join(TestRerunCommand.MOCK_FOO_EXE, python_script)} -m pytest "
under_test = failed_test_rerun_command._get_test_launcher_cmd()
assert under_test == expected
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.os.path.abspath')
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.os.path.dirname')
def test_FormatCommand_FileAsPathAndFullNodeId_CorrectCommand(self, mock_dirname, mock_abspath):
launcher_cmd = 'python -m pytest '
test_path = os.path.join('dirA', 'dirB', 'test_stuff.py')
nodeid = 'test_stuff.py::test_Stuff_Something_Else[a]'
mock_dirname.return_value = test_path
mock_abspath.return_value = os.path.join(test_path, nodeid)
expected = f'{launcher_cmd}{os.path.join(test_path, nodeid)}'
actual = failed_test_rerun_command._format_cmd(launcher_cmd, test_path, nodeid)
assert actual == expected
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.os.path.abspath')
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.os.path.dirname')
def test_FormatCommand_FileAsPathAndFileAsNodeId_CorrectCommand(self, mock_dirname, mock_abspath):
launcher_cmd = 'python -m pytest '
test_path = os.path.join('dirA', 'dirB', 'test_stuff.py')
nodeid = 'test_stuff.py'
mock_dirname.return_value = test_path
mock_abspath.return_value = os.path.join(test_path, nodeid)
expected = f'{launcher_cmd}{test_path}'
actual = failed_test_rerun_command._format_cmd(launcher_cmd, test_path, nodeid)
assert actual == expected
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.os.path.abspath')
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.os.path.dirname')
def test_FormatCommand_DirectoryAsPathAndFullNodeId_CorrectCommand(self, mock_dirname, mock_abspath):
launcher_cmd = 'python -m pytest '
test_path = os.path.join('dirA', 'dirB')
nodeid = 'test_Stuff_Something_Else[a]'
mock_dirname.return_value = test_path
mock_abspath.return_value = os.path.join(test_path, os.path.normpath(nodeid))
expected = f'{launcher_cmd}{os.path.join(test_path, nodeid)}'
actual = failed_test_rerun_command._format_cmd(launcher_cmd, test_path, nodeid)
assert actual == expected
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.os.path.abspath')
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.os.path.dirname')
def test_FormatCommand_DirectoryAsPathAndFileAsNodeId_CorrectCommand(self, mock_dirname, mock_abspath):
launcher_cmd = 'python -m pytest '
test_path = os.path.join('dirA', 'dirB')
nodeid = 'test_stuff.py'
mock_dirname.return_value = test_path
mock_abspath.return_value = os.path.join(test_path, os.path.normpath(nodeid))
expected = f'{launcher_cmd}{os.path.join(test_path, nodeid)}'
actual = failed_test_rerun_command._format_cmd(launcher_cmd, test_path, nodeid)
assert actual == expected
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command._get_test_launcher_cmd')
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.os.path.abspath')
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.os.path.dirname')
@mock.patch('os.path.exists', mock.MagicMock(return_value=False))
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.os.environ', {})
def test_BuildCommands_TwoNodeIds_CorrectCommands(self, mock_dirname, mock_abspath, mock_get_test_launcher_cmd):
test_path = os.path.join('dirA', 'dirB')
nodeids = ['test_stuff.py', 'test_something::test_Something_Somewhere_Somehow[a]']
python_cmd = 'python -m pytest '
mock_get_test_launcher_cmd.return_value = python_cmd
mock_dirname.side_effect = [test_path, test_path]
mock_abspath.side_effect = [os.path.join(test_path, os.path.normpath(nodeids[0])),
os.path.join(test_path, os.path.normpath(nodeids[1]))]
expected = [f'{python_cmd}{os.path.join(test_path, nodeids[0])}',
f'{python_cmd}{os.path.join(test_path, nodeids[1])}']
actual = failed_test_rerun_command.build_rerun_commands(test_path, nodeids)
assert actual == expected
@@ -0,0 +1,919 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import errno
import logging
import os
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('os.path.exists')
@mock.patch('ly_test_tools.environment.file_system.check_free_space')
@mock.patch('os.path.join')
def test_Unzip_ReleaseBuild_JoinCalledWithNoPathNoExtension(self, mock_join, mock_check_free, mock_exists):
path = ''
self.src_path = r'C:\packages\lumberyard-1.2.0.3-54321-pc-1234.zip'
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_join.assert_called_once_with(self.dest_path, 'lumberyard-1.2.0.3-54321-pc-1234')
@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.check_free_space')
@mock.patch('os.path.join')
@mock.patch('os.stat')
def test_Untgz_ReleaseBuild_JoinCalledWithNoPathNoExtension(self, mock_stat, mock_join, mock_check_free):
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)
mock_join.assert_called_once_with(self.dest_path, 'lumberyard-1.2.0.3-54321-pc-1234')
@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 TestUnlockFile(unittest.TestCase):
def setUp(self):
self.file_name = 'file'
@mock.patch('os.chmod')
@mock.patch('os.access')
def test_UnlockFile_WriteLocked_UnlockFile(self, mock_access, mock_chmod):
mock_access.return_value = False
success = file_system.unlock_file(self.file_name)
self.assertTrue(success)
@mock.patch('os.chmod')
@mock.patch('os.access')
def test_UnlockFile_AlreadyUnlocked_LogAlreadyUnlocked(self, mock_access, mock_chmod):
mock_access.return_value = True
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.chmod')
@mock.patch('os.access')
def test_UnlockFile_UnlockedFile_FileLockedSuccessReturnsTrue(self, mock_access, mock_chmod):
mock_access.return_value = True
success = file_system.lock_file(self.file_name)
self.assertTrue(success)
@mock.patch('os.chmod')
@mock.patch('os.access')
def test_UnlockFile_AlreadyLocked_FileLockedFailedReturnsFalse(self, mock_access, mock_chmod):
mock_access.return_value = False
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)
@@ -0,0 +1,375 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
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_LaunchSamplesProject'
'[120-simple_jacklocomotion-SamplesProject-all-profile-win_x64_vs2017]')
test_method = 'test_SystemTestExample_AllSupportedPlatforms_LaunchSamplesProject'
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_LaunchSamplesProject'
)
@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()
@@ -0,0 +1,38 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit tests for image_capture.py
"""
import unittest.mock as mock
import unittest
import pytest
import ly_test_tools.image.image_capture
pytestmark = pytest.mark.SUITE_smoke
class TestScreenCap(unittest.TestCase):
@mock.patch('pyscreenshot.grab')
def test_ScreenCap_CoordsAndNameGiven_Used(self, mock_grab):
mock_grab.return_value = mock.MagicMock()
mock_grab.return_value.save = mock.MagicMock()
x1 = 10
x2 = 20
y1 = 30
y2 = 40
image_name = 'test_capture.png'
ly_test_tools.image.image_capture.screencap(x1, y1, x2, y2, filename=image_name)
mock_grab.assert_called_once_with(bbox=(x1, y1, x2, y2), childprocess=False)
mock_grab.return_value.save.assert_called_once_with(image_name)
@@ -0,0 +1,331 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit Tests for android launcher-wrappers: all are sanity code-path tests, since no interprocess actions should be taken
"""
import unittest.mock as mock
import pytest
import ly_test_tools.launchers
import ly_test_tools.launchers.platforms.android.launcher
import ly_test_tools.launchers.exceptions
import ly_test_tools.mobile.android
pytestmark = pytest.mark.SUITE_smoke
VALID_ANDROID_CONFIG = {
'android': {
'id': '000000000000000'
}
}
PACKAGE_NAME = "dummy_project_path"
class MockedWorkspace(object):
def __init__(self):
self.paths = mock.MagicMock()
self.setup_assistant = mock.MagicMock()
self.asset_processor = mock.MagicMock()
self.shader_compiler = mock.MagicMock()
self.settings = mock.MagicMock()
self.paths.dev.return_value = 'dev_path'
self.paths.build_directory.return_value = 'build_directory'
self.paths.autoexec_file.return_value = 'autoexec.cfg'
self.project = 'project_name'
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.open', mock.mock_open())
class TestLauncherModule:
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.json.loads')
def test_GetPackageName_MockJsonHasKey_ReturnsValue(self, mock_json):
dummy_name = "some_name"
mock_json.return_value = {'android_settings': {'package_name': dummy_name}}
under_test = ly_test_tools.launchers.platforms.android.launcher.get_package_name(PACKAGE_NAME)
assert under_test == "some_name"
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.json.loads')
def test_GetPackageName_MockJsonMissingKey_SetupError(self, mock_json):
mock_json.return_value = {"one": "two"}
with pytest.raises(ly_test_tools.launchers.exceptions.SetupError):
ly_test_tools.launchers.platforms.android.launcher.get_package_name(PACKAGE_NAME)
@mock.patch('ly_test_tools.environment.process_utils.check_output')
def test_GetPid_EarlyVersionAndExplodes_NoPid(self, mock_output):
mock_output.side_effect = ['23', Exception]
under_test = ly_test_tools.launchers.platforms.android.launcher.get_pid("dummy", ["dummy"])
assert mock_output.call_count == 2
assert not under_test
@mock.patch('ly_test_tools.environment.process_utils.check_output')
def test_GetPid_LaterVersionAndExplodes_NoPid(self, mock_output):
mock_output.side_effect = ['25', Exception]
under_test = ly_test_tools.launchers.platforms.android.launcher.get_pid("dummy", ["dummy"])
assert mock_output.call_count == 2
assert not under_test
@mock.patch('ly_test_tools.environment.process_utils.check_output')
def test_GetPid_PidHasSingleValue_ReturnPid(self, mock_output):
mock_output.side_effect = ['25', '12']
under_test = ly_test_tools.launchers.platforms.android.launcher.get_pid("dummy", ["dummy"])
assert mock_output.call_count == 2
assert under_test == '12'
@mock.patch('ly_test_tools.environment.process_utils.check_output')
def test_GetPid_PidHasMultipleValues_ReturnPid(self, mock_output):
mock_output.side_effect = ['25', 'value 12 found']
under_test = ly_test_tools.launchers.platforms.android.launcher.get_pid("dummy", ["dummy"])
assert mock_output.call_count == 2
assert under_test == '12'
def test_GenerateMapCommand_HasMapArg_ReturnsMapCommand(self):
args_list = ['random_arg', '+map', 'map_name', 'another_arg']
under_test = ly_test_tools.launchers.platforms.android.launcher.generate_android_map_command(args_list)
assert under_test == 'map map_name'
def test_GenerateMapCommand_NoMapArg_ReturnsEmptyString(self):
args_list = ['random_arg', 'stuff', 'map_name', 'another_arg']
under_test = ly_test_tools.launchers.platforms.android.launcher.generate_android_map_command(args_list)
assert under_test == ''
@mock.patch('os.listdir', mock.MagicMock())
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.get_package_name',
mock.MagicMock(return_value=PACKAGE_NAME))
@mock.patch('ly_test_tools.environment.file_system.create_backup', mock.MagicMock)
@mock.patch('ly_test_tools.environment.file_system.restore_backup', mock.MagicMock)
@mock.patch('ly_test_tools.mobile.android.check_adb_connection_state', mock.MagicMock)
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.open', mock.mock_open())
class TestAndroidLauncher:
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
def test_ReadDeviceConfigINI_ReturnDeviceID_DeviceIDSet(self, mock_config):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_workspace = MockedWorkspace()
launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
assert launcher._device_id == VALID_ANDROID_CONFIG['android']['id']
assert ['adb', '-s', launcher._device_id] == launcher._adb_prefix_command
mock_config.assert_called_once()
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
def test_ReadDeviceConfigINI_ReturnsInvalidConfig_SetupError(self, mock_config):
mock_config.return_value = {'device': {'id': 12345}}
mock_workspace = MockedWorkspace()
with pytest.raises(ly_test_tools.launchers.exceptions.SetupError):
ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
@mock.patch('ly_test_tools.mobile.android.forward_tcp')
@mock.patch('ly_test_tools.mobile.android.reverse_tcp')
@mock.patch('ly_test_tools.mobile.android.undo_tcp_port_changes')
def test_EnableAndroidCaps_SetsAndroidCaps_CallsReverseTCPForwardTCP(self, mock_undo_tcp, mock_reverse_tcp,
mock_forward_tcp, mock_config):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_workspace = MockedWorkspace()
under_test = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
under_test._enable_android_capabilities()
assert mock_reverse_tcp.call_count == 2
mock_forward_tcp.assert_called_once()
mock_undo_tcp.assert_called_with(VALID_ANDROID_CONFIG['android']['id'])
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher.backup_settings')
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher.configure_settings')
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher._enable_android_capabilities')
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher._is_valid_android_environment')
@mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock(return_value=True))
def test_Setup_ValidSetup_SetupCallsSucceed(self, mock_valid_env, mock_enable_caps, mock_config,
mock_configure_settings, mock_backup):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_workspace = MockedWorkspace()
mock_project_log_path = 'c:/mock_project/log/'
mock_workspace.paths.project_log.return_value = mock_project_log_path
under_test = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
under_test.setup()
mock_enable_caps.assert_called_once()
mock_valid_env.assert_called_once()
mock_backup.assert_called_once()
mock_configure_settings.assert_called_once()
mock_workspace.shader_compiler.start.assert_called_once()
@mock.patch('ly_test_tools.mobile.android.can_run_android')
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher.backup_settings', mock.MagicMock())
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher.configure_settings',
mock.MagicMock())
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher._enable_android_capabilities',
mock.MagicMock())
@mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock(return_value=True))
def test_Setup_InvalidSetupNoADB_RaisesNotImplementedErrorException(self, mock_config, mock_can_run_android):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_workspace = MockedWorkspace()
mock_can_run_android.return_value = False
under_test = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
with pytest.raises(NotImplementedError):
under_test.setup()
@mock.patch('ly_test_tools.mobile.android.get_devices')
@mock.patch('ly_test_tools.mobile.android.can_run_android', mock.MagicMock(return_value=True))
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher.backup_settings', mock.MagicMock())
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher.configure_settings',
mock.MagicMock())
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher._enable_android_capabilities',
mock.MagicMock())
@mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock(return_value=True))
def test_Setup_InvalidSetupNoDeviceConnected_RaisesSetupErrorException(self, mock_config, mock_get_devices):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_workspace = MockedWorkspace()
mock_get_devices.return_value = []
under_test = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
with pytest.raises(ly_test_tools.launchers.exceptions.SetupError):
under_test.setup()
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.restore_settings')
@mock.patch('ly_test_tools.mobile.android.undo_tcp_port_changes', mock.MagicMock)
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.AndroidLauncher._enable_android_capabilities',
mock.MagicMock)
def test_Teardown_ValidTeardown_TeardownSucceeds(self, mock_restore, mock_config):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_workspace = MockedWorkspace()
launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
launcher.teardown()
mock_restore.assert_called_once()
mock_workspace.shader_compiler.stop.assert_called_once()
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
@mock.patch('ly_test_tools.lumberyard.settings.LySettings.modify_bootstrap_setting', mock.MagicMock)
@mock.patch('ly_test_tools.lumberyard.settings.LySettings.modify_platform_setting', mock.MagicMock)
def test_ConfigureSettings_DefaultValues_SetsValues(self, mock_config):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_workspace = MockedWorkspace()
launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
launcher.configure_settings()
assert mock_workspace.settings.modify_bootstrap_setting.call_count == 6
assert mock_workspace.settings.modify_platform_setting.call_count == 8
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
@mock.patch('ly_test_tools.environment.process_utils.check_output')
@mock.patch('os.path.isfile', mock.MagicMock(return_value=False))
def test_Launch_HappyPathNoAutoexec_CallsLaunchCmd(self, mock_call, mock_config):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_workspace = MockedWorkspace()
launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
launcher.launch()
mock_call.assert_called_once_with([
'adb', '-s', VALID_ANDROID_CONFIG['android']['id'], 'shell', 'monkey', '-p', PACKAGE_NAME,
'-c', 'android.intent.category.LAUNCHER', '1'])
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
@mock.patch('ly_test_tools.environment.process_utils.check_output')
@mock.patch('ly_test_tools.mobile.android.push_files_to_device', mock.MagicMock)
@mock.patch('os.path.isfile', mock.MagicMock(return_value=True))
def test_Launch_HappyPathHasAutoExec_PushesFilesToDevice(self, mock_push_files, mock_config):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_workspace = MockedWorkspace()
launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
launcher.launch()
mock_push_files.assert_called_once()
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
@mock.patch('ly_test_tools.environment.process_utils.check_output')
@mock.patch('os.path.isfile', mock.MagicMock(return_value=False))
def test_Launch_MonkeyAbortedInLaunchResult_RaisesSetupError(self, mock_call, mock_config):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_call.return_value = 'Monkey Aborted'
mock_workspace = MockedWorkspace()
launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
with pytest.raises(ly_test_tools.launchers.exceptions.SetupError):
launcher.launch()
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.get_pid')
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
def test_IsAlive_MockPidDNE_False(self, mock_config, mock_pid):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_workspace = MockedWorkspace()
launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
mock_pid.return_value = ""
assert not launcher.is_alive()
@mock.patch('ly_test_tools.launchers.platforms.android.launcher.get_pid')
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
def test_IsAlive_MockPidExists_True(self, mock_config, mock_pid):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_workspace = MockedWorkspace()
launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
mock_pid.return_value = "1234"
assert launcher.is_alive()
@mock.patch('ly_test_tools.environment.process_utils.check_call')
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
@mock.patch('ly_test_tools.mobile.android.check_adb_connection_state',
mock.MagicMock(return_value=ly_test_tools.mobile.android.SINGLE_DEVICE))
def test_Kill_HappyPath_KillCommandSuccess(self, mock_config, mock_call):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_workspace = MockedWorkspace()
launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
launcher.kill()
mock_call.assert_called_once_with(
['adb', '-s', VALID_ANDROID_CONFIG['android']['id'], 'shell', 'am', 'force-stop', PACKAGE_NAME])
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
def test_BinaryPath_Called_RaisesNotImplementedError(self, mock_config):
mock_config.return_value = VALID_ANDROID_CONFIG
mock_workspace = MockedWorkspace()
launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
with pytest.raises(NotImplementedError):
launcher.binary_path()
@@ -0,0 +1,228 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit Tests for base launcher-wrapper: all are sanity code-path tests, since no interprocess actions should be taken
"""
import os
import unittest.mock as mock
import pytest
import ly_test_tools.launchers
import ly_test_tools.launchers.launcher_helper
import ly_test_tools._internal.managers.artifact_manager
pytestmark = pytest.mark.SUITE_smoke
class TestBaseLauncher:
def test_Construct_TestDoubles_BaseLauncherCreated(self):
mock_workspace = mock.MagicMock()
mock_project_log_path = 'c:/mock_project/log/'
mock_workspace.paths.project_log.return_value = mock_project_log_path
under_test = ly_test_tools.launchers.Launcher(mock_workspace, ["some_args"])
assert isinstance(under_test, ly_test_tools.launchers.Launcher)
return under_test
def test_Construct_StringArgs_TypeError(self):
mock_workspace = mock.MagicMock()
with pytest.raises(TypeError):
ly_test_tools.launchers.Launcher(mock_workspace, "bad_args")
def test_BinaryPath_Unimplemented_NotImplementedError(self):
launcher = self.test_Construct_TestDoubles_BaseLauncherCreated()
with pytest.raises(NotImplementedError):
launcher.binary_path()
def test_EnsureStopped_IsAliveUnimplemented_NotImplementedError(self):
launcher = self.test_Construct_TestDoubles_BaseLauncherCreated()
with pytest.raises(NotImplementedError):
launcher.ensure_stopped()
def test_IsAlive_Unimplemented_NotImplementedError(self):
launcher = self.test_Construct_TestDoubles_BaseLauncherCreated()
with pytest.raises(NotImplementedError):
launcher.is_alive()
def test_Kill_Unimplemented_NotImplementedError(self):
launcher = self.test_Construct_TestDoubles_BaseLauncherCreated()
with pytest.raises(NotImplementedError):
launcher.kill()
def test_Launch_Unimplemented_NotImplementedError(self):
launcher = self.test_Construct_TestDoubles_BaseLauncherCreated()
with pytest.raises(NotImplementedError):
launcher.launch()
@mock.patch('os.listdir', mock.MagicMock())
@mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock(return_value=True))
def test_Start_UnimplementedLauncher_NotImplementedError(self):
launcher = self.test_Construct_TestDoubles_BaseLauncherCreated()
with pytest.raises(NotImplementedError):
launcher.start()
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.launch')
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.setup')
def test_Start_MockImplementedLauncher_SetupLaunch(self, mock_setup, mock_launch):
launcher = self.test_Construct_TestDoubles_BaseLauncherCreated()
launcher.start()
mock_setup.assert_called_once()
mock_launch.assert_called_once()
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.launch')
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.setup')
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.stop')
def test_WithStart_MockImplementedLauncher_SetupLaunchStop(self, mock_stop, mock_setup, mock_launch):
launcher = self.test_Construct_TestDoubles_BaseLauncherCreated()
with launcher.start():
pass
mock_stop.assert_called_once()
mock_setup.assert_called_once()
mock_launch.assert_called_once()
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.setup')
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.stop')
def test_WithStart_ErrorDuringStart_StopNotCalled(self, mock_stop, mock_setup):
mock_setup.side_effect = BufferError
launcher = self.test_Construct_TestDoubles_BaseLauncherCreated()
with pytest.raises(BufferError):
with launcher.start():
pass
mock_stop.assert_not_called()
mock_setup.assert_called_once()
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.launch', mock.MagicMock)
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.setup', mock.MagicMock)
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.stop')
def test_WithStart_ErrorAfterStart_StopCalled(self, mock_stop):
launcher = self.test_Construct_TestDoubles_BaseLauncherCreated()
with pytest.raises(BufferError):
with launcher.start():
raise BufferError
mock_stop.assert_called_once()
def test_Stop_UnimplementedLauncher_NotImplementedError(self):
launcher = self.test_Construct_TestDoubles_BaseLauncherCreated()
with pytest.raises(NotImplementedError):
launcher.stop()
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.kill')
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.ensure_stopped')
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.teardown')
def test_Stop_MockImplementedLauncher_KillTeardown(self, mock_teardown, mock_ensure, mock_kill):
launcher = self.test_Construct_TestDoubles_BaseLauncherCreated()
launcher.stop()
mock_kill.assert_called_once()
mock_teardown.assert_called_once()
mock_ensure.assert_called_once()
@mock.patch('os.listdir', mock.MagicMock())
@mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock(return_value=True))
def test_Setup_TestDoublesNoAPOpen_StartAssetProcessor(self):
mock_workspace = mock.MagicMock()
mock_start_ap = mock.MagicMock()
mock_workspace.asset_processor.start = mock_start_ap
mock_project_log_path = 'c:/mock_project/log/'
mock_workspace.paths.project_log.return_value = mock_project_log_path
under_test = ly_test_tools.launchers.Launcher(mock_workspace, ["some_args"])
under_test.setup()
under_test.workspace.asset_processor.start.assert_called_once()
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.save_project_log_files', mock.MagicMock())
def test_Teardown_TestDoubles_StopAppAndStopAssetProcessor(self):
mock_workspace = mock.MagicMock()
mock_stop_ap = mock.MagicMock()
mock_workspace.asset_processor.stop = mock_stop_ap
under_test = ly_test_tools.launchers.Launcher(mock_workspace, ["some_args"])
under_test.teardown()
mock_stop_ap.assert_called_once()
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher.save_project_log_files')
def test_Teardown_TeardownCalled_CallsSaveProjectLogFiles(self, under_test):
mock_workspace = mock.MagicMock()
mock_args = ['foo']
mock_launcher = ly_test_tools.launchers.Launcher(mock_workspace, mock_args)
mock_launcher.teardown()
under_test.assert_called_once()
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
@mock.patch('ly_test_tools._internal.managers.artifact_manager.ArtifactManager.save_artifact')
@mock.patch('os.listdir')
def test_SaveProjectLogFiles_LogFilesExist_SavesOnlyLogs(self, mock_listdir, under_test):
mock_log = 'foo.log'
mock_txt = 'foo.txt'
mock_args = ['foo']
mock_project_log_path = 'c:/mock_project/log/'
assert_path = os.path.join(mock_project_log_path, mock_log)
mock_listdir.return_value = [mock_log, mock_txt]
mock_workspace = mock.MagicMock()
mock_artifact_manager = ly_test_tools._internal.managers.artifact_manager.ArtifactManager(mock.MagicMock())
mock_workspace.artifact_manager = mock_artifact_manager
mock_workspace.paths.project_log.return_value = mock_project_log_path
mock_launcher = ly_test_tools.launchers.Launcher(mock_workspace, mock_args)
mock_launcher.save_project_log_files()
under_test.assert_called_once_with(assert_path, amount=100)
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
@mock.patch('ly_test_tools._internal.managers.artifact_manager.ArtifactManager.save_artifact')
@mock.patch('os.listdir')
def test_SaveProjectLogFiles_DmpFilesExist_SavesOnlyDmps(self, mock_listdir, under_test):
mock_dmp = 'foo.dmp'
mock_txt = 'foo.txt'
mock_args = ['foo']
mock_project_log_path = 'c:/mock_project/log/'
assert_path = os.path.join(mock_project_log_path, mock_dmp)
mock_listdir.return_value = [mock_dmp, mock_txt]
mock_workspace = mock.MagicMock()
mock_artifact_manager = ly_test_tools._internal.managers.artifact_manager.ArtifactManager(mock.MagicMock())
mock_workspace.artifact_manager = mock_artifact_manager
mock_workspace.paths.project_log.return_value = mock_project_log_path
mock_launcher = ly_test_tools.launchers.Launcher(mock_workspace, mock_args)
mock_launcher.save_project_log_files()
under_test.assert_called_once_with(assert_path, amount=100)
class TestLauncherBuilder(object):
"""
Fixture builder/helper in launchers.launcher
"""
def test_CreateLauncher_DummyWorkspace_DefaultLauncher(self):
dummy_workspace = mock.MagicMock()
launcher_platform = 'windows'
under_test = ly_test_tools.launchers.launcher_helper.create_launcher(
dummy_workspace, launcher_platform)
assert isinstance(under_test, ly_test_tools.launchers.Launcher)
def test_CreateDedicateLauncher_DummyWorkspace_DefaultLauncher(self):
dummy_workspace = mock.MagicMock()
launcher_platform = 'windows_dedicated'
under_test = ly_test_tools.launchers.launcher_helper.create_dedicated_launcher(
dummy_workspace, launcher_platform)
assert isinstance(under_test, ly_test_tools.launchers.Launcher)
def test_CreateEditor_DummyWorkspace_DefaultLauncher(self):
dummy_workspace = mock.MagicMock()
launcher_platform = 'windows_editor'
under_test = ly_test_tools.launchers.launcher_helper.create_editor(
dummy_workspace, launcher_platform)
assert isinstance(under_test, ly_test_tools.launchers.Launcher)
@@ -0,0 +1,72 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit Tests for mac launcher-wrappers: all are sanity code-path tests, since no interprocess actions should be taken
"""
import os
import pytest
import unittest.mock as mock
import ly_test_tools.launchers
pytestmark = pytest.mark.SUITE_smoke
class TestMacLauncher(object):
def test_Construct_TestDoubles_MacLauncherCreated(self):
under_test = ly_test_tools.launchers.MacLauncher(mock.MagicMock(), ["some_args"])
assert isinstance(under_test, ly_test_tools.launchers.Launcher)
assert isinstance(under_test, ly_test_tools.launchers.MacLauncher)
def test_BinaryPath_DummyPath_AddPathToApp(self):
dummy_path = "dummy_workspace_path"
dummy_project = "dummy_project"
mock_workspace = mock.MagicMock()
mock_workspace.paths.build_directory.return_value = dummy_path
mock_workspace.project = dummy_project
launcher = ly_test_tools.launchers.MacLauncher(mock_workspace, ["some_args"])
under_test = launcher.binary_path()
expected = os.path.join(f'{dummy_path}',
f"{dummy_project}.GameLauncher.app",
"Contents",
"MacOS",
f"{dummy_project}.GameLauncher")
assert under_test == expected
@mock.patch('ly_test_tools.launchers.MacLauncher.binary_path', mock.MagicMock)
@mock.patch('subprocess.Popen')
def test_Launch_DummyArgs_ArgsPassedToPopen(self, mock_subprocess):
dummy_args = ["some_args"]
launcher = ly_test_tools.launchers.MacLauncher(mock.MagicMock(), dummy_args)
launcher.launch()
mock_subprocess.assert_called_once()
name, args, kwargs = mock_subprocess.mock_calls[0]
unpacked_args = args[0] # args is a list inside a tuple
assert len(dummy_args) > 0, "accidentally removed dummy_args"
for expected_arg in dummy_args:
assert expected_arg in unpacked_args
@mock.patch('ly_test_tools.launchers.MacLauncher.is_alive')
def test_Kill_MockAliveFalse_SilentSuccess(self, mock_alive):
mock_alive.return_value = False
mock_proc = mock.MagicMock()
launcher = ly_test_tools.launchers.MacLauncher(mock.MagicMock(), ["dummy"])
launcher._proc = mock_proc
launcher.kill()
mock_proc.kill.assert_called_once()
mock_alive.assert_called_once()
@@ -0,0 +1,186 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit Tests for windows launcher-wrappers: all are sanity code-path tests, since no interprocess actions should be taken
"""
import os
import unittest.mock as mock
import pytest
import ly_test_tools.launchers
import ly_test_tools.launchers.exceptions
pytestmark = pytest.mark.SUITE_smoke
class TestWinLauncher(object):
def test_BinaryPath_DummyPath_AddPathToExe(self):
dummy_path = "dummy_workspace_path"
dummy_project = "dummy_project"
mock_workspace = mock.MagicMock()
mock_workspace.paths.build_directory.return_value = dummy_path
mock_workspace.project = dummy_project
launcher = ly_test_tools.launchers.WinLauncher(mock_workspace, ["some_args"])
under_test = launcher.binary_path()
expected = os.path.join(f'{dummy_path}',
f'{dummy_project}.GameLauncher.exe')
assert expected == under_test
@mock.patch('ly_test_tools.launchers.WinLauncher.binary_path', mock.MagicMock)
@mock.patch('subprocess.Popen')
def test_Launch_DummyArgs_ArgsPassedToPopen(self, mock_subprocess):
dummy_args = ["some_args"]
launcher = ly_test_tools.launchers.WinLauncher(mock.MagicMock(), dummy_args)
launcher.launch()
mock_subprocess.assert_called_once()
name, args, kwargs = mock_subprocess.mock_calls[0]
unpacked_args = args[0] # args is a list inside a tuple
assert len(dummy_args) > 0, "accidentally removed dummy_args"
for expected_arg in dummy_args:
assert expected_arg in unpacked_args
@mock.patch('ly_test_tools.launchers.WinLauncher.is_alive')
def test_Kill_MockAliveFalse_SilentSuccess(self, mock_alive):
mock_alive.return_value = False
mock_proc = mock.MagicMock()
launcher = ly_test_tools.launchers.WinLauncher(mock.MagicMock(), ["dummy"])
launcher._proc = mock_proc
launcher.kill()
mock_proc.kill.assert_called_once()
mock_alive.assert_called_once()
def test_IsAlive_NoProc_False(self):
launcher = ly_test_tools.launchers.WinLauncher(mock.MagicMock(), ["dummy"])
under_test = launcher.is_alive()
assert under_test is False
def test_IsAlive_MockProcNotReturned_True(self):
mock_proc = mock.MagicMock()
mock_proc.poll.return_value = None
launcher = ly_test_tools.launchers.WinLauncher(mock.MagicMock(), ["dummy"])
launcher._proc = mock_proc
under_test = launcher.is_alive()
assert under_test is True
def test_IsAlive_MockProcHasReturned_False(self):
mock_proc = mock.MagicMock()
mock_proc.poll.return_value = 0
launcher = ly_test_tools.launchers.WinLauncher(mock.MagicMock(), ["dummy"])
launcher._proc = mock_proc
under_test = launcher.is_alive()
assert under_test is False
def test_GetPid_HasProcess_ReturnsPid(self):
mock_pid = 11111
mock_launcher = ly_test_tools.launchers.WinLauncher(mock.MagicMock(), ["dummy"])
mock_proc = mock.MagicMock()
mock_proc.pid = mock_pid
mock_launcher._proc = mock_proc
assert mock_launcher.get_pid() == mock_pid
def test_GetPid_HasNoProcess_ReturnsNone(self):
mock_launcher = ly_test_tools.launchers.WinLauncher(mock.MagicMock(), ["dummy"])
mock_proc = None
mock_launcher._proc = mock_proc
assert mock_launcher.get_pid() is None
def test_GetReturnCode_HasProcess_CallsPoll(self):
mock_launcher = ly_test_tools.launchers.WinLauncher(mock.MagicMock(), ["dummy"])
mock_proc = mock.MagicMock()
mock_launcher._proc = mock_proc
mock_launcher.get_returncode()
mock_proc.poll.assert_called_once()
@mock.patch('subprocess.Popen.poll')
def test_GetReturnCode_HasNoProcess_ReturnsNone(self, under_test):
mock_launcher = ly_test_tools.launchers.WinLauncher(mock.MagicMock(), ["dummy"])
mock_launcher._proc = None
mock_launcher.get_returncode()
under_test.assert_not_called()
@mock.patch('ly_test_tools.launchers.WinLauncher.get_returncode')
def test_CheckReturnCode_Called_CallsGetReturncode(self, under_test):
mock_launcher = ly_test_tools.launchers.WinLauncher(mock.MagicMock(), ["dummy"])
under_test.return_value = 0
mock_launcher.check_returncode()
under_test.assert_called()
@mock.patch('ly_test_tools.launchers.WinLauncher.get_returncode')
def test_CheckReturnCode_ReturnCodeIsZero_ReturnsNone(self, mock_get_returncode):
mock_launcher = ly_test_tools.launchers.WinLauncher(mock.MagicMock(), ["dummy"])
mock_get_returncode.return_value = 0
under_test = mock_launcher.check_returncode()
assert under_test is None
@mock.patch('ly_test_tools.launchers.WinLauncher.get_returncode')
def test_CheckReturnCode_ReturnCodeIsNonZero_RaisesError(self, mock_get_returncode):
mock_launcher = ly_test_tools.launchers.WinLauncher(mock.MagicMock(), ["dummy"])
mock_get_returncode.return_value = 1
with pytest.raises(ly_test_tools.launchers.exceptions.CrashError):
mock_launcher.check_returncode()
class TestWinEditor(object):
def test_BinaryPath_DummyPath_AddPathToExe(self):
dummy_path = "dummy_workspace_path"
mock_workspace = mock.MagicMock()
mock_workspace.paths.build_directory.return_value = dummy_path
launcher = ly_test_tools.launchers.WinEditor(mock_workspace, ["some_args"])
under_test = launcher.binary_path()
assert "Editor.exe" in under_test
assert dummy_path in under_test, "workspace path unexpectedly missing"
class TestDedicatedWinLauncher(object):
def test_BinaryPath_DummyPath_AddPathToExe(self):
dummy_path = "dummy_workspace_path"
dummy_project = "dummy_project"
mock_workspace = mock.MagicMock()
mock_workspace.paths.build_directory.return_value = dummy_path
mock_workspace.project = dummy_project
launcher = ly_test_tools.launchers.DedicatedWinLauncher(mock_workspace, ["some_args"])
under_test = launcher.binary_path()
expected = os.path.join(f'{dummy_path}',
f'{dummy_project}.ServerLauncher.exe')
assert under_test == expected
def test_Build_MockWorkspace_DedicatedBuildRequested(self):
mock_workspace = mock.MagicMock()
launcher = ly_test_tools.launchers.DedicatedWinLauncher(mock_workspace, ["some_args"])
launcher.workspace.build(dedicated=True)
mock_workspace.build.assert_called_once_with(dedicated=True)
@@ -0,0 +1,229 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit tests for ly_test_tools.log.log_monitor
"""
import io
import unittest.mock as mock
import pytest
import ly_test_tools.log.log_monitor
import ly_test_tools.launchers.platforms.base
pytestmark = pytest.mark.SUITE_smoke
mock_launcher = mock.MagicMock(ly_test_tools.launchers.platforms.base.Launcher)
def mock_log_monitor():
"""Returns a LogMonitor() object with all required parameters & resets attributes for each test."""
log_monitor = ly_test_tools.log.log_monitor.LogMonitor(
launcher=mock_launcher, log_file_path='mock_path')
log_monitor.unexpected_lines_found = []
log_monitor.expected_lines_not_found = []
return log_monitor
class NotALauncher(object):
"""For simulating test failure when the wrong class is passed as a launcher parameter in LogMonitor()."""
pass
@mock.patch('time.sleep', mock.MagicMock)
class TestLogMonitor(object):
def test_Init_HasRequiredParams_ReturnsLogMonitorObject(self):
assert ly_test_tools.log.log_monitor.LogMonitor(
launcher=mock_launcher, log_file_path='some_log_file.log')
def test_CheckExactMatch_HasMatch_ReturnsString(self):
line = '9189.9998188 - INFO - [MainThread] - example.tests.test_system_example - Log Monitoring test 1'
expected_line = 'Log Monitoring test 1'
under_test = ly_test_tools.log.log_monitor.check_exact_match(line, expected_line)
assert under_test == expected_line
def test_CheckExactMatch_NoMatch_ReturnsNone(self):
line = 'log line'
expected_line = 'no match'
under_test = ly_test_tools.log.log_monitor.check_exact_match(line, expected_line)
assert under_test is None
def test_CheckExactMatch_HasExactMatchWithEscapeCharacter_ReturnsString(self):
line = '9189.9998188 - INFO - [MainThread] - Log Monitoring Test ($1/1).t text'
under_test = ly_test_tools.log.log_monitor.check_exact_match(line, line)
assert under_test == line
def test_CheckExactMatch_NoMatchWithEscapeCharacter_ReturnsNone(self):
line = r'<script\\x20type=\"text/javascript\">javascript:alert(1);</script>'
expected_line = 'no match'
under_test = ly_test_tools.log.log_monitor.check_exact_match(line, expected_line)
assert under_test is None
def test_CheckExactMatch_HasExactMatchWithEscapeCharacterAtEndOfString_ReturnsString(self):
line = 'Testing with escape character as the last character in this (line)'
under_test = ly_test_tools.log.log_monitor.check_exact_match(line, line)
assert under_test == line
def test_CheckExactMatch_HasExactMatchWithNonWordCharacterAtStartOfString_ReturnsString(self):
line = '(Testing with non-word character as the first character in this line'
under_test = ly_test_tools.log.log_monitor.check_exact_match(line, line)
assert under_test == line
def test_CheckSubstringMatch_SubstringMatchWithinWord_ReturnsNone(self):
line = 'SubstringMatchWithinWord'
expected_line = 'Match'
under_test = ly_test_tools.log.log_monitor.check_exact_match(line, expected_line)
assert under_test is None
def test_CheckSubstringMatch_SubstringMatchBetweenWords_ReturnsMatch(self):
line = 'Substring Match Within Word'
expected_line = 'Match'
under_test = ly_test_tools.log.log_monitor.check_exact_match(line, expected_line)
assert under_test == expected_line
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_Monitor_AllLinesFound_Success(self):
mock_file = io.StringIO(u'a\nb\nc\n')
mock_launcher.is_alive.side_effect = [True, True, True, False]
with mock.patch('ly_test_tools.log.log_monitor.open', return_value=mock_file, create=True):
mock_log_monitor().monitor_log_for_lines(['a', 'b', 'c'], ['d'])
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_Monitor_AllLinesNotFound_RaisesLogMonitorException(self):
mock_file = io.StringIO(u'a\nb\nc\n')
mock_launcher.is_alive.side_effect = [True, True, True, False]
with mock.patch('ly_test_tools.log.log_monitor.open', return_value=mock_file, create=True):
with pytest.raises(ly_test_tools.log.log_monitor.LogMonitorException):
mock_log_monitor().monitor_log_for_lines(['a', 'b', 'c', 'd'], ['c'])
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_Monitor_SomeUnexpectedLinesFound_RaiseLogMonitorException(self):
mock_file = io.StringIO(u'foo\nbar\n')
mock_launcher.is_alive.side_effect = [True, True, True, False]
with mock.patch('ly_test_tools.log.log_monitor.open', return_value=mock_file, create=True):
with pytest.raises(ly_test_tools.log.log_monitor.LogMonitorException):
mock_log_monitor().monitor_log_for_lines(['foo', 'bar'], ['bar'], halt_on_unexpected=True)
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_Monitor_ExpectedLinesNotFound_RaiseLogMonitorException(self):
mock_file = io.StringIO(u'foo\nbar\n')
mock_launcher.is_alive.side_effect = [True, True, True, False]
with mock.patch('ly_test_tools.log.log_monitor.open', return_value=mock_file, create=True):
with pytest.raises(ly_test_tools.log.log_monitor.LogMonitorException):
mock_log_monitor().monitor_log_for_lines(['foo', 'not bar'], [''])
@mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock)
@mock.patch('os.path.exists')
def test_Monitor_NoLogPathExists_RaiseLogMonitorException(self, mock_path_exists):
mock_path_exists.return_value = False
with pytest.raises(ly_test_tools.log.log_monitor.LogMonitorException):
mock_log_monitor().monitor_log_for_lines([''], [''])
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_Monitor_InvalidLauncherType_RaiseLogMonitorException(self):
invalid_log_monitor = ly_test_tools.log.log_monitor.LogMonitor(
launcher=NotALauncher, log_file_path='mock_path')
with pytest.raises(ly_test_tools.log.log_monitor.LogMonitorException):
invalid_log_monitor.monitor_log_for_lines(['foo'], [''])
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_Monitor_NoneTypeUnexpectedLines_CastsToList(self):
mock_file = io.StringIO(u'foo\n')
mock_launcher.is_alive.side_effect = [True, True, True, False]
with mock.patch('ly_test_tools.log.log_monitor.open', return_value=mock_file, create=True):
mock_log_monitor().monitor_log_for_lines(['foo'], None)
@mock.patch('ly_test_tools.log.log_monitor.logging.Logger.warning')
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_Monitor_NoneTypeExpectedLines_LogsWarningAndCastsToList(self, mock_log_warning):
mock_file = io.StringIO(u'foo\n')
mock_launcher.is_alive.side_effect = [True, True, True, False]
with mock.patch('ly_test_tools.log.log_monitor.open', return_value=mock_file, create=True):
mock_log_monitor().monitor_log_for_lines(None, ['bar'])
mock_log_warning.assert_called_once()
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_Monitor_ExpectedLinesExactMatch_SucceedsOnExactMatch(self):
mock_file = io.StringIO(u'exact match\n')
mock_launcher.is_alive.side_effect = [True, True, True, False]
with mock.patch('ly_test_tools.log.log_monitor.open', return_value=mock_file, create=True):
mock_log_monitor().monitor_log_for_lines(['exact match', 'exact', 'match'], [])
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
def test_Monitor_ExpectedLinesPartialMatch_RaisesLogMonitorException(self):
mock_file = io.StringIO(u'exactlyy\n')
mock_launcher.is_alive.side_effect = [True, True, True, False]
with mock.patch('ly_test_tools.log.log_monitor.open', return_value=mock_file, create=True):
with pytest.raises(ly_test_tools.log.log_monitor.LogMonitorException):
mock_log_monitor().monitor_log_for_lines(['exactly'], [])
def test_ValidateResults_Valid_ReturnsTrue(self):
mock_lm = mock_log_monitor()
mock_expected_lines = ['expected_foo']
mock_unexpected_lines = ['unexpected_foo']
mock_expected_lines_not_found = []
mock_unexpected_lines_found = []
under_test = mock_lm._validate_results(mock_expected_lines_not_found, mock_unexpected_lines_found,
mock_expected_lines, mock_unexpected_lines)
assert under_test
def test_ValidateResults_ExpectedLineNotFound_RaisesException(self):
mock_lm = mock_log_monitor()
mock_expected_lines = ['expected_foo']
mock_unexpected_lines = ['unexpected_foo']
mock_expected_lines_not_found = ['expected_foo']
mock_unexpected_lines_found = []
with pytest.raises(ly_test_tools.log.log_monitor.LogMonitorException):
mock_lm._validate_results(mock_expected_lines_not_found, mock_unexpected_lines_found, mock_expected_lines,
mock_unexpected_lines)
def test_ValidateResults_UnexpectedLineFound_RaisesException(self):
mock_lm = mock_log_monitor()
mock_expected_lines = ['expected_foo']
mock_unexpected_lines = ['unexpected_foo']
mock_expected_lines_not_found = []
mock_unexpected_lines_found = ['unexpected_foo']
with pytest.raises(ly_test_tools.log.log_monitor.LogMonitorException):
mock_lm._validate_results(mock_expected_lines_not_found, mock_unexpected_lines_found, mock_expected_lines,
mock_unexpected_lines)
def test_ValidateResults_ExpectedNotFoundAndUnexpectedFound_RaisesException(self):
mock_lm = mock_log_monitor()
mock_expected_lines = ['expected_foo']
mock_unexpected_lines = ['unexpected_foo']
mock_expected_lines_not_found = ['expected_foo']
mock_unexpected_lines_found = ['unexpected_foo']
with pytest.raises(ly_test_tools.log.log_monitor.LogMonitorException):
mock_lm._validate_results(mock_expected_lines_not_found, mock_unexpected_lines_found, mock_expected_lines,
mock_unexpected_lines)
@@ -0,0 +1,38 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit tests for ly_test_tools._internal.managers.ly_process_killer
"""
import unittest.mock as mock
import pytest
import ly_test_tools._internal.managers.ly_process_killer
pytestmark = pytest.mark.SUITE_smoke
class TestProcessKiller(object):
@mock.patch('ly_test_tools.environment.process_utils.process_exists')
def test_DetectLumberyardProcesses_ValidProcessesList_ReturnsDetectedProcessesList(self, mock_process_exists):
mock_process_exists.side_effect = [True, False]
mock_process_list = ['foo', 'bar']
under_test = ly_test_tools._internal.managers.ly_process_killer.detect_lumberyard_processes(
processes_list=mock_process_list)
assert under_test == ['foo']
def test_KillProcesses_ProcessesListIsNotList_RaisesLyProcessKillerException(self):
with pytest.raises(ly_test_tools._internal.managers.ly_process_killer.LyProcessKillerException):
ly_test_tools._internal.managers.ly_process_killer.kill_processes(processes_list={})
@@ -0,0 +1,99 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit tests for ly_test_tools._internal.managers.platforms.mac
"""
import unittest.mock as mock
import os
import pytest
from ly_test_tools._internal.managers.platforms.mac import (
_MacResourceLocator, MacWorkspaceManager,
CACHE_DIR, CONFIG_FILE)
from ly_test_tools import MAC
pytestmark = pytest.mark.SUITE_smoke
if not MAC:
pytestmark = pytest.mark.skipif(
not MAC,
reason="test_manager_platforms_mac.py only runs on Mac")
mock_engine_root = 'mock_engine_root'
mock_dev_path = 'mock_dev_path'
mock_build_directory = 'mock_build_directory'
mock_project = 'mock_project'
mock_tmp_path = 'mock_tmp_path'
mock_output_path = 'mock_output_path'
mac_resource_locator = _MacResourceLocator(
build_directory=mock_build_directory,
project=mock_project)
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator._find_engine_root',
mock.MagicMock(return_value=(mock_engine_root, mock_dev_path)))
class TestMacResourceLocator(object):
def test_PlatformConfigFile_HasPath_ReturnsPath(self):
expected = os.path.join(
mac_resource_locator.dev(),
CONFIG_FILE)
assert mac_resource_locator.platform_config_file() == expected
def test_PlatformCache_HasPath_ReturnsPath(self):
expected = os.path.join(
mac_resource_locator.project_cache(),
CACHE_DIR)
assert mac_resource_locator.platform_cache() == expected
def test_ProjectLog_HasPath_ReturnsPath(self):
expected = os.path.join(
mac_resource_locator.platform_cache(),
'user',
'log')
assert mac_resource_locator.project_log() == expected
def test_ProjectScreenshots_HasPath_ReturnsPath(self):
expected = os.path.join(
mac_resource_locator.platform_cache(),
'user',
'ScreenShots')
assert mac_resource_locator.project_screenshots() == expected
def test_EditorLog_HasPath_ReturnsPath(self):
expected = os.path.join(
mac_resource_locator.project_log(),
'editor.log')
assert mac_resource_locator.editor_log() == expected
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator._find_engine_root',
mock.MagicMock(return_value=(mock_engine_root, mock_dev_path)))
class TestMacWorkspaceManager(object):
def test_Init_SetDummyParams_ReturnsMacWorkspaceManager(self):
mac_workspace_manager = MacWorkspaceManager(
build_directory=mock_build_directory,
project=mock_project,
tmp_path=mock_tmp_path,
output_path=mock_output_path)
assert type(mac_workspace_manager) == MacWorkspaceManager
assert mac_workspace_manager.paths.build_directory() == mock_build_directory
assert mac_workspace_manager.paths._project == mock_project
assert mac_workspace_manager.tmp_path == mock_tmp_path
assert mac_workspace_manager.output_path == mock_output_path
@@ -0,0 +1,103 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit tests for ly_test_tools._internal.managers.platforms.windows
"""
import unittest.mock as mock
import os
import pytest
from ly_test_tools._internal.managers.platforms.windows import (
_WindowsResourceLocator, WindowsWorkspaceManager,
CACHE_DIR, CONFIG_FILE)
from ly_test_tools import WINDOWS
pytestmark = pytest.mark.SUITE_smoke
if not WINDOWS:
pytestmark = pytest.mark.skipif(
not WINDOWS,
reason="test_manager_platforms_windows.py only runs on Windows")
mock_engine_root = 'mock_engine_root'
mock_dev_path = 'mock_dev_path'
mock_build_directory = 'mock_build_directory'
mock_project = 'mock_project'
mock_tmp_path = 'mock_tmp_path'
mock_output_path = 'mock_output_path'
windows_resource_locator = _WindowsResourceLocator(
build_directory=mock_build_directory,
project=mock_project)
windows_workspace_manager = WindowsWorkspaceManager(
build_directory=mock_build_directory,
project=mock_project,
tmp_path=mock_tmp_path,
output_path=mock_output_path)
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator._find_engine_root',
mock.MagicMock(return_value=(mock_engine_root, mock_dev_path)))
class TestWindowsResourceLocator(object):
def test_PlatformConfigFile_HasPath_ReturnsPath(self):
expected = os.path.join(
windows_resource_locator.dev(),
CONFIG_FILE)
assert windows_resource_locator.platform_config_file() == expected
def test_PlatformCache_HasPath_ReturnsPath(self):
expected = os.path.join(
windows_resource_locator.project_cache(), CACHE_DIR)
assert windows_resource_locator.platform_cache() == expected
def test_ProjectLog_HasPath_ReturnsPath(self):
expected = os.path.join(
windows_resource_locator.platform_cache(),
'user',
'log')
assert windows_resource_locator.project_log() == expected
def test_ProjectScreenshots_HasPath_ReturnsPath(self):
expected = os.path.join(
windows_resource_locator.platform_cache(),
'user',
'ScreenShots')
assert windows_resource_locator.project_screenshots() == expected
def test_EditorLog_HasPath_ReturnsPath(self):
expected = os.path.join(
windows_resource_locator.project_log(),
'editor.log')
assert windows_resource_locator.editor_log() == expected
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator._find_engine_root',
mock.MagicMock(return_value=(mock_engine_root, mock_dev_path)))
class TestWindowsWorkspaceManager(object):
@mock.patch('ly_test_tools.environment.reg_cleaner.create_ly_keys')
def test_SetRegistryKeys_NewWorkspaceManager_KeyCreateCalled(self, mock_create_keys):
windows_workspace_manager.set_registry_keys()
mock_create_keys.assert_called_once()
@mock.patch('ly_test_tools.environment.reg_cleaner.clean_ly_keys')
def test_ClearSettings_NewWorkspaceManager_KeyClearCalled(self, mock_clear_keys):
windows_workspace_manager.clear_settings()
mock_clear_keys.assert_called_with(exception_list=r"SOFTWARE\Amazon\Lumberyard\Identity")
@@ -0,0 +1,359 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import unittest.mock as mock
import psutil
import pytest
import subprocess
import unittest
import ly_test_tools.environment.process_utils as process_utils
from ly_test_tools import WINDOWS
pytestmark = pytest.mark.SUITE_smoke
class TestSubprocessCheckOutputWrapper(unittest.TestCase):
@mock.patch('subprocess.check_output')
@mock.patch('logging.Logger.error')
def test_CheckOutput_FailingCommand_UsesCorrectLoggingLevel(self, mock_log_err, mock_sub_output):
mock_sub_output.side_effect = subprocess.CalledProcessError(1, 'cmd', 'output')
cmd = ['test', 'cmd']
with pytest.raises(subprocess.CalledProcessError):
process_utils.check_output(cmd)
mock_log_err.assert_called_once()
@mock.patch('subprocess.check_output')
@mock.patch('logging.Logger.info')
def test_CheckOutput_SuccessfulCommand_UsesCorrectLoggingLevel(self, mock_log_info, mock_sub_output):
mock_sub_output.return_value = 'Output returned successfully'.encode()
cmd = ['test', 'cmd']
expected_logger_info_calls = 2
process_utils.check_output(cmd)
self.assertEqual(expected_logger_info_calls, mock_log_info.call_count)
@mock.patch('subprocess.check_output')
def test_CheckOutput_FailingCommand_RaisesCalledProcessError(self, mock_sub_output):
mock_sub_output.side_effect = subprocess.CalledProcessError(1, 'cmd', 'output')
cmd = ['test', 'cmd']
with self.assertRaises(subprocess.CalledProcessError):
process_utils.check_output(cmd)
@mock.patch('subprocess.check_output')
def test_CheckOutput_CmdPassedAsString_ReturnsOutput(self, mock_sub_output):
expected_output = 'Output returned successfully'
mock_sub_output.return_value = expected_output.encode()
cmd = 'test cmd'
actual_output = process_utils.check_output(cmd)
mock_sub_output.assert_called_once()
self.assertEqual(expected_output, actual_output)
class TestSubprocessCheckOutputWrapperSafe(unittest.TestCase):
@mock.patch('subprocess.check_output')
@mock.patch('logging.Logger.warning')
def test_SafeCheckOutput_FailingCommand_UsesCorrectLoggingLevel(self, mock_log_warn, mock_sub_output):
mock_sub_output.side_effect = subprocess.CalledProcessError(1, 'cmd', 'output')
cmd = ['test', 'cmd']
process_utils.safe_check_output(cmd)
mock_log_warn.assert_called_once()
@mock.patch('subprocess.check_output')
@mock.patch('logging.Logger.info')
def test_SafeCheckOutput_SuccessfulCommand_UsesCorrectLoggingLevel(self, mock_log_info, mock_sub_output):
mock_sub_output.return_value = 'Output returned successfully'.encode()
cmd = ['test', 'cmd']
expected_logger_info_calls = 2
process_utils.check_output(cmd)
self.assertEqual(expected_logger_info_calls, mock_log_info.call_count)
@mock.patch('subprocess.check_output')
def test_SafeCheckOutput_FailingCommand_ReturnsOutput(self, mock_sub_output):
expected_output = 'Output returned successfully'
mock_sub_output.side_effect = subprocess.CalledProcessError(1, 'cmd', expected_output)
cmd = ['test', 'cmd']
actual_output = process_utils.safe_check_output(cmd)
mock_sub_output.assert_called_once()
self.assertEqual(expected_output, actual_output)
@mock.patch('subprocess.check_output')
def test_SafeCheckOutput_CmdPassedAsString_ReturnsOutput(self, mock_sub_output):
expected_output = 'Output returned successfully'
mock_sub_output.return_value = expected_output.encode()
cmd = 'test cmd'
actual_output = process_utils.safe_check_output(cmd)
mock_sub_output.assert_called_once()
self.assertEqual(expected_output, actual_output)
class TestSubprocessCheckCallWrapper(unittest.TestCase):
@mock.patch('subprocess.check_call')
@mock.patch('logging.Logger.error')
def test_CheckCall_FailingCommand_UsesCorrectLoggingLevel(self, mock_log_err, mock_sub_call):
mock_sub_call.side_effect = subprocess.CalledProcessError(1, 'cmd', 'output')
cmd = ['test', 'cmd']
with pytest.raises(subprocess.CalledProcessError):
process_utils.check_call(cmd)
mock_log_err.assert_called_once()
@mock.patch('subprocess.check_call')
@mock.patch('logging.Logger.info')
def test_CheckOutput_SuccessfulCommand_UsesCorrectLoggingLevel(self, mock_log_info, mock_sub_call):
mock_sub_call.return_value = 0
cmd = ['test', 'cmd']
expected_logger_info_calls = 2
process_utils.check_call(cmd)
self.assertEqual(expected_logger_info_calls, mock_log_info.call_count)
@mock.patch('subprocess.check_call')
def test_CheckCall_FailingCommand_RaisesCalledProcessError(self, mock_sub_call):
mock_sub_call.side_effect = subprocess.CalledProcessError(1, 'cmd', 'output')
cmd = ['test', 'cmd']
with self.assertRaises(subprocess.CalledProcessError):
process_utils.check_call(cmd)
mock_sub_call.assert_called_once()
@mock.patch('subprocess.check_call')
def test_CheckCall_CmdPassedAsString_ReturnsSuccess(self, mock_sub_call):
expected_retcode = 0
mock_sub_call.returncode = expected_retcode
cmd = 'test cmd'
actual_retcode = process_utils.check_call(cmd)
mock_sub_call.assert_called_once()
self.assertEqual(expected_retcode, actual_retcode)
class TestSubprocessCheckCallWrapperSafe(unittest.TestCase):
@mock.patch('subprocess.check_call')
@mock.patch('logging.Logger.warning')
def test_SafeCheckCall_FailingCommand_UsesCorrectLoggingLevel(self, mock_log_warn, mock_sub_call):
mock_sub_call.side_effect = subprocess.CalledProcessError(1, 'cmd', 'output')
cmd = ['test', 'cmd']
process_utils.safe_check_call(cmd)
mock_log_warn.assert_called_once()
@mock.patch('subprocess.check_call')
@mock.patch('logging.Logger.info')
def test_CheckOutput_SuccessfulCommand_UsesCorrectLoggingLevel(self, mock_log_info, mock_sub_call):
mock_sub_call.return_value = 0
cmd = ['test', 'cmd']
expected_logger_info_calls = 2
process_utils.safe_check_call(cmd)
self.assertEqual(expected_logger_info_calls, mock_log_info.call_count)
@mock.patch('subprocess.check_call')
def test_SafeCheckCall_FailingCommand_ReturnsFailureCode(self, mock_sub_call):
expected_retcode = 1
mock_sub_call.side_effect = subprocess.CalledProcessError(expected_retcode, 'cmd', 'output')
cmd = ['test', 'cmd']
actual_retcode = process_utils.safe_check_call(cmd)
mock_sub_call.assert_called_once()
self.assertEqual(expected_retcode, actual_retcode)
@mock.patch('subprocess.check_call')
def test_SafeCheckCall_CmdPassedAsString_ReturnsSuccess(self, mock_sub_call):
expected_retcode = 0
mock_sub_call.returncode = expected_retcode
cmd = 'test cmd'
actual_retcode = process_utils.safe_check_call(cmd)
mock_sub_call.assert_called_once()
self.assertEqual(expected_retcode, actual_retcode)
@pytest.mark.skipif(
not WINDOWS,
reason="tests.unit.test_process_utils is restricted to the Windows platform.")
class TestCloseWindowsProcess(unittest.TestCase):
@mock.patch('ly_test_tools.environment.process_utils.WINDOWS', False)
def test_CloseWindowsProccess_NotOnWindows_Error(self):
with pytest.raises(NotImplementedError):
process_utils.close_windows_process(1)
def test_CloseWindowsProccess_IdNone_Error(self):
with pytest.raises(TypeError):
process_utils.close_windows_process(None)
@mock.patch('psutil.Process')
def test_CloseWindowsProccess_ProcDNE_Error(self, mock_psutil):
mock_proc = mock.MagicMock()
mock_proc.is_running.return_value = False
mock_psutil.return_value = mock_proc
with pytest.raises(TypeError):
process_utils.close_windows_process(None)
@mock.patch('psutil.Process')
@mock.patch('ctypes.windll.user32.EnumWindows')
@mock.patch('ctypes.windll', mock.MagicMock())
@mock.patch('ly_test_tools.environment.waiter.wait_for', mock.MagicMock())
def test_CloseProcess_MockedWindll_VerifyMock(self, mock_enum, mock_psutil):
mock_proc = mock.MagicMock()
mock_proc.is_running.return_value = True
mock_psutil.return_value = mock_proc
process_utils.close_windows_process(3)
mock_enum.assert_called_once()
class Test(unittest.TestCase):
@mock.patch("ly_test_tools.environment.process_utils._safe_get_processes")
def test_ProcExists_HasExtension_Found(self, mock_get_proc):
name = "dummy.exe"
proc_mock = mock.MagicMock()
proc_mock.name.return_value = name
mock_get_proc.return_value = [proc_mock]
result = process_utils.process_exists(name)
self.assertTrue(result)
proc_mock.name.assert_called()
@mock.patch("ly_test_tools.environment.process_utils._safe_get_processes")
def test_ProcExists_NoExtension_Ignored(self, mock_get_proc):
name = "dummy.exe"
proc_mock = mock.MagicMock()
proc_mock.name.return_value = name
mock_get_proc.return_value = [proc_mock]
result = process_utils.process_exists("dummy")
self.assertFalse(result)
proc_mock.name.assert_called()
@mock.patch("ly_test_tools.environment.process_utils._safe_get_processes")
def test_ProcExistsIgnoreExtension_NoExtension_Found(self, mock_get_proc):
name = "dummy.exe"
proc_mock = mock.MagicMock()
proc_mock.name.return_value = name
mock_get_proc.return_value = [proc_mock]
result = process_utils.process_exists("dummy", ignore_extensions=True)
self.assertTrue(result)
proc_mock.name.assert_called()
@mock.patch('ly_test_tools.environment.process_utils._safe_kill_process', mock.MagicMock)
@mock.patch('ly_test_tools.environment.process_utils._safe_get_processes')
def test_KillProcNamed_MockKill_SilentSuccess(self, mock_get_proc):
name = "dummy.exe"
proc_mock = mock.MagicMock()
proc_mock.name.return_value = name
mock_get_proc.return_value = [proc_mock]
process_utils.kill_processes_named("dummy", ignore_extensions=True)
proc_mock.name.assert_called()
@mock.patch('ly_test_tools.environment.process_utils._safe_kill_process', mock.MagicMock)
@mock.patch('ly_test_tools.environment.process_utils._safe_get_processes')
@mock.patch('os.path.exists')
def test_KillProcFrom_MockKill_SilentSuccess(self, mock_path, mock_get_proc):
mock_path.return_value = True
proc_mock = mock.MagicMock()
mock_get_proc.return_value = [proc_mock]
process_utils.kill_processes_started_from("dummy_path")
@mock.patch('ly_test_tools.environment.process_utils._safe_kill_process')
@mock.patch('psutil.Process')
def test_KillProcPid_ProcRunning_Killed(self, mock_psutil, mock_kill):
mock_proc = mock.MagicMock()
mock_proc.is_running.return_value = True
mock_psutil.return_value = mock_proc
process_utils.kill_process_with_pid(1)
mock_kill.assert_called()
@mock.patch('ly_test_tools.environment.process_utils._safe_kill_process', mock.MagicMock)
@mock.patch('psutil.Process')
def test_KillProcPid_NoProc_SilentPass(self, mock_psutil):
mock_proc = mock.MagicMock()
mock_proc.is_running.return_value = False
mock_psutil.return_value = mock_proc
process_utils.kill_process_with_pid(1)
@mock.patch('ly_test_tools.environment.process_utils._safe_kill_process', mock.MagicMock)
@mock.patch('psutil.Process')
def test_KillProcPidRaiseOnMissing_NoProc_Raises(self, mock_psutil):
mock_proc = mock.MagicMock()
mock_proc.is_running.return_value = False
mock_psutil.return_value = mock_proc
with self.assertRaises(RuntimeError):
process_utils.kill_process_with_pid(1, raise_on_missing=True)
def test_SafeKillProc_HappyPath_Success(self):
proc_mock = mock.MagicMock()
proc_mock.is_running.return_value = False
process_utils._safe_kill_process(proc_mock)
proc_mock.kill.assert_called()
proc_mock.is_running.assert_called()
@mock.patch('ly_test_tools.environment.waiter.wait_for')
@mock.patch('logging.Logger.warning')
def test_SafeKillProc_KillRetriesFail_LogsFailure(self, mock_log_warn, mock_wait):
mock_wait.side_effect = psutil.AccessDenied()
proc_mock = mock.MagicMock()
process_utils._safe_kill_process(proc_mock)
proc_mock.kill.assert_called()
mock_wait.assert_called()
mock_log_warn.assert_called()
@mock.patch('psutil.process_iter')
@mock.patch('logging.Logger.debug')
def test_SafeGetProc_CannotAccess_LogAndReturnNone(self, mock_log_debug, mock_psiter):
mock_psiter.side_effect = psutil.Error()
under_test = process_utils._safe_get_processes()
self.assertIsNone(under_test)
mock_log_debug.assert_called()
@mock.patch('psutil.process_iter')
@mock.patch('logging.Logger.debug')
def test_SafeGetProc_HappyPathDummy_ReturnDummy(self, mock_log_debug, mock_psiter):
dummy = object()
mock_psiter.return_value = dummy
under_test = process_utils._safe_get_processes()
self.assertIs(under_test, dummy)
mock_log_debug.assert_not_called()
@@ -0,0 +1,108 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import pytest
import unittest.mock as mock
from pytest_mock import MockFixture
import ly_test_tools._internal.log.py_logging_util as py_logging_util
pytestmark = pytest.mark.SUITE_smoke
class TestTerminateLogging(object):
def test_TerminateLogging_HandlersUninitialized_NoHandlersRemoved(self, mocker):
# type: (MockFixture) -> None
mock_getLogger = mocker.patch("logging.getLogger") # type: MagicMock
mock_removeHandler = mock_getLogger.return_value.removeHandler # type: MagicMock
py_logging_util.terminate_logging()
mock_removeHandler.assert_not_called()
def test_TerminateLogging_HandlersInitialized_HandlersRemoved(self, mocker):
# type: (MockFixture) -> None
mock_getLogger = mocker.patch("logging.getLogger") # type: MagicMock
mock_removeHandler = mock_getLogger.return_value.removeHandler # type: MagicMock
mock_stream_handler = "Mock Stream Handler"
mock_info_file_handler = "Mock Info File Handler"
mock_debug_file_handler = "Mock Debug File Handler"
py_logging_util._stream_handler = mock_stream_handler
py_logging_util._info_file_handler = mock_info_file_handler
py_logging_util._debug_file_handler = mock_debug_file_handler
py_logging_util.terminate_logging()
calls = [
mock.call(mock_stream_handler),
mock.call(mock_info_file_handler),
mock.call(mock_debug_file_handler),
]
mock_removeHandler.assert_has_calls(calls)
class TestInitializeLogging(object):
@mock.patch("logging.getLogger", scope='module')
def test_InitializeLogging_AddHandlerCalled_CalledThrice(self, mock_get_logger):
dummy_log_path = "dummy_log_path"
dummy_info_path = "dummy_info_path"
py_logging_util._stream_handler = None
py_logging_util._info_file_handler = None
py_logging_util._debug_file_handler = None
mock_add_handler = mock_get_logger.return_value.addHandler
py_logging_util.initialize_logging(dummy_info_path, dummy_log_path)
assert mock_add_handler.call_count == 3
py_logging_util.terminate_logging()
@mock.patch("logging.getLogger", scope='module')
def test_InitializeLogging_CheckLoggerCalled_LoggerCalledOnce(self, mock_get_logger):
dummy_log_path = "dummy_path"
dummy_info_path = "dummy_path"
py_logging_util.initialize_logging(dummy_info_path, dummy_log_path)
mock_get_logger.assert_called_once()
@mock.patch("logging.getLogger", scope='module')
def test_InitializeLogging_SetLogLevelValidArgs_ValidArgsPassed(self, mock_get_logger):
dummy_log_path = "dummy_path"
dummy_info_path = "dummy_path"
mock_setLevel = mock_get_logger.return_value.setLevel
py_logging_util.initialize_logging(dummy_info_path, dummy_log_path)
mock_setLevel.assert_called_with(10) # logging.DEBUG = 10
def test_InitializeLogging_CheckHandlerInitialized_HandlerNotNone(self):
dummy_log_path = "dummy_path"
dummy_info_path = "dummy_path"
py_logging_util.initialize_logging(dummy_info_path,dummy_log_path)
assert py_logging_util._debug_file_handler is not None
assert py_logging_util._info_file_handler is not None
assert py_logging_util._stream_handler is not None
@mock.patch("logging.StreamHandler.setFormatter", scope='module')
def test_InitializeLogging_CheckFormatting_HandlerFormattingIsCorrect(self,mock_stream_handler_formatter):
dummy_log_path = "dummy_path"
dummy_info_path = "dummy_path"
py_logging_util._stream_handler = None
py_logging_util._info_file_handler = None
py_logging_util._debug_file_handler = None
py_logging_util.initialize_logging(dummy_info_path,dummy_log_path)
#example of formatted string : 7024.00016785 - DEBUG - [MainThread] - ly_test_tools.launchers.platforms.win.launcher - Initialized Windows Launcher
format_string = "%(relativeCreated)s - %(levelname)s - [%(threadName)s] - %(name)s - %(message)s"
assert mock_stream_handler_formatter.call_args[0][0]._fmt == format_string
@@ -0,0 +1,92 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit Tests for ~/ly_test_tools/report/rad_telemetry.py
"""
import unittest.mock as mock
import os
import pytest
import ly_test_tools.report.rad_telemetry
from ly_test_tools import WINDOWS
pytestmark = pytest.mark.SUITE_smoke
_RAD_DEFAULT_PORT = 4719
_CREATE_NEW_PROCESS_GROUP = 0x00000200
_DETACHED_PROCESS = 0x00000008
_WINDOWS_FLAGS = _CREATE_NEW_PROCESS_GROUP | _DETACHED_PROCESS
RAD_TOOLS_SUBPATH = os.path.join("dev", "Gems", "RADTelemetry", "Tools")
@pytest.mark.skipif(
not WINDOWS,
reason="tests.unit.test_rad_telemetry is restricted to the Windows platform.")
class TestRADTelemetry:
@mock.patch('ly_test_tools.environment.process_utils.check_call')
@mock.patch('ly_test_tools.environment.process_utils.safe_check_call')
def test_SetFirewallRules_ShowRuleResultNotZero_CallsAddRule(self, mock_safe_call, mock_call):
ly_test_tools.report.rad_telemetry.set_firewall_rules()
mock_safe_call.call_args_list = [
mock.call(['netsh', 'advfirewall', 'firewall', 'show', 'rule', 'name=RADTelemetry', 'dir=in']),
mock.call(['netsh', 'advfirewall', 'firewall', 'show', 'rule', 'name=RADTelemetry', 'dir=out']),
]
mock_call.call_args_list = [
mock.call(
['netsh', 'advfirewall', 'firewall', 'add', 'rule', 'name=RADTelemetry', 'dir=in',
'action=allow', 'protocol=TCP', 'localport={}'.format(_RAD_DEFAULT_PORT)]),
mock.call(
['netsh', 'advfirewall', 'firewall', 'add', 'rule', 'name=RADTelemetry', 'dir=out',
'action=allow', 'protocol=TCP', 'localport={}'.format(_RAD_DEFAULT_PORT)]),
]
assert mock_call.call_count == 2
assert mock_safe_call.call_count == 2
@mock.patch('ly_test_tools.environment.process_utils.check_call')
@mock.patch('ly_test_tools.environment.process_utils.safe_check_call')
def test_SetFirewallRules_ShowRuleResultEqualsZero_AddRuleNotCalled(self, mock_safe_call, mock_call):
mock_safe_call.return_value = 0
ly_test_tools.report.rad_telemetry.set_firewall_rules()
mock_call.assert_not_called()
assert mock_safe_call.call_count == 2
@mock.patch('subprocess.Popen')
def test_LaunchServer_ValidDevPath_PopenSuccess(self, mock_popen):
mock_server_path = os.path.join('dev_path', RAD_TOOLS_SUBPATH, "tm_server.exe")
ly_test_tools.report.rad_telemetry.launch_server('dev_path')
mock_popen.assert_called_once_with([mock_server_path], creationflags=_WINDOWS_FLAGS, close_fds=True)
@mock.patch('ly_test_tools.environment.process_utils.kill_processes_started_from')
def test_TerminateServer_ValidDevPath_KillsRADProcess(self, mock_kill_process):
mock_rad_path = os.path.join('dev_path', RAD_TOOLS_SUBPATH)
ly_test_tools.report.rad_telemetry.terminate_servers('dev_path')
mock_kill_process.assert_called_once_with(mock_rad_path)
@mock.patch('ly_test_tools.environment.process_utils.check_output')
def test_TerminateServer_ValidDevPath_KillsRADProcess(self, mock_call):
mock_get_folder_path = os.path.join('dev_path', RAD_TOOLS_SUBPATH, "tm_server.exe")
mock_call.return_value = 'test'
under_test = ly_test_tools.report.rad_telemetry.get_capture_path('dev_path')
mock_call.assert_called_once_with([mock_get_folder_path])
assert under_test == 'test'
@@ -0,0 +1,93 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import pytest
from pytest_mock import MockFixture
import ly_test_tools.environment.reg_cleaner
from ly_test_tools import WINDOWS
pytestmark = pytest.mark.SUITE_smoke
if not WINDOWS:
pytestmark = pytest.mark.skipif(
not WINDOWS,
reason="tests.unit.test_reg_cleaner is restricted to the Windows platform.")
def test_DeleteKey_KeyDoesNotExist_SilentlyFails(mocker):
# type: (MockFixture) -> None
mock_delete_child_keys_and_values = mocker.patch(
"ly_test_tools.environment.reg_cleaner._delete_child_keys_and_values")
mock_delete_child_keys_and_values.side_effect = WindowsError
ly_test_tools.environment.reg_cleaner._delete_key("key_1")
def test_DeleteKey_KeyIsEmpty_KeyDeleted(mocker):
# type: (MockFixture) -> None
mockwinreg = mocker.patch("ly_test_tools.environment.reg_cleaner.winreg")
mock_delete_child_keys_and_values = mocker.patch(
"ly_test_tools.environment.reg_cleaner._delete_child_keys_and_values")
mock_delete_child_keys_and_values.return_value = True
ly_test_tools.environment.reg_cleaner._delete_key("key_1")
assert mockwinreg.DeleteKey.called
def test_DeleteKey_KeyIsNotEmpty_KeyNotDeleted(mocker):
# type: (MockFixture) -> None
mockwinreg = mocker.patch("ly_test_tools.environment.reg_cleaner.winreg")
mock_delete_child_keys_and_values = mocker.patch(
"ly_test_tools.environment.reg_cleaner._delete_child_keys_and_values")
mock_delete_child_keys_and_values.return_value = False
ly_test_tools.environment.reg_cleaner._delete_key("key_1")
assert not mockwinreg.DeleteKey.called
def test_DeleteChildKeysAndValues_KeyDoesNotExist_RaisesWindowsError(mocker):
# type: (MockFixture) -> None
mockwinreg = mocker.patch("ly_test_tools.environment.reg_cleaner.winreg")
mockwinreg.OpenKey.side_effect = WindowsError
with pytest.raises(WindowsError):
ly_test_tools.environment.reg_cleaner._delete_child_keys_and_values("key_1")
def test_DeleteChildKeysAndValues_KeyIsEmpty_ReturnsTrue(mocker):
# type: (MockFixture) -> None
mockwinreg = mocker.patch("ly_test_tools.environment.reg_cleaner.winreg")
mockwinreg.EnumKey.side_effect = WindowsError
mockwinreg.EnumValue.side_effect = WindowsError
assert ly_test_tools.environment.reg_cleaner._delete_child_keys_and_values("key_1")
def test_DeleteChildKeysAndValues_KeyWithNoChildrenInExceptionList_ReturnsTrue(mocker):
# type: (MockFixture) -> None
mockwinreg = mocker.patch("ly_test_tools.environment.reg_cleaner.winreg")
mockwinreg.EnumKey.side_effect = ["child_key_1", WindowsError, WindowsError]
mockwinreg.EnumValue.side_effect = [WindowsError, ("child_value_1", None, None), WindowsError]
assert ly_test_tools.environment.reg_cleaner._delete_child_keys_and_values("key_1")
def test_DeleteChildKeysAndValues_KeyWithChildrenInExceptionList_ReturnsFalse(mocker):
# type: (MockFixture) -> None
mockwinreg = mocker.patch("ly_test_tools.environment.reg_cleaner.winreg")
mockwinreg.EnumKey.side_effect = ["child_key_1", WindowsError]
mockwinreg.EnumValue.side_effect = [("child_value_1", None, None), WindowsError]
exception_list = ["key_1\\child_key_1", "key_1\\child_value_1"]
assert not ly_test_tools.environment.reg_cleaner._delete_child_keys_and_values("key_1", exception_list)
@@ -0,0 +1,104 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit test for ly_test_tools.image.screenshot_compare_qssim
"""
import unittest.mock as mock
import numpy as np
import pytest
import ly_test_tools.image.screenshot_compare_qssim as screenshot_compare
pytestmark = pytest.mark.SUITE_smoke
class TestScreenshotCompare(object):
def test_QuaternionMatrixConj_4x3Matrix_ValidConjugate(self):
given_matrix = np.array([[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10 , 11, 12]]])
expected_conjugateMatrix = np.array([[[1, -2, -3, -4], [5, -6, -7, -8], [9, -10, -11, -12]]])
result_conjugateMatrix = screenshot_compare._quaternion_matrix_conj(given_matrix)
assert np.array_equal(result_conjugateMatrix,expected_conjugateMatrix)
def test_QuaternionMatrixDot_4x3matrix_ValidDotProduct(self):
given_matrix = np.array([[[0, 0, 0, 2], [0, 0, 4, 0], [0, 0, 8, 0]]])
expected_answer = np.array([[2, 4, 8]])
result_matrix = screenshot_compare._quaternion_matrix_dot(given_matrix, given_matrix)
assert np.array_equal(expected_answer,result_matrix)
@mock.patch('ly_test_tools.image.screenshot_compare_qssim._quaternion_matrix_dot')
def test_QuaternionMatrixNorm_DotProductUsed_AssertDotProductCalled(self, mock_matrixDotProduct):
given_matrix = np.array([[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]])
screenshot_compare._quaternion_matrix_norm(given_matrix)
mock_matrixDotProduct.assert_called_once()
mock_matrixDotProduct.assert_called_with(given_matrix,given_matrix)
@mock.patch('ly_test_tools.image.screenshot_compare_qssim._quaternion_matrix_norm')
def test_QuaternionMatrixDivide_NormCalledForSecondMatrix_AssertNormCalled(self, mock_matrixNorm):
matrix_a = np.array([[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]])
matrix_b = np.array([[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]])
mock_matrixNorm.return_value = np.array([[1,2,3]])
screenshot_compare._quaternion_matrix_div(matrix_a, matrix_b)
mock_matrixNorm.assert_called_with(matrix_b)
@mock.patch('numpy.divide',mock.MagicMock())
@mock.patch('ly_test_tools.image.screenshot_compare_qssim._quaternion_matrix_mult',mock.MagicMock())
@mock.patch('ly_test_tools.image.screenshot_compare_qssim._quaternion_matrix_conj')
def test_QuaternionMatrixDivide_ConjugateCalledForSecondMatrix_AssertConjugateCalled(self, mock_matrixConjugate):
matrix_a = np.array([[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]])
matrix_b = np.array([[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]])
screenshot_compare._quaternion_matrix_div(matrix_a, matrix_b)
mock_matrixConjugate.assert_called_with(matrix_b)
@mock.patch('numpy.divide',mock.MagicMock())
@mock.patch('ly_test_tools.image.screenshot_compare_qssim._quaternion_matrix_conj')
@mock.patch('ly_test_tools.image.screenshot_compare_qssim._quaternion_matrix_mult')
def test_QuaternionMatrixDivide_MultiplyCalledForMatAConjB_AssertMultiplyCalled(self, mock_matrixMultiply,mock_matrixConjugate):
matrix_a = np.array([[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]])
matrix_b = np.array([[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]])
mock_conjugate_return = np.array([[[1, -2, -3, -4], [5, -6, -7, -8], [9, -10, -11, -12]]])
mock_matrixConjugate.return_value = mock_conjugate_return
screenshot_compare._quaternion_matrix_div(matrix_a, matrix_b)
mock_matrixMultiply.assert_called_with(matrix_a,mock_conjugate_return)
@mock.patch('imageio.imread')
@mock.patch('imageio.imwrite',mock.MagicMock())
def test_qssim_CheckSameImage_ShouldReturnOne(self, mock_imageRead):
matrix_a = np.array([[[1, 2, 3], [4, 5, 6], [7, 8, 9]]])
matrix_b = np.array([[[1, 2, 3], [4, 5, 6], [7, 8, 9]]])
mock_imageRead.side_effect = [matrix_a,matrix_b]
assert screenshot_compare.qssim('test1.jpg', 'test2.jpg') == 1
@mock.patch('imageio.imread')
@mock.patch('imageio.imwrite',mock.MagicMock())
def test_qssim_CheckAlmostSameImage_GreaterThanHalf(self, mock_imageRead):
matrix_a = np.array([[[1, 2, 3], [4, 5, 6], [7, 8, 9]]])
matrix_b = np.array([[[1, 2, 3], [4, 5, 6], [7, 8, 19]]])
mock_imageRead.side_effect = [matrix_a,matrix_b]
assert screenshot_compare.qssim('test1.jpg', 'test2.jpg') > 0.5
@mock.patch('imageio.imread')
@mock.patch('imageio.imwrite',mock.MagicMock())
def test_qssim_CheckDifferentImage_ShouldNotReturnOne(self, mock_imageRead):
matrix_a = np.array([[[1, 2, 3], [4, 5, 6], [7, 8, 9]]])
matrix_b = np.array([[[11, 12, 13], [14, 15, 16], [17, 18, 19]]])
mock_imageRead.side_effect = [matrix_a,matrix_b]
assert screenshot_compare.qssim('test1.jpg', 'test2.jpg') != 1
@mock.patch('imageio.imread')
@mock.patch('imageio.imwrite')
def test_qssim_CheckDiffImageSaved_AssertImSave(self, mock_imageSave, mock_imageRead):
matrix_a = np.array([[[1, 2, 3], [4, 5, 6], [7, 8, 9]]])
matrix_b = np.array([[[1, 2, 3], [4, 5, 6], [7, 8, 9]]])
mock_imageRead.side_effect = [matrix_a,matrix_b]
screenshot_compare.qssim('test1.jpg', 'test2.jpg')
mock_imageSave.assert_called()
@@ -0,0 +1,160 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import unittest.mock as mock
import unittest
import pytest
import ly_test_tools.lumberyard.settings
pytestmark = pytest.mark.SUITE_smoke
class MockDocumentInput(object):
def __init__(self, lines):
self._lines = lines
def __iter__(self):
return (line for line in self._lines)
def close(self):
pass
class TestReplaceLineInFile(unittest.TestCase):
def setUp(self):
self.file_name = 'file1'
self.search_for = 'search_for'
self.replace_with = 'replace_with'
self.mock_file_content = [
"Setting1=Foo",
";Setting2=Bar",
"Setting3=Baz ",
"Setting4="]
@mock.patch('fileinput.input')
@mock.patch('os.path.isfile')
@mock.patch('logging.Logger.warning')
def test_ReplaceLineInFile_FileInUse_NoRaise(self, mock_log_warning, mock_path_isfile, mock_input):
mock_path_isfile.return_value = True
mock_input.side_effect = PermissionError()
try:
with mock.patch('__builtin__.open'):
ly_test_tools.lumberyard.settings._edit_text_settings_file(self.file_name, self.search_for, self.replace_with)
except ImportError:
with mock.patch('builtins.open'):
ly_test_tools.lumberyard.settings._edit_text_settings_file(self.file_name, self.search_for, self.replace_with)
mock_log_warning.assert_called_once()
@mock.patch('fileinput.input')
@mock.patch('os.path.isfile')
@mock.patch('logging.Logger.error')
def test_ReplaceLineInFile_Error_Raises(self, mock_log_error, mock_path_isfile, mock_input):
mock_path_isfile.return_value = True
mock_input.side_effect = NotImplementedError()
with pytest.raises(NotImplementedError):
try:
with mock.patch('__builtin__.open'):
ly_test_tools.lumberyard.settings._edit_text_settings_file(self.file_name, self.search_for, self.replace_with)
except ImportError:
with mock.patch('builtins.open'):
ly_test_tools.lumberyard.settings._edit_text_settings_file(self.file_name, self.search_for, self.replace_with)
@mock.patch('fileinput.input')
@mock.patch('os.path.isfile')
def test_ReplaceLineInFile_FileFound_NoRaise(self, mock_path_isfile, mock_input):
mock_path_isfile.return_value = True
try:
with mock.patch('__builtin__.open'):
ly_test_tools.lumberyard.settings._edit_text_settings_file(self.file_name, self.search_for, self.replace_with)
except ImportError:
with mock.patch('builtins.open'):
ly_test_tools.lumberyard.settings._edit_text_settings_file(self.file_name, self.search_for, self.replace_with)
mock_input.return_value.close.assert_called_once_with()
@mock.patch('os.path.isfile')
@mock.patch('fileinput.input')
@mock.patch('sys.stdout')
def test_ReplaceLineInFile_SettingMatch_SettingReplaced(self, mock_stdout, mock_input, mock_isfile):
mock_isfile.return_value = True
mock_input.return_value = MockDocumentInput(self.mock_file_content)
expected_print_lines = [
mock.call.write("Setting1=NewFoo"), mock.call.write('\n'),
mock.call.write(";Setting2=Bar"), mock.call.write('\n'),
mock.call.write("Setting3=Baz"), mock.call.write('\n'),
mock.call.write("Setting4="), mock.call.write('\n'),
]
ly_test_tools.lumberyard.settings._edit_text_settings_file(self.file_name, 'Setting1', 'NewFoo')
mock_stdout.assert_has_calls(expected_print_lines)
@mock.patch('os.path.isfile')
@mock.patch('fileinput.input')
@mock.patch('sys.stdout')
def test_ReplaceLineInFile_CommentedSettingMatch_SettingReplaced(self, mock_stdout, mock_input, mock_isfile):
mock_isfile.return_value = True
mock_input.return_value = MockDocumentInput(self.mock_file_content)
expected_print_lines = [
mock.call.write("Setting1=Foo"), mock.call.write('\n'),
mock.call.write("Setting2=NewBar"), mock.call.write('\n'),
mock.call.write("Setting3=Baz"), mock.call.write('\n'),
mock.call.write("Setting4="), mock.call.write('\n'),
]
ly_test_tools.lumberyard.settings._edit_text_settings_file(self.file_name, 'Setting2', 'NewBar')
mock_stdout.assert_has_calls(expected_print_lines)
@mock.patch('os.path.isfile')
@mock.patch('fileinput.input')
@mock.patch('sys.stdout')
def test_ReplaceLineInFile_EmptySettingMatch_SettingReplaced(self, mock_stdout, mock_input, mock_isfile):
mock_isfile.return_value = True
mock_input.return_value = MockDocumentInput(self.mock_file_content)
expected_print_lines = [
mock.call.write("Setting1=Foo"), mock.call.write('\n'),
mock.call.write(";Setting2=Bar"), mock.call.write('\n'),
mock.call.write("Setting3=Baz"), mock.call.write('\n'),
mock.call.write("Setting4=NewContent"), mock.call.write('\n'),
]
ly_test_tools.lumberyard.settings._edit_text_settings_file(self.file_name, 'Setting4', 'NewContent')
mock_stdout.assert_has_calls(expected_print_lines)
@mock.patch('os.path.isfile')
@mock.patch('fileinput.input')
@mock.patch('sys.stdout')
def test_ReplaceLineInFile_NoMatch_SettingAppended(self, mock_stdout, mock_input, mock_isfile):
mock_isfile.return_value = True
mock_input.return_value = MockDocumentInput(self.mock_file_content)
expected_print_lines = [
mock.call.write("Setting1=Foo"), mock.call.write('\n'),
mock.call.write(";Setting2=Bar"), mock.call.write('\n'),
mock.call.write("Setting3=Baz"), mock.call.write('\n'),
mock.call.write("Setting4="), mock.call.write('\n'),
]
ly_test_tools.lumberyard.settings._edit_text_settings_file(self.file_name, 'Setting5', 'NewSetting!')
mock_stdout.assert_has_calls(expected_print_lines)
@@ -0,0 +1,128 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit tests for ly_test_tools.lumberyard.shader_compiler
"""
import unittest.mock as mock
import pytest
import ly_test_tools._internal.managers.workspace
import ly_test_tools._internal.managers.abstract_resource_locator
import ly_test_tools.lumberyard.shader_compiler
pytestmark = pytest.mark.SUITE_smoke
mock_initial_path = "mock_initial_path"
mock_engine_root = "mock_engine_root"
mock_dev_path = "mock_dev_path"
mock_build_directory = 'mock_build_directory'
mock_project = 'mock_project'
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator.os.path.abspath',
mock.MagicMock(return_value=mock_initial_path))
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator._find_engine_root',
mock.MagicMock(return_value=(mock_engine_root, mock_dev_path)))
@mock.patch('ly_test_tools.lumberyard.asset_processor.logger.warning', mock.MagicMock())
class TestShaderCompiler(object):
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
def test_Init_MockWorkspace_MembersSetCorrectly(self, mock_workspace):
under_test = ly_test_tools.lumberyard.shader_compiler.ShaderCompiler(mock_workspace)
assert under_test._workspace == mock_workspace
assert under_test._sc_proc is None
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@mock.patch('subprocess.Popen')
@mock.patch('ly_test_tools.WINDOWS', True)
def test_Start_NoneRunning_ProcessStarted(self, mock_popen, mock_workspace):
mock_shader_compiler_path = 'mock_shader_compiler_path'
mock_workspace.paths.get_shader_compiler_path.return_value = mock_shader_compiler_path
mock_popen.return_value = mock.MagicMock()
under_test = ly_test_tools.lumberyard.shader_compiler.ShaderCompiler(mock_workspace)
assert under_test._sc_proc is None
under_test.start()
assert under_test._sc_proc is not None
mock_popen.assert_called_once_with(['RunAs', '/trustlevel:0x20000', mock_shader_compiler_path])
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@mock.patch('subprocess.Popen')
@mock.patch('ly_test_tools.lumberyard.shader_compiler.MAC', True)
def test_Start_NotImplemented_ErrorRaised(self, mock_popen, mock_workspace):
under_test = ly_test_tools.lumberyard.shader_compiler.ShaderCompiler(mock_workspace)
assert under_test._sc_proc is None
with pytest.raises(NotImplementedError):
under_test.start()
assert under_test._sc_proc is None
mock_popen.assert_not_called()
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@mock.patch('subprocess.Popen')
@mock.patch('ly_test_tools.lumberyard.shader_compiler.logger.info')
@mock.patch('ly_test_tools.lumberyard.shader_compiler.MAC', True)
def test_Start_AlreadyRunning_ProcessNotChanged(self, mock_logger, mock_popen, mock_workspace):
mock_shader_compiler_path = 'mock_shader_compiler_path'
mock_workspace.paths.get_shader_compiler_path.return_value = mock_shader_compiler_path
mock_popen.return_value = mock.MagicMock()
under_test = ly_test_tools.lumberyard.shader_compiler.ShaderCompiler(mock_workspace)
under_test._sc_proc = 'foo'
under_test.start()
assert under_test._sc_proc is not None
mock_popen.assert_not_called()
mock_logger.assert_called_once_with(
'Attempted to start shader compiler at the path: {0}, '
'but we already have one open!'.format(mock_shader_compiler_path))
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@mock.patch('ly_test_tools.lumberyard.shader_compiler.process_utils.kill_processes_started_from')
@mock.patch('ly_test_tools.lumberyard.shader_compiler.waiter.wait_for')
def test_Stop_AlreadyRunning_ProcessStopped(self, mock_wait, mock_kill, mock_workspace):
mock_shader_compiler_path = 'mock_shader_compiler_path'
mock_workspace.paths.get_shader_compiler_path.return_value = mock_shader_compiler_path
under_test = ly_test_tools.lumberyard.shader_compiler.ShaderCompiler(mock_workspace)
under_test._sc_proc = 'foo'
under_test.stop()
assert under_test._sc_proc is None
mock_kill.assert_called_once_with(mock_shader_compiler_path)
mock_wait.assert_called_once()
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@mock.patch('ly_test_tools.lumberyard.shader_compiler.process_utils.kill_processes_started_from')
@mock.patch('ly_test_tools.lumberyard.shader_compiler.waiter.wait_for')
@mock.patch('ly_test_tools.lumberyard.shader_compiler.logger.info')
def test_Stop_NoneRunning_MessageLogged(self, mock_logger, mock_wait, mock_kill, mock_workspace):
mock_shader_compiler_path = 'mock_shader_compiler_path'
mock_workspace.paths.get_shader_compiler_path.return_value = mock_shader_compiler_path
under_test = ly_test_tools.lumberyard.shader_compiler.ShaderCompiler(mock_workspace)
under_test._sc_proc = None
under_test.stop()
assert under_test._sc_proc is None
mock_kill.assert_not_called()
mock_wait.assert_not_called()
mock_logger.assert_called_once_with(
'Attempted to stop shader compiler at the path: {0}, '
'but we do not have any open!'.format(mock_shader_compiler_path))
@@ -0,0 +1,105 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit tests for ly_test_tools._internal.pytest_plugin.terminal_report
"""
import os
import pytest
import unittest.mock as mock
import ly_test_tools._internal.pytest_plugin.terminal_report as terminal_report
pytestmark = pytest.mark.SUITE_smoke
class TestTerminalReport(object):
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.build_rerun_commands')
def test_AddCommands_MockCommands_CommandsAdded(self, mock_build_commands):
mock_build_commands.side_effect = lambda path, nodes: nodes
mock_reporter = mock.MagicMock()
header = 'This is a header'
test_path = 'Foo'
mock_node_ids = ['a', 'b']
terminal_report._add_commands(mock_reporter, header, test_path, mock_node_ids)
mock_reporter.write_line.assert_has_calls([
mock.call(header),
mock.call('a'),
mock.call('b')
])
@mock.patch('ly_test_tools._internal.pytest_plugin.failed_test_rerun_command.build_rerun_commands')
def test_AddCommands_NoCommands_ErrorWritten(self, mock_build_commands):
mock_reporter = mock.MagicMock()
header = 'This is a header'
test_path = 'Foo'
mock_node_ids = []
terminal_report._add_commands(mock_reporter, header, test_path, mock_node_ids)
calls = mock_reporter.write_line.mock_calls
mock_build_commands.assert_not_called()
assert calls[0] == mock.call(header)
assert 'Error' in calls[1][1][0]
@mock.patch('ly_test_tools._internal.pytest_plugin.terminal_report._add_commands')
def test_TerminalSummary_NoErrorsNoFailures_EmptyReport(self, mock_add_commands):
mock_report = mock.MagicMock()
mock_report.stats.get.return_value = []
terminal_report.pytest_terminal_summary(mock_report, 0)
mock_add_commands.assert_not_called()
mock_report.config.getoption.assert_not_called()
mock_report.section.assert_not_called()
@mock.patch('ly_test_tools._internal.pytest_plugin.terminal_report._add_commands')
def test_TerminalSummary_ErrorsAndFailures_SectionsAdded(self, mock_add_commands):
mock_report = mock.MagicMock()
mock_node = mock.MagicMock()
mock_node.nodeid = 'something'
mock_report.stats.get.return_value = [mock_node, mock_node]
terminal_report.pytest_terminal_summary(mock_report, 0)
assert len(mock_add_commands.mock_calls) == 2
mock_report.config.getoption.assert_called()
mock_report.section.assert_called_once()
@mock.patch('ly_test_tools._internal.pytest_plugin.terminal_report._add_commands', mock.MagicMock())
@mock.patch('os.path.basename')
def test_TerminalSummary_Failures_CallsWithBasename(self, mock_basename):
mock_report = mock.MagicMock()
mock_node = mock.MagicMock()
mock_base = 'something'
node_id = os.path.join('C:', mock_base)
mock_node.nodeid = node_id
mock_report.stats.get.side_effect = [[mock_node], []] # first item is failure list
terminal_report.pytest_terminal_summary(mock_report, 0)
mock_basename.assert_called_with(node_id)
@mock.patch('ly_test_tools._internal.pytest_plugin.terminal_report._add_commands', mock.MagicMock())
@mock.patch('os.path.basename')
def test_TerminalSummary_Errors_CallsWithBasename(self, mock_basename):
mock_report = mock.MagicMock()
mock_node = mock.MagicMock()
mock_base = 'something'
node_id = os.path.join('C:', mock_base)
mock_node.nodeid = node_id
mock_report.stats.get.side_effect = [[], [mock_node]] # second item is error list
terminal_report.pytest_terminal_summary(mock_report, 0)
mock_basename.assert_called_with(node_id)
@@ -0,0 +1,50 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import unittest.mock as mock
import unittest
import time
import pytest
import ly_test_tools.environment.waiter
pytestmark = pytest.mark.SUITE_smoke
@mock.patch('time.sleep', mock.MagicMock)
class TestWaitFor(unittest.TestCase):
def test_WaitForFunctionCall_GivenExceptionTimeoutExceeded_RaiseException(self):
input_func = mock.MagicMock()
input_func.return_value = False
with self.assertRaises(Exception):
ly_test_tools.environment.waiter.wait_for(input_func, .001, Exception, 0)
def test_WaitForFunctionCall_TimeoutExceeded_RaiseAssertionError(self):
input_func = mock.MagicMock()
input_func.return_value = False
with self.assertRaises(Exception):
ly_test_tools.environment.waiter.wait_for(input_func, .001, interval=0)
def test_WaitForFunctionCall_TimeoutExceeded_EnoughTime(self):
input_func = mock.MagicMock()
input_func.return_value = False
timeout_end = time.time() + 0.1
try:
ly_test_tools.environment.waiter.wait_for(input_func, 0.1, Exception, interval=0.01)
except Exception:
pass
# It should have taken at least 1/10 second
assert time.time() > timeout_end
@@ -0,0 +1,264 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit Tests for watchdog.py
"""
import unittest
import unittest.mock as mock
import pytest
import ly_test_tools.environment.watchdog as watchdog
pytestmark = pytest.mark.SUITE_smoke
def mock_bool_fn():
return
class TestWatchdog(unittest.TestCase):
@mock.patch('threading.Event')
@mock.patch('threading.Thread')
def test_Watchdog_Instantiated_CreatesEventAndThread(self, mock_thread, mock_event):
mock_watchdog = watchdog.Watchdog(mock_bool_fn)
mock_event.assert_called_once()
mock_thread.assert_called_once_with(target=mock_watchdog._watchdog, name=mock_watchdog.name)
@mock.patch('threading.Event', mock.MagicMock())
@mock.patch('threading.Thread', mock.MagicMock())
class TestWatchdogMethods(unittest.TestCase):
def setUp(self):
self.mock_watchdog = watchdog.Watchdog(mock_bool_fn)
@mock.patch('threading.Thread.start')
@mock.patch('threading.Event.clear')
def test_Start_Called_ClearsEventAndStartsThread(self, mock_clear, mock_start):
self.mock_watchdog.start()
mock_clear.assert_called_once()
mock_start.assert_called_once()
@mock.patch('threading.Thread.join', mock.MagicMock())
@mock.patch('threading.Event.set')
def test_Stop_Called_CallsEventSet(self, under_test):
self.mock_watchdog.stop()
under_test.assert_called_once()
@mock.patch('threading.Thread.join', mock.MagicMock())
@mock.patch('threading.Event.set', mock.MagicMock())
@mock.patch('ly_test_tools.environment.watchdog.logging.Logger.error')
def test_Stop_NoCaughtFailures_NoRaiseOrError(self, mock_error_log):
self.mock_watchdog.caught_failure = False
try:
self.mock_watchdog.stop()
except watchdog.WatchdogError as e:
self.fail(f"Unexpected WatchdogError called. Error: {e}")
mock_error_log.assert_not_called()
@mock.patch('threading.Thread.join', mock.MagicMock())
@mock.patch('threading.Event.set', mock.MagicMock())
@mock.patch('ly_test_tools.environment.watchdog.logging.Logger.error')
def test_Stop_CaughtFailuresAndRaisesOnCondition_RaisesWatchdogError(self, mock_error_log):
self.mock_watchdog.caught_failure = True
self.mock_watchdog._raise_on_condition = True
with pytest.raises(watchdog.WatchdogError):
self.mock_watchdog.stop()
mock_error_log.assert_not_called()
@mock.patch('threading.Thread.join', mock.MagicMock())
@mock.patch('threading.Event.set', mock.MagicMock())
@mock.patch('ly_test_tools.environment.watchdog.logging.Logger.error')
def test_Stop_CaughtFailuresAndNotRaisesOnCondition_LogsError(self, mock_error_log):
self.mock_watchdog.caught_failure = True
self.mock_watchdog._raise_on_condition = False
try:
self.mock_watchdog.stop()
except watchdog.WatchdogError as e:
self.fail(f"Unexpected WatchdogError called. Error: {e}")
mock_error_log.assert_called_once()
@mock.patch('threading.Thread.join')
def test_Stop_Called_CallsJoin(self, under_test):
self.mock_watchdog.caught_failure = False
self.mock_watchdog.stop()
under_test.assert_called_once()
@mock.patch('threading.Thread.join', mock.MagicMock())
@mock.patch('ly_test_tools.environment.watchdog.Watchdog.is_alive')
@mock.patch('ly_test_tools.environment.watchdog.logging.Logger.error')
def test_Stop_ThreadIsAlive_LogsError(self, under_test, mock_is_alive):
mock_is_alive.return_value = True
self.mock_watchdog.stop()
under_test.assert_called_once()
@mock.patch('threading.Thread.join', mock.MagicMock())
@mock.patch('ly_test_tools.environment.watchdog.Watchdog.is_alive')
@mock.patch('ly_test_tools.environment.watchdog.logging.Logger.error')
def test_Stop_ThreadNotAlive_NoLogsError(self, under_test, mock_is_alive):
mock_is_alive.return_value = False
self.mock_watchdog.stop()
under_test.assert_not_called()
@mock.patch('threading.Thread.is_alive')
def test_IsAlive_Called_CallsIsAlive(self, under_test):
self.mock_watchdog.is_alive()
under_test.assert_called_once()
@mock.patch('threading.Event.wait')
def test_WatchdogRunner_ShutdownEventNotSet_CallsBoolFn(self, mock_event_wait):
mock_event_wait.side_effect = [False, True]
mock_bool_fn = mock.MagicMock()
mock_bool_fn.return_value = False
self.mock_watchdog._bool_fn = mock_bool_fn
self.mock_watchdog._watchdog()
self.mock_watchdog._bool_fn.assert_called_once()
assert self.mock_watchdog.caught_failure == False
def test_WatchdogRunner_ShutdownEventSet_NoCallsBoolFn(self):
self.mock_watchdog._shutdown.set()
mock_bool_fn = mock.MagicMock()
self.mock_watchdog._bool_fn = mock_bool_fn
under_test = self.mock_watchdog._watchdog()
assert under_test is None
self.mock_watchdog._bool_fn.assert_not_called()
@mock.patch('threading.Event.wait')
def test_WatchdogRunner_BoolFnReturnsTrue_SetsCaughtFailureToTrue(self, mock_event_wait):
mock_event_wait.side_effect = [False, True]
mock_bool_fn = mock.MagicMock()
mock_bool_fn.return_value = True
self.mock_watchdog._bool_fn = mock_bool_fn
self.mock_watchdog._watchdog()
assert self.mock_watchdog.caught_failure == True
class TestProcessUnresponsiveWatchdog(unittest.TestCase):
mock_process_id = 11111
mock_name = 'foo.exe'
mock_process_not_resp_call = \
'\r\n " \
"Image Name PID Session Name Session# Mem Usage\r\n" \
"========================= ======== ================ =========== ============\r\n" \
"foo.exe %d Console 1 0 K\r\n"' % mock_process_id
mock_process_resp_call = "INFO: No tasks are running which match the specified criteria.\r\n"
@mock.patch('psutil.Process', mock.MagicMock())
def setUp(self):
self.mock_watchdog = watchdog.ProcessUnresponsiveWatchdog(self.mock_process_id)
self.mock_watchdog._process_name = self.mock_name
@mock.patch('ly_test_tools.environment.process_utils.check_output')
def test_ProcessNotResponding_ProcessResponsive_ReturnsFalse(self, mock_check_output):
mock_check_output.return_value = self.mock_process_resp_call
self.mock_watchdog._pid = self.mock_process_id
under_test = self.mock_watchdog._process_not_responding()
assert not under_test
assert self.mock_watchdog._calculated_timeout_point is None
@mock.patch('time.time')
@mock.patch('ly_test_tools.environment.process_utils.check_output')
def test_ProcessNotResponding_ProcessUnresponsiveNoTimeout_ReturnsFalse(self, mock_check_output, mock_time):
mock_time.return_value = 1
mock_check_output.return_value = self.mock_process_not_resp_call
self.mock_watchdog._pid = self.mock_process_id
under_test = self.mock_watchdog._process_not_responding()
timeout_under_test = mock_time.return_value + self.mock_watchdog._unresponsive_timeout
assert not under_test
assert self.mock_watchdog._calculated_timeout_point == timeout_under_test
@mock.patch('time.time')
@mock.patch('ly_test_tools.environment.process_utils.check_output')
def test_ProcessNotResponding_ProcessUnresponsiveReachesTimeout_ReturnsTrue(self, mock_check_output, mock_time):
mock_time.return_value = 3
mock_check_output.return_value = self.mock_process_not_resp_call
self.mock_watchdog._pid = self.mock_process_id
self.mock_watchdog._calculated_timeout_point = 2
under_test = self.mock_watchdog._process_not_responding()
assert under_test
def test_GetPid_Called_ReturnsAttribute(self):
self.mock_watchdog._pid = self.mock_process_id
assert self.mock_watchdog.get_pid() == self.mock_watchdog._pid
class TestCrashLogWatchdog(unittest.TestCase):
mock_log_path = 'C:/foo'
@mock.patch('os.path.exists')
def test_CrashExists_Called_CallsOsPathExists(self, under_test):
under_test.side_effect = [False, mock.DEFAULT]
mock_watchdog = watchdog.CrashLogWatchdog(self.mock_log_path)
mock_watchdog._bool_fn()
under_test.assert_called_with(self.mock_log_path)
@mock.patch('os.path.exists')
@mock.patch('os.remove')
def test_CrashLogWatchdog_LogsExist_ClearsExistingLogs(self, under_test, mock_exists):
mock_exists.return_value = True
mock_watchdog = watchdog.CrashLogWatchdog(self.mock_log_path)
under_test.assert_called_once_with(self.mock_log_path)
@mock.patch('os.path.exists')
@mock.patch('os.remove')
def test_CrashLogWatchdog_LogsNotExist_NoClearsExistingLogs(self, under_test, mock_exists):
mock_exists.return_value = False
mock_watchdog = watchdog.CrashLogWatchdog(self.mock_log_path)
under_test.assert_not_called()
@mock.patch('threading.Thread.join', mock.MagicMock())
@mock.patch('builtins.print')
@mock.patch('builtins.open')
@mock.patch('os.path.exists')
def test_CrashLogWatchdogStop_LogsExists_OpensLogAndPrints(self, mock_exists, mock_open, mock_print):
mock_exists.side_effect = [False, True]
mock_watchdog = watchdog.CrashLogWatchdog(self.mock_log_path)
mock_watchdog.caught_failure = True
mock_watchdog._raise_on_condition = False
mock_watchdog.stop()
mock_open.assert_called_once_with(mock_watchdog._log_path, "r")
assert mock_print.called
@mock.patch('threading.Thread.join', mock.MagicMock())
@mock.patch('builtins.print')
@mock.patch('builtins.open')
@mock.patch('os.path.exists')
def test_CrashLogWatchdogStop_LogsNoExists_NoOpensAndNoPrintsLog(self, mock_exists, mock_open, mock_print):
mock_exists.return_value = False
mock_watchdog = watchdog.CrashLogWatchdog(self.mock_log_path)
mock_watchdog.caught_failure = False
mock_watchdog._raise_on_condition = False
mock_watchdog.stop()
assert not mock_open.called
assert not mock_print.called
@@ -0,0 +1,188 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unit Tests for workspace module
"""
import unittest.mock as mock
import pytest
import unittest
import ly_test_tools._internal.managers.workspace
pytestmark = pytest.mark.SUITE_smoke
mock_initial_path = "mock_initial_path"
mock_engine_root = "mock_engine_root"
mock_dev_path = "mock_dev_path"
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator.os.path.abspath',
mock.MagicMock(return_value=mock_initial_path))
@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator._find_engine_root',
mock.MagicMock(return_value=(mock_engine_root, mock_dev_path)))
class MockedWorkspaceManager(ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager):
def __init__(
self,
resource_locator=mock.MagicMock(),
project=mock.MagicMock(),
tmp_path=mock.MagicMock(),
output_path=mock.MagicMock()
):
super(MockedWorkspaceManager, self).__init__(
resource_locator=resource_locator,
project=project,
tmp_path=tmp_path,
output_path=output_path
)
def setup(self):
super(MockedWorkspaceManager, self).setup()
def run_setup_assistant(self):
pass
class TestWorkspaceManager:
def test_Init_NoInheritanceAbstractWorkspaceManager_RaisesTypeError(self):
mock_resource_locator = mock.MagicMock()
with pytest.raises(TypeError):
ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager(resource_locator=mock_resource_locator)
@mock.patch('ly_test_tools._internal.managers.artifact_manager.NullArtifactManager.__init__')
@mock.patch('tempfile.mkdtemp')
def test_Init_TmpPathIsNone_TmpPathIsCreated(self, under_test, mock_null_artifact_manager):
mock_null_artifact_manager.return_value = None
mock_workspace = MockedWorkspaceManager(tmp_path=None)
under_test.assert_called_once()
@mock.patch('os.path.exists', mock.MagicMock())
@mock.patch('tempfile.mkdtemp', mock.MagicMock())
def test_Init_LogsPathIsNone_LogsPathIsSetToDefault(self):
dummy_path = 'mockTestResults'
mock_resource_locator = mock.MagicMock()
mock_resource_locator.test_results.return_value = dummy_path
mock_workspace = MockedWorkspaceManager(resource_locator=mock_resource_locator, output_path=None)
assert mock_workspace.output_path.startswith(dummy_path)
class TestSetup(unittest.TestCase):
def setUp(self):
self.mock_workspace = MockedWorkspaceManager()
@mock.patch('os.makedirs')
@mock.patch('os.path.exists')
def test_Setup_TmpPathExists_CallsMakeDirs(self, mock_path_exists, mock_makedirs):
self.mock_workspace.tmp_path = 'mock_tmp_path'
mock_path_exists.side_effect = [False, True, True] # ArtifactManager.__init__() calls os.path.exists()
self.mock_workspace._custom_output_path = True
self.mock_workspace.setup()
mock_makedirs.assert_called_once_with(self.mock_workspace.tmp_path)
@mock.patch('os.makedirs')
@mock.patch('os.path.exists')
def test_Setup_TmpPathNotExists_NoCallsMakeDirs(self, mock_path_exists, mock_makedirs):
mock_path_exists.return_value = True
self.mock_workspace.tmp_path = None
self.mock_workspace._custom_output_path = True
self.mock_workspace.setup()
assert not mock_makedirs.called
@mock.patch('os.makedirs')
@mock.patch('os.path.exists')
def test_Setup_LogPathExists_NoCallsMakeDirs(self, mock_path_exists, mock_makedirs):
mock_path_exists.return_value = True
self.mock_workspace.tmp_path = None
self.mock_workspace.setup()
mock_makedirs.assert_not_called()
@mock.patch('os.makedirs')
@mock.patch('os.path.exists')
def test_Setup_LogPathNotExists_CallsMakeDirs(self, mock_path_exists, mock_makedirs):
mock_path_exists.return_value = False
self.mock_workspace.tmp_path = None
self.mock_workspace.output_path = 'mock_output_path'
self.mock_workspace.setup()
mock_makedirs.assert_called_with(self.mock_workspace.output_path)
assert mock_makedirs.call_count == 2 # ArtifactManager.__init__() calls os.path.exists()
class TestTeardown(unittest.TestCase):
def setUp(self):
self.mock_workspace = MockedWorkspaceManager()
@mock.patch('os.chdir', mock.MagicMock())
@mock.patch('ly_test_tools.environment.file_system.delete')
def test_Teardown_TmpPathNotNone_DeletesTmpPath(self, mock_delete):
self.mock_workspace.tmp_path = 'tmp_path'
self.mock_workspace.teardown()
mock_delete.assert_called_once_with([self.mock_workspace.tmp_path], True, True)
@mock.patch('ly_test_tools.environment.file_system.delete', mock.MagicMock())
@mock.patch('os.chdir')
def test_Teardown_CwdModified_RevertsCwdToDefault(self, mock_chdir):
self.mock_workspace.tmp_path = 'tmp_path'
self.mock_workspace.teardown()
mock_chdir.assert_called_once_with(self.mock_workspace._original_cwd)
class TestClearCache(unittest.TestCase):
def setUp(self):
self.mock_workspace = MockedWorkspaceManager()
@mock.patch('ly_test_tools.environment.file_system.delete')
@mock.patch('os.path.exists')
def test_ClearCache_CacheExists_CacheIsDeleted(self, mock_path_exists, mock_delete):
mock_path_exists.return_value = True
self.mock_workspace.clear_cache()
mock_delete.assert_called_once_with([self.mock_workspace.paths.cache()], True, True)
@mock.patch('ly_test_tools.environment.file_system.delete')
@mock.patch('os.path.exists')
def test_ClearCache_CacheNotExists_CacheNotDeleted(self, mock_path_exists, mock_delete):
mock_path_exists.return_value = False
self.mock_workspace.clear_cache()
mock_delete.assert_not_called()
class TestClearBin(unittest.TestCase):
def setUp(self):
self.mock_workspace = MockedWorkspaceManager()
@mock.patch('ly_test_tools.environment.file_system.delete')
@mock.patch('os.path.exists')
def test_ClearBin_BinExists_BinIsDeleted(self, mock_path_exists, mock_delete):
mock_path_exists.return_value = True
self.mock_workspace.clear_bin()
mock_delete.assert_called_once_with([self.mock_workspace.paths.build_directory()], True, True)
@mock.patch('ly_test_tools.environment.file_system.delete')
@mock.patch('os.path.exists')
def test_ClearBin_BinNotExists_BinNotDeleted(self, mock_path_exists, mock_delete):
mock_path_exists.return_value = False
self.mock_workspace.clear_bin()
mock_delete.assert_not_called()