diff --git a/.config/dictionary.txt b/.config/dictionary.txt index 0817cbff81..b3d785e0cb 100644 --- a/.config/dictionary.txt +++ b/.config/dictionary.txt @@ -108,6 +108,7 @@ templated templating testhost testname +testsfailed topbar tracebacks truecolor diff --git a/pyproject.toml b/pyproject.toml index 7b63776a61..a0d440f33f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,9 +78,7 @@ incremental = false [[tool.mypy.overrides]] # https://github.com/ansible/ansible-runner/issues/1340 -module = [ - "ansible_runner" -] +module = ["ansible_runner"] ignore_missing_imports = true [tool.pydoclint] @@ -111,6 +109,7 @@ ignore = [ good-names = "i,j,k,ex,Run,_,f,fh" jobs = 0 no-docstring-rgx = "__.*__" +max-args = 6 # default of 5 too low [tool.pylint.messages_control] disable = [ diff --git a/src/ansible_navigator/ui_framework/menu_builder.py b/src/ansible_navigator/ui_framework/menu_builder.py index eb707e469f..7cf905a2e4 100644 --- a/src/ansible_navigator/ui_framework/menu_builder.py +++ b/src/ansible_navigator/ui_framework/menu_builder.py @@ -39,7 +39,6 @@ def __init__( :param color_menu_item: The callback for adding color to menu entries :param ui_config: The current user interface configuration """ - # pylint: disable=too-many-arguments self._number_colors = number_colors self._progress_bar_width = progress_bar_width self._screen_width = screen_width diff --git a/tests/conftest.py b/tests/conftest.py index 46e81631b2..1597db4c41 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -36,6 +36,10 @@ from .defaults import FIXTURES_DIR +# implicit verbosity, updated at runtime +VERBOSITY = 0 + + def valid_ce() -> str: """Return an available container engine. @@ -199,7 +203,8 @@ def pull_image(valid_container_engine: str, image_name: str) -> None: pull_policy="missing", ) image_puller.assess() - image_puller.prologue_stdout() + if VERBOSITY > 0: + image_puller.prologue_stdout() if image_puller.assessment.exit_messages: print( msg.to_lines(color=False, width=console_width(), with_prefix=True) @@ -313,6 +318,14 @@ def pytest_sessionstart(session: pytest.Session) -> None: if getattr(session.config, "workerinput", None) is not None: return container_engine = valid_ce() + # fail fast if engine is not working properly, macos podman machine have + # the habit of getting stuck. + try: + cmd = [container_engine, "info"] + subprocess.check_output(cmd, stderr=subprocess.STDOUT, timeout=6) + except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as exc: + pytest.exit(f"Container engine is broken, fail to run: {' '.join(cmd)}: {exc}") + pull_image( valid_container_engine=container_engine, image_name=default_ee_image_name(), @@ -331,6 +344,8 @@ def pytest_configure(config: pytest.Config) -> None: :param config: The pytest config object """ + global VERBOSITY + VERBOSITY = config.option.verbose # limit an environment variables that may conflict with tests allow = ("ANSIBLE_NAVIGATOR_UPDATE_TEST_FIXTURES",) for k in os.environ: @@ -371,3 +386,18 @@ def pytest_unconfigure(config: pytest.Config) -> None: """ for key, value in USER_ENVIRONMENT.items(): os.environ[key] = value + + +@pytest.fixture(scope="function") +def skip_if_already_failed( + request: pytest.FixtureRequest, failed=set() +) -> Generator[None, None, None]: + """Fixture that stops parametrized tests running on first failure.""" + key = request.node.name.split("[")[0] + failed_before = request.session.testsfailed + if key in failed: + pytest.skip(f"previous test {key} failed") + yield + failed_after = request.session.testsfailed + if failed_before != failed_after: + failed.add(key) diff --git a/tests/integration/actions/builder/base.py b/tests/integration/actions/builder/base.py index 38ca1a0632..c481929919 100644 --- a/tests/integration/actions/builder/base.py +++ b/tests/integration/actions/builder/base.py @@ -45,7 +45,11 @@ def fixture_tmux_session( yield tmux_session def test( - self, request: pytest.FixtureRequest, tmux_session: TmuxSession, step: UiTestStep + self, + request: pytest.FixtureRequest, + tmux_session: TmuxSession, + step: UiTestStep, + skip_if_already_failed: None, ) -> None: """Run the tests for ``builder``, mode and ``ee`` set in child class. diff --git a/tests/integration/actions/collections/base.py b/tests/integration/actions/collections/base.py index b205de1593..76dfae9a1a 100644 --- a/tests/integration/actions/collections/base.py +++ b/tests/integration/actions/collections/base.py @@ -130,6 +130,7 @@ def test( request: pytest.FixtureRequest, step: UiTestStep, tmux_session: TmuxSession, + skip_if_already_failed: None, ) -> None: """Run the tests for ``collections``, mode and ``ee`` set in child class. diff --git a/tests/integration/actions/config/base.py b/tests/integration/actions/config/base.py index 0f834fd7fc..aca4de4f1f 100644 --- a/tests/integration/actions/config/base.py +++ b/tests/integration/actions/config/base.py @@ -66,7 +66,11 @@ def fixture_tmux_session( yield tmux_session def test( - self, request: pytest.FixtureRequest, tmux_session: TmuxSession, step: UiTestStep + self, + request: pytest.FixtureRequest, + tmux_session: TmuxSession, + step: UiTestStep, + skip_if_already_failed: None, ) -> None: # pylint: disable=too-many-locals """Run the tests for ``config``, mode and ``ee`` set in child class. diff --git a/tests/integration/actions/doc/base.py b/tests/integration/actions/doc/base.py index b9d55c10ea..05e5ffc638 100644 --- a/tests/integration/actions/doc/base.py +++ b/tests/integration/actions/doc/base.py @@ -52,6 +52,7 @@ def test( comment: str, testname: str, expected_in_output: list[str] | None, + skip_if_already_failed: None, ) -> None: # pylint: disable=too-many-arguments # pylint: disable=too-many-locals diff --git a/tests/integration/actions/doc/test_stdout_subprocess.py b/tests/integration/actions/doc/test_stdout_subprocess.py index 83d215a24c..5514c856f1 100644 --- a/tests/integration/actions/doc/test_stdout_subprocess.py +++ b/tests/integration/actions/doc/test_stdout_subprocess.py @@ -105,6 +105,7 @@ def test( data: StdoutCliTest, exec_env: bool, cmd_in_tty: TCmdInTty, + skip_if_already_failed: None, ) -> None: """Test doc using subcommand. diff --git a/tests/integration/actions/exec/base.py b/tests/integration/actions/exec/base.py index b55eda22db..4eed4c8c7b 100644 --- a/tests/integration/actions/exec/base.py +++ b/tests/integration/actions/exec/base.py @@ -54,7 +54,11 @@ def fixture_tmux_session( yield tmux_session def test( - self, request: pytest.FixtureRequest, tmux_session: TmuxSession, step: UiTestStep + self, + request: pytest.FixtureRequest, + tmux_session: TmuxSession, + step: UiTestStep, + skip_if_already_failed: None, ) -> None: """Test interactive/stdout exec. diff --git a/tests/integration/actions/images/base.py b/tests/integration/actions/images/base.py index 533f2a5310..75d33493e6 100644 --- a/tests/integration/actions/images/base.py +++ b/tests/integration/actions/images/base.py @@ -74,7 +74,11 @@ def fixture_tmux_session(request: pytest.FixtureRequest) -> Generator[TmuxSessio yield tmux_session def test( - self, request: pytest.FixtureRequest, tmux_session: TmuxSession, step: UiTestStep + self, + request: pytest.FixtureRequest, + tmux_session: TmuxSession, + step: UiTestStep, + skip_if_already_failed: None, ) -> None: """Run the tests for images, mode and ``ee`` set in child class. diff --git a/tests/integration/actions/inventory/base.py b/tests/integration/actions/inventory/base.py index 909666d94a..8c39e027c0 100644 --- a/tests/integration/actions/inventory/base.py +++ b/tests/integration/actions/inventory/base.py @@ -79,7 +79,11 @@ def fixture_tmux_session(request: pytest.FixtureRequest) -> Generator[TmuxSessio yield tmux_session def test( - self, request: pytest.FixtureRequest, tmux_session: TmuxSession, step: UiTestStep + self, + request: pytest.FixtureRequest, + tmux_session: TmuxSession, + step: UiTestStep, + skip_if_already_failed: None, ) -> None: """Run the tests for inventory, mode and ``ee`` set in child class. diff --git a/tests/integration/actions/lint/base.py b/tests/integration/actions/lint/base.py index d4283ab422..2e0c0b05c5 100644 --- a/tests/integration/actions/lint/base.py +++ b/tests/integration/actions/lint/base.py @@ -46,7 +46,11 @@ def fixture_tmux_session(request: pytest.FixtureRequest) -> Generator[TmuxSessio yield tmux_session def test( - self, request: pytest.FixtureRequest, tmux_session: TmuxSession, step: UiTestStep + self, + request: pytest.FixtureRequest, + tmux_session: TmuxSession, + step: UiTestStep, + skip_if_already_failed: None, ) -> None: """Run the tests for lint, mode and ``ee`` set in child class. diff --git a/tests/integration/actions/run/base.py b/tests/integration/actions/run/base.py index 939a564bb4..4ab9763981 100644 --- a/tests/integration/actions/run/base.py +++ b/tests/integration/actions/run/base.py @@ -70,7 +70,11 @@ def fixture_tmux_session(request: pytest.FixtureRequest) -> Generator[TmuxSessio yield tmux_session def test( - self, request: pytest.FixtureRequest, tmux_session: TmuxSession, step: UiTestStep + self, + request: pytest.FixtureRequest, + tmux_session: TmuxSession, + step: UiTestStep, + skip_if_already_failed: None, ) -> None: """Run the tests for run, mode and ``ee`` set in child class. diff --git a/tests/integration/actions/run_unicode/base.py b/tests/integration/actions/run_unicode/base.py index c6f501c3df..179e7f6ab2 100644 --- a/tests/integration/actions/run_unicode/base.py +++ b/tests/integration/actions/run_unicode/base.py @@ -66,6 +66,7 @@ def test( request: pytest.FixtureRequest, tmux_session: TmuxSession, step: UiTestStep, + skip_if_already_failed: None, ) -> None: """Run the tests for run, mode and ``ee`` set in child class. diff --git a/tests/integration/actions/settings/base.py b/tests/integration/actions/settings/base.py index 4721ae9ca9..4a5937d0fe 100644 --- a/tests/integration/actions/settings/base.py +++ b/tests/integration/actions/settings/base.py @@ -67,7 +67,11 @@ def fixture_tmux_session( yield tmux_session def test( - self, request: pytest.FixtureRequest, tmux_session: TmuxSession, step: UiTestStep + self, + request: pytest.FixtureRequest, + tmux_session: TmuxSession, + step: UiTestStep, + skip_if_already_failed: None, ) -> None: # pylint: disable=too-many-locals """Run the tests for ``settings``, mode and ``ee`` set in child class. diff --git a/tests/integration/actions/stdout/base.py b/tests/integration/actions/stdout/base.py index 1a92f534ef..7b06d4cabf 100644 --- a/tests/integration/actions/stdout/base.py +++ b/tests/integration/actions/stdout/base.py @@ -53,6 +53,7 @@ def test( user_input: str, comment: str, search_within_response: str, + skip_if_already_failed: None, ) -> None: # pylint:disable=too-many-arguments """Run the tests for stdout, mode and EE set in child class. diff --git a/tests/integration/actions/templar/base.py b/tests/integration/actions/templar/base.py index 71dff871e6..5aea573720 100644 --- a/tests/integration/actions/templar/base.py +++ b/tests/integration/actions/templar/base.py @@ -86,7 +86,11 @@ def fixture_tmux_session(request: pytest.FixtureRequest) -> Generator[TmuxSessio yield tmux_session def test( - self, request: pytest.FixtureRequest, tmux_session: TmuxSession, step: UiTestStep + self, + request: pytest.FixtureRequest, + tmux_session: TmuxSession, + step: UiTestStep, + skip_if_already_failed: None, ) -> None: """Test interactive and ``stdout`` mode ``config``. diff --git a/tests/integration/diagnostics/test_from_cli.py b/tests/integration/diagnostics/test_from_cli.py index cc850512f1..4ae04c9f92 100644 --- a/tests/integration/diagnostics/test_from_cli.py +++ b/tests/integration/diagnostics/test_from_cli.py @@ -18,6 +18,7 @@ def test( monkeypatch: pytest.MonkeyPatch, settings_env_var_to_full: tuple[Path, SettingsFileType], tmp_path: Path, + skip_if_already_failed: None, ) -> None: """Test diagnostics generation. diff --git a/tests/unit/configuration_subsystem/test_posix_message_queue.py b/tests/unit/configuration_subsystem/test_posix_message_queue.py index 3d3d7269ef..dc881e21ae 100644 --- a/tests/unit/configuration_subsystem/test_posix_message_queue.py +++ b/tests/unit/configuration_subsystem/test_posix_message_queue.py @@ -31,7 +31,6 @@ def test_posix_message_queue_ee( :param platform: The system platform to mock :param generate_config: The configuration generator fixture """ - # pylint: disable=too-many-arguments message_queue_msg = ( "Execution environment support while using podman requires a '/dev/mqueue/' directory." ) diff --git a/tests/unit/utils/test_functions.py b/tests/unit/utils/test_functions.py index 08f2b010a0..8253bc5cf8 100644 --- a/tests/unit/utils/test_functions.py +++ b/tests/unit/utils/test_functions.py @@ -287,3 +287,18 @@ def test_now_iso(caplog: pytest.LogCaptureFixture, time_zone: str) -> None: if time_zone == "bogus": assert matched["timezone"] == "+00:00" assert "The time zone 'bogus' could not be found. Using UTC." in caplog.text + + +@pytest.mark.parametrize( + "data,output", + ( + pytest.param({}, {}, id="0"), + pytest.param(None, None, id="1"), + pytest.param([], [], id="2"), + pytest.param("foo", "foo", id="3"), + ), +) +def test_unescape_moustaches(data: Any, output: Any) -> None: + """Tests unescape_moustaches.""" + result = functions.unescape_moustaches(data) + assert result == output diff --git a/tox.ini b/tox.ini index ed99778647..0b78a38137 100644 --- a/tox.ini +++ b/tox.ini @@ -39,7 +39,7 @@ commands = # pytest params are kept in pyproject.toml # if one wants to control parallelism define PYTEST_XDIST_AUTO_NUM_WORKERS coverage run -m pytest {posargs:-n=auto --dist=loadfile} - sh -c "coverage combine -q .tox/.coverage.* && coverage xml || true && coverage report" + sh -c "coverage combine -q {toxworkdir}/.coverage.* && coverage xml || true && coverage report" setenv = COVERAGE_FILE = {env:COVERAGE_FILE:{toxworkdir}/.coverage.{envname}} COVERAGE_PROCESS_START={toxinidir}/pyproject.toml