Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd_runner: add __call__ method to invoke context #4791

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/4791-cmd-runner-callable.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- cmd_runner module utils - add ``__call__`` method to invoke context (https://github.com/ansible-collections/community.general/pull/4791).
5 changes: 4 additions & 1 deletion plugins/module_utils/cmd_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ def __init__(self, module, command, arg_formats=None, default_args_order=(),
if mod_param_name not in self.arg_formats:
self.arg_formats[mod_param_name] = _Format.as_default_type(spec['type'], mod_param_name)

def context(self, args_order=None, output_process=None, ignore_value_none=True, check_mode_skip=False, check_mode_return=None, **kwargs):
def __call__(self, args_order=None, output_process=None, ignore_value_none=True, check_mode_skip=False, check_mode_return=None, **kwargs):
if output_process is None:
output_process = _process_as_is
if args_order is None:
Expand All @@ -216,6 +216,9 @@ def context(self, args_order=None, output_process=None, ignore_value_none=True,
def has_arg_format(self, arg):
return arg in self.arg_formats

# not decided whether to keep it or not, but if deprecating it will happen in a farther future.
context = __call__


class _CmdRunnerContext(object):
def __init__(self, runner, args_order, output_process, ignore_value_none, check_mode_skip, check_mode_return, **kwargs):
Expand Down
6 changes: 3 additions & 3 deletions plugins/modules/system/xfconf.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,11 @@ def process_command_output(self, rc, out, err):
return result

def _get(self):
with self.runner.context('channel property', output_process=self.process_command_output) as ctx:
with self.runner('channel property', output_process=self.process_command_output) as ctx:
return ctx.run()

def state_absent(self):
with self.runner.context('channel property reset', check_mode_skip=True) as ctx:
with self.runner('channel property reset', check_mode_skip=True) as ctx:
ctx.run(reset=True)
self.vars.value = None

Expand All @@ -239,7 +239,7 @@ def state_present(self):
isinstance(self.vars.previous_value, list) or \
values_len > 1

with self.runner.context('channel property create force_array values_and_types', check_mode_skip=True) as ctx:
with self.runner('channel property create force_array values_and_types', check_mode_skip=True) as ctx:
ctx.run(create=True, force_array=self.vars.is_array, values_and_types=(self.vars.value, value_type))

if not self.vars.is_array:
Expand Down
65 changes: 64 additions & 1 deletion tests/unit/plugins/module_utils/test_cmd_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ def test_arg_format(func, fmt_opt, value, expected):
@pytest.mark.parametrize('runner_input, cmd_execution, expected',
(TC_RUNNER[tc] for tc in TC_RUNNER_IDS),
ids=TC_RUNNER_IDS)
def test_runner(runner_input, cmd_execution, expected):
def test_runner_context(runner_input, cmd_execution, expected):
arg_spec = {}
params = {}
arg_formats = {}
Expand Down Expand Up @@ -304,3 +304,66 @@ def _assert_run(runner_input, cmd_execution, expected, ctx, results):
with runner.context(**runner_input['runner_ctx_args']) as ctx:
results = ctx.run(**cmd_execution['runner_ctx_run_args'])
_assert_run(runner_input, cmd_execution, expected, ctx, results)


@pytest.mark.parametrize('runner_input, cmd_execution, expected',
(TC_RUNNER[tc] for tc in TC_RUNNER_IDS),
ids=TC_RUNNER_IDS)
def test_runner_callable(runner_input, cmd_execution, expected):
arg_spec = {}
params = {}
arg_formats = {}
for k, v in runner_input['args_bundle'].items():
try:
arg_spec[k] = {'type': v['type']}
except KeyError:
pass
try:
params[k] = v['value']
except KeyError:
pass
try:
arg_formats[k] = v['fmt_func'](v['fmt_arg'])
except KeyError:
pass

orig_results = tuple(cmd_execution[x] for x in ('rc', 'out', 'err'))

print("arg_spec={0}\nparams={1}\narg_formats={2}\n".format(
arg_spec,
params,
arg_formats,
))

module = MagicMock()
type(module).argument_spec = PropertyMock(return_value=arg_spec)
type(module).params = PropertyMock(return_value=params)
module.get_bin_path.return_value = '/mock/bin/testing'
module.run_command.return_value = orig_results

runner = CmdRunner(
module=module,
command="testing",
arg_formats=arg_formats,
**runner_input['runner_init_args']
)

def _assert_run_info(actual, expected):
reduced = dict((k, actual[k]) for k in expected.keys())
assert reduced == expected, "{0}".format(reduced)

def _assert_run(runner_input, cmd_execution, expected, ctx, results):
_assert_run_info(ctx.run_info, expected['run_info'])
assert results == expected.get('results', orig_results)

exc = expected.get("exc")
if exc:
with pytest.raises(exc):
with runner(**runner_input['runner_ctx_args']) as ctx:
results = ctx.run(**cmd_execution['runner_ctx_run_args'])
_assert_run(runner_input, cmd_execution, expected, ctx, results)

else:
with runner(**runner_input['runner_ctx_args']) as ctx:
results = ctx.run(**cmd_execution['runner_ctx_run_args'])
_assert_run(runner_input, cmd_execution, expected, ctx, results)