From 638d711a7248972f207be50c9001247e511d24dd Mon Sep 17 00:00:00 2001 From: Matt Clay Date: Tue, 20 May 2025 11:11:45 -0700 Subject: [PATCH] ansible-test - Fix option filtering (#85182) (cherry picked from commit feda0a5c6e82757c27bfa43984716cdd79ae5fe9) --- .../ansible-test-delegation-options.yml | 5 +++ test/lib/ansible_test/_internal/util.py | 20 +++++++++ .../units/ansible_test/_internal/test_util.py | 45 +++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 changelogs/fragments/ansible-test-delegation-options.yml diff --git a/changelogs/fragments/ansible-test-delegation-options.yml b/changelogs/fragments/ansible-test-delegation-options.yml new file mode 100644 index 00000000000..78de3d0f4f6 --- /dev/null +++ b/changelogs/fragments/ansible-test-delegation-options.yml @@ -0,0 +1,5 @@ +bugfixes: + - ansible-test - Fix incorrect handling of options with optional args (e.g. ``--color``), + when followed by other options which are omitted during arg filtering (e.g. ``--docker``). + Previously it was possible for non-option arguments to be incorrectly omitted in these cases. + (https://github.com/ansible/ansible/issues/85173) diff --git a/test/lib/ansible_test/_internal/util.py b/test/lib/ansible_test/_internal/util.py index f875463111a..778eef24cdc 100644 --- a/test/lib/ansible_test/_internal/util.py +++ b/test/lib/ansible_test/_internal/util.py @@ -254,12 +254,29 @@ def filter_args(args: list[str], filters: dict[str, int]) -> list[str]: """Return a filtered version of the given command line arguments.""" remaining = 0 result = [] + pass_through_args: list[str] = [] + pass_through_explicit = False + pass_through_implicit = False for arg in args: + if pass_through_explicit: + pass_through_args.append(arg) + continue + + if arg == '--': + pass_through_explicit = True + continue + if not arg.startswith('-') and remaining: remaining -= 1 + pass_through_implicit = not remaining continue + if not arg.startswith('-') and pass_through_implicit: + pass_through_args.append(arg) + continue + + pass_through_implicit = False remaining = 0 parts = arg.split('=', 1) @@ -271,6 +288,9 @@ def filter_args(args: list[str], filters: dict[str, int]) -> list[str]: result.append(arg) + if pass_through_args: + result += ['--'] + pass_through_args + return result diff --git a/test/units/ansible_test/_internal/test_util.py b/test/units/ansible_test/_internal/test_util.py index 97e2f05dd74..d3b21171544 100644 --- a/test/units/ansible_test/_internal/test_util.py +++ b/test/units/ansible_test/_internal/test_util.py @@ -34,3 +34,48 @@ def test_failed_interactive_command() -> None: assert error.value.stdout is None assert error.value.stderr is None + + +@pytest.mark.parametrize("args,filters,expected", ( + ( + # args after a known option must be separated from existing args + ['--color', '--docker', 'default', 'ping', 'split'], + {'--docker': 1}, + ['--color', '--', 'ping', 'split'], + ), + ( + # args after '--' are not options + ['--', '--color'], + {'--color': 1}, + ['--', '--color'], + ), + ( + # args after a known option must be separated from existing args without conflicting with an explicit '--' + ['--color', '--docker', 'default', 'ping', '--', 'split'], + {'--docker': 1}, + ['--color', '--', 'ping', 'split'], + ), + ( + # args before options are properly handled + ['ping', '--docker', 'default', '-v'], + {'--docker': 1}, + ['ping', '-v'], + ), + ( + # no options + ['ping', 'split'], + {'--docker': 1}, + ['ping', 'split'], + ), + ( + # only options + ['--color', '--docker', 'default', '-v'], + {'--docker': 1}, + ['--color', '-v'], + ) +)) +def test_filter_args(args: list[str], filters: dict[str, int], expected: list[str]) -> None: + """Verify arg filtering properly handles various scenarios.""" + from ansible_test._internal.util import filter_args + + assert filter_args(args, filters) == expected