From 517e2d48ebb3008910176aa1f88b7b7558c9a477 Mon Sep 17 00:00:00 2001 From: Alexei Znamensky <103110+russoz@users.noreply.github.com> Date: Mon, 11 Sep 2023 07:24:59 +1200 Subject: [PATCH] cpanm: using yaml-specified unit tests (#7231) * cpanm: using yaml-specified unit tests * add quote around URLs to appease pyaml@py26 * add changelog frag --- .../fragments/7231-cpanm-adjustments.yml | 2 + plugins/modules/cpanm.py | 9 +- tests/unit/plugins/modules/test_cpanm.py | 274 +----------------- tests/unit/plugins/modules/test_cpanm.yaml | 220 ++++++++++++++ 4 files changed, 236 insertions(+), 269 deletions(-) create mode 100644 changelogs/fragments/7231-cpanm-adjustments.yml create mode 100644 tests/unit/plugins/modules/test_cpanm.yaml diff --git a/changelogs/fragments/7231-cpanm-adjustments.yml b/changelogs/fragments/7231-cpanm-adjustments.yml new file mode 100644 index 0000000000..7a74aea6cf --- /dev/null +++ b/changelogs/fragments/7231-cpanm-adjustments.yml @@ -0,0 +1,2 @@ +minor_changes: + - cpanm - minor refactor when creating the ``CmdRunner`` object (https://github.com/ansible-collections/community.general/pull/7231). diff --git a/plugins/modules/cpanm.py b/plugins/modules/cpanm.py index 7aab087ec9..20ac3e7149 100644 --- a/plugins/modules/cpanm.py +++ b/plugins/modules/cpanm.py @@ -183,8 +183,9 @@ class CPANMinus(ModuleHelper): if v.name and v.from_path: self.do_raise("Parameters 'name' and 'from_path' are mutually exclusive when 'mode=new'") - self.command = self.get_bin_path(v.executable if v.executable else self.command) - self.vars.set("binary", self.command) + self.command = v.executable if v.executable else self.command + self.runner = CmdRunner(self.module, self.command, self.command_args_formats, check_rc=True) + self.vars.binary = self.runner.binary def _is_package_installed(self, name, locallib, version): def process(rc, out, err): @@ -220,8 +221,6 @@ class CPANMinus(ModuleHelper): self.do_raise(msg=err, cmd=self.vars.cmd_args) return 'is up to date' not in err and 'is up to date' not in out - runner = CmdRunner(self.module, self.command, self.command_args_formats, check_rc=True) - v = self.vars pkg_param = 'from_path' if v.from_path else 'name' @@ -235,7 +234,7 @@ class CPANMinus(ModuleHelper): return pkg_spec = self.sanitize_pkg_spec_version(v[pkg_param], v.version) - with runner(['notest', 'locallib', 'mirror', 'mirror_only', 'installdeps', 'pkg_spec'], output_process=process) as ctx: + with self.runner(['notest', 'locallib', 'mirror', 'mirror_only', 'installdeps', 'pkg_spec'], output_process=process) as ctx: self.changed = ctx.run(pkg_spec=pkg_spec) diff --git a/tests/unit/plugins/modules/test_cpanm.py b/tests/unit/plugins/modules/test_cpanm.py index cfe2304ddb..8f2a592181 100644 --- a/tests/unit/plugins/modules/test_cpanm.py +++ b/tests/unit/plugins/modules/test_cpanm.py @@ -12,280 +12,26 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -import json - -from ansible_collections.community.general.plugins.modules import cpanm import pytest - -@pytest.fixture -def patch_cpanm(mocker): - """ - Function used for mocking some parts of redhat_subscription module - """ - mocker.patch('ansible.module_utils.basic.AnsibleModule.get_bin_path', - return_value='/testbin/cpanm') +from ansible_collections.community.general.plugins.modules import cpanm +from .cmd_runner_test_utils import CmdRunnerTestHelper -TEST_CASES = [ - [ - {'name': 'Dancer'}, - { - 'id': 'install_dancer_compatibility', - 'run_command.calls': [ - ( - ['/testbin/cpanm', '-le', 'use Dancer;'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False}, - (2, '', 'error, not installed',), # output rc, out, err - ), - ( - ['/testbin/cpanm', 'Dancer'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True}, - (0, '', '',), # output rc, out, err - ), - ], - 'changed': True, - } - ], - [ - {'name': 'Dancer'}, - { - 'id': 'install_dancer_already_installed_compatibility', - 'run_command.calls': [ - ( - ['/testbin/cpanm', '-le', 'use Dancer;'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False}, - (0, '', '',), # output rc, out, err - ), - ], - 'changed': False, - } - ], - [ - {'name': 'Dancer', 'mode': 'new'}, - { - 'id': 'install_dancer', - 'run_command.calls': [( - ['/testbin/cpanm', 'Dancer'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True}, - (0, '', '',), # output rc, out, err - )], - 'changed': True, - } - ], - [ - {'name': 'MIYAGAWA/Plack-0.99_05.tar.gz'}, - { - 'id': 'install_distribution_file_compatibility', - 'run_command.calls': [( - ['/testbin/cpanm', 'MIYAGAWA/Plack-0.99_05.tar.gz'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True}, - (0, '', '',), # output rc, out, err - )], - 'changed': True, - } - ], - [ - {'name': 'MIYAGAWA/Plack-0.99_05.tar.gz', 'mode': 'new'}, - { - 'id': 'install_distribution_file', - 'run_command.calls': [( - ['/testbin/cpanm', 'MIYAGAWA/Plack-0.99_05.tar.gz'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True}, - (0, '', '',), # output rc, out, err - )], - 'changed': True, - } - ], - [ - {'name': 'Dancer', 'locallib': '/srv/webapps/my_app/extlib', 'mode': 'new'}, - { - 'id': 'install_into_locallib', - 'run_command.calls': [( - ['/testbin/cpanm', '--local-lib', '/srv/webapps/my_app/extlib', 'Dancer'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True}, - (0, '', '',), # output rc, out, err - )], - 'changed': True, - } - ], - [ - {'from_path': '/srv/webapps/my_app/src/', 'mode': 'new'}, - { - 'id': 'install_from_local_directory', - 'run_command.calls': [( - ['/testbin/cpanm', '/srv/webapps/my_app/src/'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True}, - (0, '', '',), # output rc, out, err - )], - 'changed': True, - } - ], - [ - {'name': 'Dancer', 'locallib': '/srv/webapps/my_app/extlib', 'notest': True, 'mode': 'new'}, - { - 'id': 'install_into_locallib_no_unit_testing', - 'run_command.calls': [( - ['/testbin/cpanm', '--notest', '--local-lib', '/srv/webapps/my_app/extlib', 'Dancer'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True}, - (0, '', '',), # output rc, out, err - )], - 'changed': True, - } - ], - [ - {'name': 'Dancer', 'mirror': 'http://cpan.cpantesters.org/', 'mode': 'new'}, - { - 'id': 'install_from_mirror', - 'run_command.calls': [( - ['/testbin/cpanm', '--mirror', 'http://cpan.cpantesters.org/', 'Dancer'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True}, - (0, '', '',), # output rc, out, err - )], - 'changed': True, - } - ], - [ - {'name': 'Dancer', 'system_lib': True, 'mode': 'new'}, - { - 'id': 'install_into_system_lib', - 'run_command.calls': [], - 'changed': False, - 'failed': True, - } - ], - [ - {'name': 'Dancer', 'version': '1.0', 'mode': 'new'}, - { - 'id': 'install_minversion_implicit', - 'run_command.calls': [( - ['/testbin/cpanm', 'Dancer~1.0'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True}, - (0, '', '',), # output rc, out, err - )], - 'changed': True, - } - ], - [ - {'name': 'Dancer', 'version': '~1.5', 'mode': 'new'}, - { - 'id': 'install_minversion_explicit', - 'run_command.calls': [( - ['/testbin/cpanm', 'Dancer~1.5'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True}, - (0, '', '',), # output rc, out, err - )], - 'changed': True, - } - ], - [ - {'name': 'Dancer', 'version': '@1.7', 'mode': 'new'}, - { - 'id': 'install_specific_version', - 'run_command.calls': [( - ['/testbin/cpanm', 'Dancer@1.7'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True}, - (0, '', '',), # output rc, out, err - )], - 'changed': True, - 'failed': False, - } - ], - [ - {'name': 'MIYAGAWA/Plack-0.99_05.tar.gz', 'version': '@1.7', 'mode': 'new'}, - { - 'id': 'install_specific_version_from_file_error', - 'run_command.calls': [], - 'changed': False, - 'failed': True, - 'msg': "parameter 'version' must not be used when installing from a file", - } - ], - [ - {'from_path': '~/', 'version': '@1.7', 'mode': 'new'}, - { - 'id': 'install_specific_version_from_directory_error', - 'run_command.calls': [], - 'changed': False, - 'failed': True, - 'msg': "parameter 'version' must not be used when installing from a directory", - } - ], - [ - {'name': 'git://github.com/plack/Plack.git', 'version': '@1.7', 'mode': 'new'}, - { - 'id': 'install_specific_version_from_git_url_explicit', - 'run_command.calls': [( - ['/testbin/cpanm', 'git://github.com/plack/Plack.git@1.7'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True}, - (0, '', '',), # output rc, out, err - )], - 'changed': True, - 'failed': False, - } - ], - [ - {'name': 'git://github.com/plack/Plack.git', 'version': '2.5', 'mode': 'new'}, - { - 'id': 'install_specific_version_from_git_url_implicit', - 'run_command.calls': [( - ['/testbin/cpanm', 'git://github.com/plack/Plack.git@2.5'], - {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True}, - (0, '', '',), # output rc, out, err - )], - 'changed': True, - 'failed': False, - } - ], - [ - {'name': 'git://github.com/plack/Plack.git', 'version': '~2.5', 'mode': 'new'}, - { - 'id': 'install_version_operator_from_git_url_error', - 'run_command.calls': [], - 'changed': False, - 'failed': True, - 'msg': "operator '~' not allowed in version parameter when installing from git repository", - } - ], -] -TEST_CASES_IDS = [item[1]['id'] for item in TEST_CASES] +with open("tests/unit/plugins/modules/test_cpanm.yaml", "r") as TEST_CASES: + helper = CmdRunnerTestHelper(cpanm.main, test_cases=TEST_CASES) + patch_bin = helper.cmd_fixture @pytest.mark.parametrize('patch_ansible_module, testcase', - TEST_CASES, - ids=TEST_CASES_IDS, + helper.testcases_params, ids=helper.testcases_ids, indirect=['patch_ansible_module']) @pytest.mark.usefixtures('patch_ansible_module') -def test_cpanm(mocker, capfd, patch_cpanm, testcase): +def test_module(mocker, capfd, patch_bin, testcase): """ - Run unit tests for test cases listen in TEST_CASES + Run unit tests for test cases listed in TEST_CASES """ - # Mock function used for running commands first - call_results = [item[2] for item in testcase['run_command.calls']] - mock_run_command = mocker.patch( - 'ansible_collections.community.general.plugins.module_utils.module_helper.AnsibleModule.run_command', - side_effect=call_results) - - # Try to run test case - with pytest.raises(SystemExit): - cpanm.main() - - out, err = capfd.readouterr() - results = json.loads(out) - print("results =\n%s" % results) - - assert mock_run_command.call_count == len(testcase['run_command.calls']) - if mock_run_command.call_count: - call_args_list = [(item[0][0], item[1]) for item in mock_run_command.call_args_list] - expected_call_args_list = [(item[0], item[1]) for item in testcase['run_command.calls']] - print("call args list =\n%s" % call_args_list) - print("expected args list =\n%s" % expected_call_args_list) - assert call_args_list == expected_call_args_list - - assert results.get('changed', False) == testcase['changed'] - if 'failed' in testcase: - assert results.get('failed', False) == testcase['failed'] - if 'msg' in testcase: - assert results.get('msg', '') == testcase['msg'] + with helper(testcase, mocker, capfd) as testcase_context: + testcase_context.run() diff --git a/tests/unit/plugins/modules/test_cpanm.yaml b/tests/unit/plugins/modules/test_cpanm.yaml new file mode 100644 index 0000000000..4ac7d59f35 --- /dev/null +++ b/tests/unit/plugins/modules/test_cpanm.yaml @@ -0,0 +1,220 @@ +# -*- coding: utf-8 -*- +# Copyright (c) Alexei Znamensky (russoz@gmail.com) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +--- +- id: install_dancer_compatibility + input: + name: Dancer + output: + changed: true + run_command_calls: + - command: [/testbin/perl, -le, 'use Dancer;'] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: false} + rc: 2 + out: "" + err: "error, not installed" + - command: [/testbin/cpanm, Dancer] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true} + rc: 0 + out: "" + err: "" +- id: install_dancer_already_installed_compatibility + input: + name: Dancer + output: + changed: false + run_command_calls: + - command: [/testbin/perl, -le, 'use Dancer;'] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: false} + rc: 0 + out: "" + err: "" +- id: install_dancer + input: + name: Dancer + mode: new + output: + changed: true + run_command_calls: + - command: [/testbin/cpanm, Dancer] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true} + rc: 0 + out: "" + err: "" +- id: install_distribution_file_compatibility + input: + name: MIYAGAWA/Plack-0.99_05.tar.gz + output: + changed: true + run_command_calls: + - command: [/testbin/cpanm, MIYAGAWA/Plack-0.99_05.tar.gz] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true} + rc: 0 + out: "" + err: "" +- id: install_distribution_file + input: + name: MIYAGAWA/Plack-0.99_05.tar.gz + mode: new + output: + changed: true + run_command_calls: + - command: [/testbin/cpanm, MIYAGAWA/Plack-0.99_05.tar.gz] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true} + rc: 0 + out: "" + err: "" +- id: install_into_locallib + input: + name: Dancer + mode: new + locallib: /srv/webapps/my_app/extlib + output: + changed: true + run_command_calls: + - command: [/testbin/cpanm, --local-lib, /srv/webapps/my_app/extlib, Dancer] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true} + rc: 0 + out: "" + err: "" +- id: install_from_local_directory + input: + from_path: /srv/webapps/my_app/src/ + mode: new + output: + changed: true + run_command_calls: + - command: [/testbin/cpanm, /srv/webapps/my_app/src/] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true} + rc: 0 + out: "" + err: "" +- id: install_into_locallib_no_unit_testing + input: + name: Dancer + notest: true + mode: new + locallib: /srv/webapps/my_app/extlib + output: + changed: true + run_command_calls: + - command: [/testbin/cpanm, --notest, --local-lib, /srv/webapps/my_app/extlib, Dancer] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true} + rc: 0 + out: "" + err: "" +- id: install_from_mirror + input: + name: Dancer + mode: new + mirror: "http://cpan.cpantesters.org/" + output: + changed: true + run_command_calls: + - command: [/testbin/cpanm, --mirror, "http://cpan.cpantesters.org/", Dancer] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true} + rc: 0 + out: "" + err: "" +- id: install_into_system_lib + input: + name: Dancer + mode: new + system_lib: true + output: + failed: true + run_command_calls: [] +- id: install_minversion_implicit + input: + name: Dancer + mode: new + version: "1.0" + output: + changed: true + run_command_calls: + - command: [/testbin/cpanm, Dancer~1.0] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true} + rc: 0 + out: "" + err: "" +- id: install_minversion_explicit + input: + name: Dancer + mode: new + version: "~1.5" + output: + changed: true + run_command_calls: + - command: [/testbin/cpanm, Dancer~1.5] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true} + rc: 0 + out: "" + err: "" +- id: install_specific_version + input: + name: Dancer + mode: new + version: "@1.7" + output: + changed: true + run_command_calls: + - command: [/testbin/cpanm, Dancer@1.7] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true} + rc: 0 + out: "" + err: "" +- id: install_specific_version_from_file_error + input: + name: MIYAGAWA/Plack-0.99_05.tar.gz + mode: new + version: "@1.7" + output: + failed: true + msg: parameter 'version' must not be used when installing from a file + run_command_calls: [] +- id: install_specific_version_from_directory_error + input: + from_path: ~/ + mode: new + version: "@1.7" + output: + failed: true + msg: parameter 'version' must not be used when installing from a directory + run_command_calls: [] +- id: install_specific_version_from_git_url_explicit + input: + name: "git://github.com/plack/Plack.git" + mode: new + version: "@1.7" + output: + changed: true + run_command_calls: + - command: [/testbin/cpanm, "git://github.com/plack/Plack.git@1.7"] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true} + rc: 0 + out: "" + err: "" +- id: install_specific_version_from_git_url_implicit + input: + name: "git://github.com/plack/Plack.git" + mode: new + version: "2.5" + output: + changed: true + run_command_calls: + - command: [/testbin/cpanm, "git://github.com/plack/Plack.git@2.5"] + environ: {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true} + rc: 0 + out: "" + err: "" +- id: install_version_operator_from_git_url_error + input: + name: "git://github.com/plack/Plack.git" + mode: new + version: "~2.5" + output: + failed: true + msg: operator '~' not allowed in version parameter when installing from git repository + run_command_calls: []