Integrating latest 47acbe8

This commit is contained in:
alexpete
2021-03-25 13:57:57 -07:00
parent 448c549698
commit 75dc720198
10312 changed files with 2711566 additions and 671451 deletions
@@ -14,14 +14,19 @@ import sys
from ly_test_tools import WINDOWS
def _get_test_launcher_cmd():
def _get_test_launcher_cmd(build_dir=None):
"""
Helper function to determine the test launcher command for the current platform
:param build_dir: the --build-directory arg that is passed to determine which build dir to use. Can also be None
:return: The test launcher command
"""
python_runner = "python3.cmd"
build_arg = ""
if build_dir:
build_arg = f"--build-directory {build_dir} "
python_runner = "python.cmd"
if not WINDOWS:
python_runner = "python3.sh"
python_runner = "python.sh"
current_dir = sys.executable
# Look upward a handful of levels to check for the LY python entry point script
@@ -29,12 +34,12 @@ def _get_test_launcher_cmd():
for _ in range(10):
python_wrapper = os.path.join(current_dir, python_runner)
if os.path.exists(python_wrapper):
return f"{python_wrapper} -m pytest "
return f"{python_wrapper} -m pytest{build_arg} "
# Using an explicit else to avoid aberrant behavior from following filesystem links
else:
current_dir = os.path.abspath(os.path.join(current_dir, os.path.pardir))
return f"{sys.executable} -m pytest "
return f"{sys.executable} -m pytest{build_arg} "
def _format_cmd(launcher_cmd, test_path, nodeid):
@@ -65,17 +70,18 @@ def _format_cmd(launcher_cmd, test_path, nodeid):
return f"{launcher_cmd}{test_id_argument}"
def build_rerun_commands(test_path, nodeids):
def build_rerun_commands(test_path, nodeids, build_dir=None):
"""
Builds a list of commands to run tests
:param test_path: File or directory that contains the test(s) that were run
:param nodeids: List of test node ids, with parametrized values
:param build_dir: the --build-directory arg that is passed to determine which build dir to use. Can also be None
:return: A list of commands to re-run tests
"""
commands = []
test_launcher_cmd = _get_test_launcher_cmd()
test_launcher_cmd = _get_test_launcher_cmd(build_dir)
for nodeid in nodeids:
commands.append(_format_cmd(test_launcher_cmd, test_path, nodeid))
@@ -13,32 +13,39 @@ import os
import ly_test_tools._internal.pytest_plugin.failed_test_rerun_command as rerun
def _add_commands(terminalreporter, header, test_path, nodeids):
def _add_commands(terminalreporter, header, test_path, nodeids, build_dir=None):
"""
Add test re-run commands to the TerminalReporter object
:param terminalreporter: Pytest's TerminalReporter object that contains test result information.
:param header: Message to write to TerminalReporter before list is added
:param test_path: File or directory that contains the test(s) that to run
:param nodeids: List of test node ids, with parametrized values
:param build_dir: the --build-directory arg that is passed to determine which build dir to use. Can also be None
"""
terminalreporter.write_line(header)
if nodeids:
commands = rerun.build_rerun_commands(test_path, nodeids)
commands = rerun.build_rerun_commands(test_path, nodeids, build_dir)
for command in commands:
terminalreporter.write_line(command)
else:
terminalreporter.write_line("Error, Test node id list is empty!")
def pytest_terminal_summary(terminalreporter, exitstatus):
def pytest_terminal_summary(terminalreporter, exitstatus, config):
"""
Pytest's hook for terminal reporting. This hook is invoked at the end of the test session.
:param terminalreporter: Pytest's TerminalReporter object that contains test result information.
:param exitstatus: Exit that will be returned to the system
"""
# Check to see if the build directory was passed
build_dir = None
try:
build_dir = config.known_args_namespace.build_directory
except AttributeError:
pass
# Add to the TerminalReport a section for failed test re-running
failures = terminalreporter.stats.get('failed', [])
@@ -62,7 +69,7 @@ def pytest_terminal_summary(terminalreporter, exitstatus):
terminalreporter,
"Use the following commands to re-run each test that failed locally\n"
"(NOTE: The 'PYTHON' or 'PYTHONPATH' environment variables need values for accurate commands): ",
test_path, nodeids)
test_path, nodeids, build_dir)
if error_count:
nodeids = [os.path.basename(report.nodeid) for report in errors]
@@ -71,4 +78,4 @@ def pytest_terminal_summary(terminalreporter, exitstatus):
terminalreporter,
"Use the following commands to re-run each test that had errors locally\n"
"(NOTE: The 'PYTHON' or 'PYTHONPATH' environment variables need values for accurate commands): ",
test_path, nodeids)
test_path, nodeids, build_dir)
@@ -126,6 +126,7 @@ def kill_processes_with_name_not_started_from(name, path):
else:
logger.warning(f"Path:'{path}' not found")
def kill_process_with_pid(pid, raise_on_missing=False):
"""
Kills the process with the specified pid
@@ -367,7 +368,10 @@ def _safe_kill_process_list(proc_list):
except Exception: # purposefully broad
logger.warning("Unexpected exception while terminating process", exc_info=True)
psutil.wait_procs(proc_list, timeout=30, callback=on_terminate)
try:
psutil.wait_procs(proc_list, timeout=30, callback=on_terminate)
except Exception: # purposefully broad
logger.warning("Unexpected exception while waiting for process to terminate", exc_info=True)
def _terminate_and_confirm_dead(proc):
@@ -220,7 +220,7 @@ def platform_enabled(workspace: pytest.fixture, platform: str) -> bool:
Checks to see if the platform specified is enabled for the current build of LY.
:param workspace: The current testing workspace
:param platform: The name of the platform to lookup. Example Platforms: 'Xenia', 'Provo', 'Salem'
:param platform: The name of the platform to lookup.
:return: True if the platform is enabled, False if not.
"""
user_settings_file = os.path.join(workspace.paths.dev(), "_WAF_", "user_settings.options")
+6 -1
View File
@@ -16,9 +16,10 @@ ly_add_pytest(
NAME LyTestTools_UnitTests
TEST_SUITE smoke
PATH ${CMAKE_CURRENT_LIST_DIR}/unit/
COMPONENT TestTools
)
if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS)
if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS_NAME)
# Integration tests.
ly_add_pytest(
NAME LyTestTools_IntegTests_Sanity_smoke_no_gpu
@@ -31,6 +32,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT
AutomatedTesting.GameLauncher
AutomatedTesting.Assets
Legacy::CryRenderNULL
COMPONENT TestTools
)
ly_add_pytest(
@@ -38,6 +40,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT
PATH ${CMAKE_CURRENT_LIST_DIR}/integ/test_process_utils.py
TEST_SERIAL
TEST_SUITE smoke
COMPONENT TestTools
)
ly_add_pytest(
@@ -50,6 +53,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT
AutomatedTesting.GameLauncher
AutomatedTesting.Assets
Legacy::CryRenderNULL
COMPONENT TestTools
)
# Regression tests.
@@ -64,5 +68,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT
AutomatedTesting.GameLauncher
AutomatedTesting.Assets
Legacy::CryRenderNULL
COMPONENT TestTools
)
endif()
@@ -49,7 +49,7 @@ class TestRerunCommand(object):
@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'
python_script = 'python.cmd'
expected = f"{os.path.join(TestRerunCommand.MOCK_FOO_EXE, python_script)} -m pytest "
under_test = failed_test_rerun_command._get_test_launcher_cmd()
@@ -59,7 +59,7 @@ class TestRerunCommand(object):
@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'
python_script = 'python.sh'
expected = f"{os.path.join(TestRerunCommand.MOCK_FOO_EXE, python_script)} -m pytest "
under_test = failed_test_rerun_command._get_test_launcher_cmd()
@@ -337,6 +337,17 @@ class Test(unittest.TestCase):
mock_wait.assert_called()
mock_log_warn.assert_called()
@mock.patch('psutil.wait_procs')
@mock.patch('logging.Logger.warning')
def test_SafeKillProcList_RaisesError_NoRaiseAndLogsError(self, mock_log_warn, mock_wait_procs):
mock_wait_procs.side_effect = psutil.PermissionError()
proc_mock = mock.MagicMock()
process_utils._safe_kill_process_list(proc_mock)
mock_wait_procs.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):
@@ -23,7 +23,7 @@ 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_build_commands.side_effect = lambda path, nodes, dir: nodes
mock_reporter = mock.MagicMock()
header = 'This is a header'
test_path = 'Foo'
@@ -55,8 +55,9 @@ class TestTerminalReport(object):
def test_TerminalSummary_NoErrorsNoFailures_EmptyReport(self, mock_add_commands):
mock_report = mock.MagicMock()
mock_report.stats.get.return_value = []
mock_config = mock.MagicMock()
terminal_report.pytest_terminal_summary(mock_report, 0)
terminal_report.pytest_terminal_summary(mock_report, 0, mock_config)
mock_add_commands.assert_not_called()
mock_report.config.getoption.assert_not_called()
@@ -68,8 +69,9 @@ class TestTerminalReport(object):
mock_node = mock.MagicMock()
mock_node.nodeid = 'something'
mock_report.stats.get.return_value = [mock_node, mock_node]
mock_config = mock.MagicMock()
terminal_report.pytest_terminal_summary(mock_report, 0)
terminal_report.pytest_terminal_summary(mock_report, 0, mock_config)
assert len(mock_add_commands.mock_calls) == 2
mock_report.config.getoption.assert_called()
@@ -84,8 +86,9 @@ class TestTerminalReport(object):
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
mock_config = mock.MagicMock()
terminal_report.pytest_terminal_summary(mock_report, 0)
terminal_report.pytest_terminal_summary(mock_report, 0, mock_config)
mock_basename.assert_called_with(node_id)
@@ -98,8 +101,9 @@ class TestTerminalReport(object):
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
mock_config = mock.MagicMock()
terminal_report.pytest_terminal_summary(mock_report, 0)
terminal_report.pytest_terminal_summary(mock_report, 0, mock_config)
mock_basename.assert_called_with(node_id)