File: test_mod_args.py

package info (click to toggle)
ansible-core 2.19.0~beta6-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 32,628 kB
  • sloc: python: 180,313; cs: 4,929; sh: 4,601; xml: 34; makefile: 21
file content (135 lines) | stat: -rw-r--r-- 4,635 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
# Copyright 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import annotations

import pytest

from ansible.errors import AnsibleParserError
from ansible.parsing.mod_args import ModuleArgsParser
from ansible.utils.sentinel import Sentinel


class TestModArgsDwim:

    # TODO: add tests that construct ModuleArgsParser with a task reference
    # TODO: verify the AnsibleError raised on failure knows the task
    #       and the task knows the line numbers

    INVALID_MULTIPLE_ACTIONS = (
        ({'action': 'shell echo hi', 'local_action': 'shell echo hi'}, "action and local_action are mutually exclusive"),
        ({'action': 'shell echo hi', 'shell': 'echo hi'}, "conflicting action statements: shell, shell"),
        ({'local_action': 'shell echo hi', 'shell': 'echo hi'}, "conflicting action statements: shell, shell"),
    )

    def _debug(self, mod, args, to):
        print("RETURNED module = {0}".format(mod))
        print("           args = {0}".format(args))
        print("             to = {0}".format(to))

    def test_basic_shell(self):
        m = ModuleArgsParser(dict(shell='echo hi'))
        mod, args, to = m.parse()
        self._debug(mod, args, to)

        assert mod == 'shell'
        assert args == dict(
            _raw_params='echo hi',
        )
        assert to is Sentinel

    def test_basic_command(self):
        m = ModuleArgsParser(dict(command='echo hi'))
        mod, args, to = m.parse()
        self._debug(mod, args, to)

        assert mod == 'command'
        assert args == dict(
            _raw_params='echo hi',
        )
        assert to is Sentinel

    def test_shell_with_modifiers(self):
        m = ModuleArgsParser(dict(shell='/bin/foo creates=/tmp/baz removes=/tmp/bleep'))
        mod, args, to = m.parse()
        self._debug(mod, args, to)

        assert mod == 'shell'
        assert args == dict(
            creates='/tmp/baz',
            removes='/tmp/bleep',
            _raw_params='/bin/foo',
        )
        assert to is Sentinel

    def test_normal_usage(self):
        m = ModuleArgsParser(dict(copy='src=a dest=b'))
        mod, args, to = m.parse()
        self._debug(mod, args, to)

        assert mod, 'copy'
        assert args, dict(src='a', dest='b')
        assert to is Sentinel

    def test_complex_args(self):
        m = ModuleArgsParser(dict(copy=dict(src='a', dest='b')))
        mod, args, to = m.parse()
        self._debug(mod, args, to)

        assert mod, 'copy'
        assert args, dict(src='a', dest='b')
        assert to is Sentinel

    def test_action_with_complex(self):
        m = ModuleArgsParser(dict(action=dict(module='copy', src='a', dest='b')))
        mod, args, to = m.parse()
        self._debug(mod, args, to)

        assert mod == 'copy'
        assert args == dict(src='a', dest='b')
        assert to is Sentinel

    def test_action_with_complex_and_complex_args(self):
        m = ModuleArgsParser(dict(action=dict(module='copy', args=dict(src='a', dest='b'))))
        mod, args, to = m.parse()
        self._debug(mod, args, to)

        assert mod == 'copy'
        assert args == dict(src='a', dest='b')
        assert to is Sentinel

    def test_local_action_string(self):
        m = ModuleArgsParser(dict(local_action='copy src=a dest=b'))
        mod, args, delegate_to = m.parse()
        self._debug(mod, args, delegate_to)

        assert mod == 'copy'
        assert args == dict(src='a', dest='b')
        assert delegate_to == 'localhost'

    @pytest.mark.parametrize("args_dict, msg", INVALID_MULTIPLE_ACTIONS)
    def test_multiple_actions(self, args_dict, msg):
        m = ModuleArgsParser(args_dict)
        with pytest.raises(AnsibleParserError) as err:
            m.parse()

        assert err.value.args[0] == msg

    @pytest.mark.usefixtures('collection_loader')
    def test_multiple_actions_ping_shell(self):
        args_dict = {'ping': 'data=hi', 'shell': 'echo hi'}
        m = ModuleArgsParser(args_dict)
        with pytest.raises(AnsibleParserError) as err:
            m.parse()

        assert err.value.args[0] == f'conflicting action statements: {", ".join(args_dict)}'

    @pytest.mark.usefixtures('collection_loader')
    def test_bogus_action(self):
        args_dict = {'bogusaction': {}}
        m = ModuleArgsParser(args_dict)
        with pytest.raises(AnsibleParserError) as err:
            m.parse()

        assert err.value.args[0].startswith(f"couldn't resolve module/action '{next(iter(args_dict))}'")