1from __future__ import absolute_import, division, print_function
2
3__metaclass__ = type
4
5import sys
6
7import pytest
8
9from ansible.playbook.task import Task
10
11from ansible_collections.sensu.sensu_go.plugins.module_utils import (
12    bonsai, errors,
13)
14from ansible_collections.sensu.sensu_go.plugins.action import bonsai_asset
15
16pytestmark = pytest.mark.skipif(
17    sys.version_info < (2, 7), reason="requires python2.7 or higher"
18)
19
20
21class TestValidate:
22    @pytest.mark.parametrize("name,args,required,typ", [
23        # Required values must match the selected type.
24        ("a", dict(a=3), True, int),
25        ("a", dict(a=3.3), True, float),
26        ("a", dict(a="b"), True, str),
27        ("a", dict(a=[]), True, list),
28        ("a", dict(a={}), True, dict),
29        # Optional values are not checked for type-correctness if they are
30        # missing.
31        ("a", dict(), False, int),
32        ("a", dict(), False, float),
33        ("a", dict(), False, str),
34        ("a", dict(), False, list),
35        ("a", dict(), False, dict),
36    ])
37    def test_valid_values(self, name, args, required, typ):
38        bonsai_asset.validate(name, args, required, typ)
39
40    def test_missing_required(self):
41        with pytest.raises(errors.Error, match="required"):
42            bonsai_asset.validate("a", {}, True, str)
43
44    def test_invalid_type(self):
45        with pytest.raises(errors.Error, match="should"):
46            bonsai_asset.validate("a", dict(a=3), True, str)
47
48    def test_invalid_type_for_optional_value(self):
49        with pytest.raises(errors.Error, match="should"):
50            bonsai_asset.validate("a", dict(a=3), False, dict)
51
52
53class TestValidateArguments:
54    def test_valid_minimal_args(self):
55        bonsai_asset.ActionModule.validate_arguments(dict(
56            name="abc", version="1.2.3",
57        ))
58
59    def test_valid_all_args(self):
60        bonsai_asset.ActionModule.validate_arguments(dict(
61            name="abc", version="1.2.3", rename="def",
62            labels={}, annotations={},
63        ))
64
65    def test_valid_unicode_strings_python2(self):
66        bonsai_asset.ActionModule.validate_arguments(dict(
67            name=u"abc", version=u"1.2.3", rename=u"def",
68            labels={}, annotations={},
69        ))
70
71    def test_invalid_name(self):
72        with pytest.raises(errors.Error, match="name"):
73            bonsai_asset.ActionModule.validate_arguments(dict(
74                name=1.234, version="1.2.3",
75            ))
76
77    def test_missing_name(self):
78        with pytest.raises(errors.Error, match="name"):
79            bonsai_asset.ActionModule.validate_arguments(dict(
80                version="1.2.3",
81            ))
82
83    def test_invalid_version(self):
84        with pytest.raises(errors.Error, match="version"):
85            bonsai_asset.ActionModule.validate_arguments(dict(
86                name="abc", version=1.2,
87            ))
88
89    def test_missing_version(self):
90        with pytest.raises(errors.Error, match="version"):
91            bonsai_asset.ActionModule.validate_arguments(dict(
92                name="abc",
93            ))
94
95    def test_invalid_rename(self):
96        with pytest.raises(errors.Error, match="rename"):
97            bonsai_asset.ActionModule.validate_arguments(dict(
98                name="abc", version="1.2.3", rename=1,
99            ))
100
101    def test_invalid_labels(self):
102        with pytest.raises(errors.Error, match="labels"):
103            bonsai_asset.ActionModule.validate_arguments(dict(
104                name="abc", version="1.2.3", labels=1,
105            ))
106
107    def test_invalid_annotations(self):
108        with pytest.raises(errors.Error, match="annotations"):
109            bonsai_asset.ActionModule.validate_arguments(dict(
110                name="abc", version="1.2.3", annotations=1,
111            ))
112
113
114class TestBuildAssetArgs:
115    def test_no_additional_metadata(self, mocker):
116        bonsai_params = mocker.patch.object(bonsai, "get_asset_parameters")
117        bonsai_params.return_value = dict(
118            builds=[], labels=None, annotations=None,
119        )
120
121        result = bonsai_asset.ActionModule.build_asset_args(dict(
122            name="test/asset",
123            version="1.2.3",
124        ))
125
126        assert result == dict(
127            name="test/asset",
128            state="present",
129            builds=[],
130        )
131
132    def test_bonsai_metadata_only(self, mocker):
133        bonsai_params = mocker.patch.object(bonsai, "get_asset_parameters")
134        bonsai_params.return_value = dict(
135            builds=[], labels=dict(a="b"), annotations=dict(c="d"),
136        )
137
138        result = bonsai_asset.ActionModule.build_asset_args(dict(
139            name="test/asset",
140            version="1.2.3",
141        ))
142
143        assert result == dict(
144            name="test/asset",
145            state="present",
146            builds=[],
147            annotations=dict(c="d"),
148            labels=dict(a="b"),
149        )
150
151    def test_user_metadata_only(self, mocker):
152        bonsai_params = mocker.patch.object(bonsai, "get_asset_parameters")
153        bonsai_params.return_value = dict(
154            builds=[1, 2, 3], labels=None, annotations=None,
155        )
156
157        result = bonsai_asset.ActionModule.build_asset_args(dict(
158            name="test/asset",
159            version="1.2.3",
160            labels=dict(my="label"),
161            annotations=dict(my="annotation"),
162        ))
163
164        assert result == dict(
165            name="test/asset",
166            state="present",
167            builds=[1, 2, 3],
168            annotations=dict(my="annotation"),
169            labels=dict(my="label"),
170        )
171
172    def test_mixed_metadata(self, mocker):
173        bonsai_params = mocker.patch.object(bonsai, "get_asset_parameters")
174        bonsai_params.return_value = dict(
175            builds=[], labels=dict(my="x", a="b"), annotations=dict(my="c"),
176        )
177
178        result = bonsai_asset.ActionModule.build_asset_args(dict(
179            name="test/asset",
180            version="1.2.3",
181            labels=dict(my="label"),
182            annotations=dict(my="annotation"),
183        ))
184
185        assert result == dict(
186            name="test/asset",
187            state="present",
188            builds=[],
189            annotations=dict(my="annotation"),
190            labels=dict(my="label", a="b"),
191        )
192
193    def test_rename(self, mocker):
194        bonsai_params = mocker.patch.object(bonsai, "get_asset_parameters")
195        bonsai_params.return_value = dict(
196            builds=[], labels=None, annotations=None,
197        )
198
199        result = bonsai_asset.ActionModule.build_asset_args(dict(
200            name="test/asset",
201            version="1.2.3",
202            rename="my-asset",
203        ))
204
205        assert result == dict(
206            name="my-asset",
207            state="present",
208            builds=[],
209        )
210
211    def test_auth_passthrough(self, mocker):
212        bonsai_params = mocker.patch.object(bonsai, "get_asset_parameters")
213        bonsai_params.return_value = dict(
214            builds=[], labels=None, annotations=None,
215        )
216
217        result = bonsai_asset.ActionModule.build_asset_args(dict(
218            auth=dict(url="http://localhost:1234"),
219            name="test/asset",
220            version="1.2.3",
221        ))
222
223        assert result == dict(
224            auth=dict(url="http://localhost:1234"),
225            name="test/asset",
226            state="present",
227            builds=[],
228        )
229
230    def test_namespace_passthrough(self, mocker):
231        bonsai_params = mocker.patch.object(bonsai, "get_asset_parameters")
232        bonsai_params.return_value = dict(
233            builds=[], labels=None, annotations=None,
234        )
235
236        result = bonsai_asset.ActionModule.build_asset_args(dict(
237            namespace='default',
238            name="test/asset",
239            version="1.2.3",
240        ))
241
242        assert result == dict(
243            name="test/asset",
244            namespace='default',
245            state="present",
246            builds=[],
247        )
248
249    def test_fail_bonsai(self, mocker):
250        bonsai_params = mocker.patch.object(bonsai, "get_asset_parameters")
251        bonsai_params.side_effect = errors.BonsaiError("Bonsai bad")
252
253        with pytest.raises(errors.Error, match="Bonsai bad"):
254            bonsai_asset.ActionModule.build_asset_args(dict(
255                name="test/asset",
256                version="1.2.3",
257            ))
258
259        bonsai_params.assert_called_with("test/asset", "1.2.3")
260
261
262class TestRun:
263    def test_success(self, mocker):
264        bonsai_params = mocker.patch.object(bonsai, "get_asset_parameters")
265        bonsai_params.return_value = dict(
266            builds=[], labels=None, annotations=None,
267        )
268        task = mocker.MagicMock(Task, async_val=0, args=dict(
269            name="test/asset",
270            version="1.2.3",
271        ))
272        action = bonsai_asset.ActionModule(
273            task, mocker.MagicMock(), mocker.MagicMock(), loader=None,
274            templar=None, shared_loader_obj=None,
275        )
276        action._execute_module = mocker.MagicMock(return_value=dict(a=3))
277
278        result = action.run()
279
280        assert result == dict(a=3)
281
282    def test_fail(self, mocker):
283        bonsai_params = mocker.patch.object(bonsai, "get_asset_parameters")
284        bonsai_params.return_value = dict(
285            builds=[], labels=None, annotations=None,
286        )
287        task = mocker.MagicMock(Task, async_val=0, args=dict(
288            name="test/asset",
289        ))
290        action = bonsai_asset.ActionModule(
291            task, mocker.MagicMock(), mocker.MagicMock(), loader=None,
292            templar=None, shared_loader_obj=None,
293        )
294        action._execute_module = mocker.MagicMock(return_value=dict(a=3))
295
296        result = action.run()
297
298        assert result["failed"] is True
299