# Copyright (c) 2020, Thales Netherlands # Copyright (c) 2021, Ansible Project # 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 from __future__ import annotations import unittest from unittest.mock import patch from ansible.errors import AnsibleError from ansible.plugins import AnsiblePlugin from ansible.template import Templar from ansible.utils.display import Display from ansible_collections.community.internal_test_tools.tests.unit.mock.loader import DictDataLoader from ansible_collections.community.general.plugins.lookup import merge_variables class TestMergeVariablesLookup(unittest.TestCase): class HostVarsMock(dict): def __getattr__(self, item): return super().__getitem__(item) def __setattr__(self, item, value): return super().__setitem__(item, value) def raw_get(self, host): return super().__getitem__(host) def setUp(self): self.loader = DictDataLoader({}) self.templar = Templar(loader=self.loader, variables={}) self.merge_vars_lookup = merge_variables.LookupModule(loader=self.loader, templar=self.templar) @patch.object(AnsiblePlugin, "set_options") @patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", None]) @patch.object(Templar, "template", side_effect=[["item1"], ["item3"]]) def test_merge_list(self, mock_set_options, mock_get_option, mock_template): results = self.merge_vars_lookup.run( ["__merge_list"], {"testlist1__merge_list": ["item1"], "testlist2": ["item2"], "testlist3__merge_list": ["item3"]}, ) self.assertEqual(results, [["item1", "item3"]]) @patch.object(AnsiblePlugin, "set_options") @patch.object(AnsiblePlugin, "get_option", side_effect=[["initial_item"], "ignore", "suffix", None]) @patch.object(Templar, "template", side_effect=[["item1"], ["item3"]]) def test_merge_list_with_initial_value(self, mock_set_options, mock_get_option, mock_template): results = self.merge_vars_lookup.run( ["__merge_list"], {"testlist1__merge_list": ["item1"], "testlist2": ["item2"], "testlist3__merge_list": ["item3"]}, ) self.assertEqual(results, [["initial_item", "item1", "item3"]]) @patch.object(AnsiblePlugin, "set_options") @patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", None]) @patch.object( Templar, "template", side_effect=[{"item1": "test", "list_item": ["test1"]}, {"item2": "test", "list_item": ["test2"]}], ) def test_merge_dict(self, mock_set_options, mock_get_option, mock_template): results = self.merge_vars_lookup.run( ["__merge_dict"], { "testdict1__merge_dict": {"item1": "test", "list_item": ["test1"]}, "testdict2__merge_dict": {"item2": "test", "list_item": ["test2"]}, }, ) self.assertEqual(results, [{"item1": "test", "item2": "test", "list_item": ["test1", "test2"]}]) @patch.object(AnsiblePlugin, "set_options") @patch.object( AnsiblePlugin, "get_option", side_effect=[{"initial_item": "random value", "list_item": ["test0"]}, "ignore", "suffix", None], ) @patch.object( Templar, "template", side_effect=[{"item1": "test", "list_item": ["test1"]}, {"item2": "test", "list_item": ["test2"]}], ) def test_merge_dict_with_initial_value(self, mock_set_options, mock_get_option, mock_template): results = self.merge_vars_lookup.run( ["__merge_dict"], { "testdict1__merge_dict": {"item1": "test", "list_item": ["test1"]}, "testdict2__merge_dict": {"item2": "test", "list_item": ["test2"]}, }, ) self.assertEqual( results, [ { "initial_item": "random value", "item1": "test", "item2": "test", "list_item": ["test0", "test1", "test2"], } ], ) @patch.object(AnsiblePlugin, "set_options") @patch.object(AnsiblePlugin, "get_option", side_effect=[None, "warn", "suffix", None]) @patch.object(Templar, "template", side_effect=[{"item": "value1"}, {"item": "value2"}]) @patch.object(Display, "warning") def test_merge_dict_non_unique_warning(self, mock_set_options, mock_get_option, mock_template, mock_display): results = self.merge_vars_lookup.run( ["__merge_non_unique"], {"testdict1__merge_non_unique": {"item": "value1"}, "testdict2__merge_non_unique": {"item": "value2"}}, ) self.assertTrue(mock_display.called) self.assertEqual(results, [{"item": "value2"}]) @patch.object(AnsiblePlugin, "set_options") @patch.object(AnsiblePlugin, "get_option", side_effect=[None, "error", "suffix", None]) @patch.object(Templar, "template", side_effect=[{"item": "value1"}, {"item": "value2"}]) def test_merge_dict_non_unique_error(self, mock_set_options, mock_get_option, mock_template): with self.assertRaises(AnsibleError): self.merge_vars_lookup.run( ["__merge_non_unique"], {"testdict1__merge_non_unique": {"item": "value1"}, "testdict2__merge_non_unique": {"item": "value2"}}, ) @patch.object(AnsiblePlugin, "set_options") @patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", None]) @patch.object(Templar, "template", side_effect=[{"item1": "test", "list_item": ["test1"]}, ["item2", "item3"]]) def test_merge_list_and_dict(self, mock_set_options, mock_get_option, mock_template): with self.assertRaises(AnsibleError): self.merge_vars_lookup.run( ["__merge_var"], { "testlist__merge_var": {"item1": "test", "list_item": ["test1"]}, "testdict__merge_var": ["item2", "item3"], }, ) @patch.object(AnsiblePlugin, "set_options") @patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", ["all"]]) @patch.object( Templar, "template", side_effect=[ {"var": [{"item1": "value1", "item2": "value2"}]}, {"var": [{"item5": "value5", "item6": "value6"}]}, ], ) def test_merge_dict_group_all(self, mock_set_options, mock_get_option, mock_template): hostvars = self.HostVarsMock( { "host1": { "group_names": ["dummy1"], "inventory_hostname": "host1", "1testlist__merge_var": {"var": [{"item1": "value1", "item2": "value2"}]}, }, "host2": { "group_names": ["dummy1"], "inventory_hostname": "host2", "2otherlist__merge_var": {"var": [{"item5": "value5", "item6": "value6"}]}, }, } ) variables = {"inventory_hostname": "host1", "hostvars": hostvars} results = self.merge_vars_lookup.run(["__merge_var"], variables) self.assertEqual( results, [{"var": [{"item1": "value1", "item2": "value2"}, {"item5": "value5", "item6": "value6"}]}] ) @patch.object(AnsiblePlugin, "set_options") @patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", ["dummy1"]]) @patch.object( Templar, "template", side_effect=[ {"var": [{"item1": "value1", "item2": "value2"}]}, {"var": [{"item5": "value5", "item6": "value6"}]}, ], ) def test_merge_dict_group_single(self, mock_set_options, mock_get_option, mock_template): hostvars = self.HostVarsMock( { "host1": { "group_names": ["dummy1"], "inventory_hostname": "host1", "1testlist__merge_var": {"var": [{"item1": "value1", "item2": "value2"}]}, }, "host2": { "group_names": ["dummy1"], "inventory_hostname": "host2", "2otherlist__merge_var": {"var": [{"item5": "value5", "item6": "value6"}]}, }, "host3": { "group_names": ["dummy2"], "inventory_hostname": "host3", "3otherlist__merge_var": {"var": [{"item3": "value3", "item4": "value4"}]}, }, } ) variables = {"inventory_hostname": "host1", "hostvars": hostvars} results = self.merge_vars_lookup.run(["__merge_var"], variables) self.assertEqual( results, [{"var": [{"item1": "value1", "item2": "value2"}, {"item5": "value5", "item6": "value6"}]}] ) @patch.object(AnsiblePlugin, "set_options") @patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", ["dummy1", "dummy2"]]) @patch.object( Templar, "template", side_effect=[ {"var": [{"item1": "value1", "item2": "value2"}]}, {"var": [{"item5": "value5", "item6": "value6"}]}, ], ) def test_merge_dict_group_multiple(self, mock_set_options, mock_get_option, mock_template): hostvars = self.HostVarsMock( { "host1": { "group_names": ["dummy1"], "inventory_hostname": "host1", "1testlist__merge_var": {"var": [{"item1": "value1", "item2": "value2"}]}, }, "host2": { "group_names": ["dummy2"], "inventory_hostname": "host2", "2otherlist__merge_var": {"var": [{"item5": "value5", "item6": "value6"}]}, }, "host3": { "group_names": ["dummy3"], "inventory_hostname": "host3", "3otherlist__merge_var": {"var": [{"item3": "value3", "item4": "value4"}]}, }, } ) variables = {"inventory_hostname": "host1", "hostvars": hostvars} results = self.merge_vars_lookup.run(["__merge_var"], variables) self.assertEqual( results, [{"var": [{"item1": "value1", "item2": "value2"}, {"item5": "value5", "item6": "value6"}]}] ) @patch.object(AnsiblePlugin, "set_options") @patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", ["dummy1", "dummy2"]]) @patch.object( Templar, "template", side_effect=[ ["item1"], ["item5"], ], ) def test_merge_list_group_multiple(self, mock_set_options, mock_get_option, mock_template): hostvars = self.HostVarsMock( { "host1": {"group_names": ["dummy1"], "inventory_hostname": "host1", "1testlist__merge_var": ["item1"]}, "host2": {"group_names": ["dummy2"], "inventory_hostname": "host2", "2otherlist__merge_var": ["item5"]}, "host3": {"group_names": ["dummy3"], "inventory_hostname": "host3", "3otherlist__merge_var": ["item3"]}, } ) variables = {"inventory_hostname": "host1", "hostvars": hostvars} results = self.merge_vars_lookup.run(["__merge_var"], variables) self.assertEqual(results, [["item1", "item5"]])