/
githubmirror
/
salt
Обзор
Документация
Войти
/
githubmirror
/
salt
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
tests/pytests/unit/states/test_host.py
507 строк
17 KB
Pedro Algarvio
Update code to be Py3.7+ to reduce merge forward conflicts
29 фев 2024, 13:16
29 фев 2024, 13:16
03ad4c6
Код
Авторство
О чём код?
""" :codeauthor: Rahul Handay <rahulha@saltstack.com> """ import logging import pytest import salt.states.host as host from tests.support.mock import MagicMock, call, patch log = logging.getLogger(__name__) hostname = "salt" localhost_ip = "127.0.0.1" ip_list = ["203.0.113.113", "203.0.113.14"] default_hosts = { ip_list[0]: {"aliases": [hostname]}, ip_list[1]: {"aliases": [hostname]}, } @pytest.fixture def configure_loader_modules(): return { host: {"__opts__": {"test": False}}, } def test_present(): """ Test to ensures that the named host is present with the given ip """ add_host = MagicMock(return_value=True) rm_host = MagicMock(return_value=True) hostname = "salt" ip_str = "127.0.0.1" ip_list = ["10.1.2.3", "10.4.5.6"] # Case 1: No match for hostname. Single IP address passed to the state. list_hosts = MagicMock(return_value={"127.0.0.1": {"aliases": ["localhost"]}}) with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": add_host, "hosts.rm_host": rm_host, }, ): ret = host.present(hostname, ip_str) assert ret["result"] is True assert ret["comment"] == f"Added host {hostname} ({ip_str})", ret["comment"] assert ret["changes"] == {"added": {ip_str: [hostname]}}, ret["changes"] expected = [call(ip_str, hostname)] assert add_host.mock_calls == expected, add_host.mock_calls assert rm_host.mock_calls == [], rm_host.mock_calls # Case 2: No match for hostname. Multiple IP addresses passed to the # state. list_hosts = MagicMock(return_value={"127.0.0.1": {"aliases": ["localhost"]}}) add_host.reset_mock() rm_host.reset_mock() with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": add_host, "hosts.rm_host": rm_host, }, ): ret = host.present(hostname, ip_list) assert ret["result"] is True assert f"Added host {hostname} ({ip_list[0]})" in ret["comment"] assert f"Added host {hostname} ({ip_list[1]})" in ret["comment"] assert ret["changes"] == { "added": {ip_list[0]: [hostname], ip_list[1]: [hostname]} }, ret["changes"] expected = sorted(call(x, hostname) for x in ip_list) assert sorted(add_host.mock_calls) == expected, add_host.mock_calls assert rm_host.mock_calls == [], rm_host.mock_calls # Case 3: Match for hostname, but no matching IP. Single IP address # passed to the state. list_hosts = MagicMock( return_value={ "127.0.0.1": {"aliases": ["localhost"]}, ip_list[0]: {"aliases": [hostname]}, } ) add_host.reset_mock() rm_host.reset_mock() with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": add_host, "hosts.rm_host": rm_host, }, ): ret = host.present(hostname, ip_str) assert ret["result"] is True assert f"Added host {hostname} ({ip_str})" in ret["comment"] assert ( f"Host {hostname} present for IP address {ip_list[0]}" in ret["warnings"][0] ) assert ret["changes"] == {"added": {ip_str: [hostname]}}, ret["changes"] expected = [call(ip_str, hostname)] assert add_host.mock_calls == expected, add_host.mock_calls assert rm_host.mock_calls == [], rm_host.mock_calls # Case 3a: Repeat the above with clean=True add_host.reset_mock() rm_host.reset_mock() with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": add_host, "hosts.rm_host": rm_host, }, ): ret = host.present(hostname, ip_str, clean=True) assert ret["result"] is True assert f"Added host {hostname} ({ip_str})" in ret["comment"] assert f"Removed host {hostname} ({ip_list[0]})" in ret["comment"] assert ret["changes"] == { "added": {ip_str: [hostname]}, "removed": {ip_list[0]: [hostname]}, }, ret["changes"] expected = [call(ip_str, hostname)] assert add_host.mock_calls == expected, add_host.mock_calls expected = [call(ip_list[0], hostname)] assert rm_host.mock_calls == expected, rm_host.mock_calls # Case 4: Match for hostname, but no matching IP. Multiple IP addresses # passed to the state. cur_ip = "1.2.3.4" list_hosts = MagicMock( return_value={ "127.0.0.1": {"aliases": ["localhost"]}, cur_ip: {"aliases": [hostname]}, } ) add_host.reset_mock() rm_host.reset_mock() with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": add_host, "hosts.rm_host": rm_host, }, ): ret = host.present(hostname, ip_list) assert ret["result"] is True assert f"Added host {hostname} ({ip_list[0]})" in ret["comment"] assert f"Added host {hostname} ({ip_list[1]})" in ret["comment"] assert ret["changes"] == { "added": {ip_list[0]: [hostname], ip_list[1]: [hostname]}, }, ret["changes"] expected = sorted(call(x, hostname) for x in ip_list) assert sorted(add_host.mock_calls) == expected, add_host.mock_calls assert rm_host.mock_calls == [], rm_host.mock_calls # Case 4a: Repeat the above with clean=True add_host.reset_mock() rm_host.reset_mock() with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": add_host, "hosts.rm_host": rm_host, }, ): ret = host.present(hostname, ip_list, clean=True) assert ret["result"] is True assert f"Added host {hostname} ({ip_list[0]})" in ret["comment"] assert f"Added host {hostname} ({ip_list[1]})" in ret["comment"] assert f"Removed host {hostname} ({cur_ip})" in ret["comment"] assert ret["changes"] == { "added": {ip_list[0]: [hostname], ip_list[1]: [hostname]}, "removed": {cur_ip: [hostname]}, }, ret["changes"] expected = sorted(call(x, hostname) for x in ip_list) assert sorted(add_host.mock_calls) == expected, add_host.mock_calls expected = [call(cur_ip, hostname)] assert rm_host.mock_calls == expected, rm_host.mock_calls # Case 5: Multiple IP addresses passed to the state. One of them # matches, the other does not. There is also a non-matching IP that # must be removed. cur_ip = "1.2.3.4" list_hosts = MagicMock( return_value={ "127.0.0.1": {"aliases": ["localhost"]}, cur_ip: {"aliases": [hostname]}, ip_list[0]: {"aliases": [hostname]}, } ) add_host.reset_mock() rm_host.reset_mock() with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": add_host, "hosts.rm_host": rm_host, }, ): ret = host.present(hostname, ip_list) assert ret["result"] is True assert f"Added host {hostname} ({ip_list[1]})" in ret["comment"] assert ret["changes"] == {"added": {ip_list[1]: [hostname]}}, ret["changes"] expected = [call(ip_list[1], hostname)] assert add_host.mock_calls == expected, add_host.mock_calls assert rm_host.mock_calls == [], rm_host.mock_calls # Case 5a: Repeat the above with clean=True add_host.reset_mock() rm_host.reset_mock() with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": add_host, "hosts.rm_host": rm_host, }, ): ret = host.present(hostname, ip_list, clean=True) assert ret["result"] is True assert f"Added host {hostname} ({ip_list[1]})" in ret["comment"] assert f"Removed host {hostname} ({cur_ip})" in ret["comment"] assert ret["changes"] == { "added": {ip_list[1]: [hostname]}, "removed": {cur_ip: [hostname]}, }, ret["changes"] expected = [call(ip_list[1], hostname)] assert add_host.mock_calls == expected, add_host.mock_calls expected = [call(cur_ip, hostname)] assert rm_host.mock_calls == expected, rm_host.mock_calls # Case 6: Single IP address passed to the state, which matches the # current configuration for that hostname. No changes should be made. list_hosts = MagicMock(return_value={ip_str: {"aliases": [hostname]}}) add_host.reset_mock() rm_host.reset_mock() with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": add_host, "hosts.rm_host": rm_host, }, ): ret = host.present(hostname, ip_str) assert ret["result"] is True assert f"Host {hostname} ({ip_str}) already present" in ret["comment"] assert ret["changes"] == {}, ret["changes"] assert add_host.mock_calls == [], add_host.mock_calls assert rm_host.mock_calls == [], rm_host.mock_calls # Case 7: Multiple IP addresses passed to the state, which both match # the current configuration for that hostname. No changes should be # made. list_hosts = MagicMock( return_value={ ip_list[0]: {"aliases": [hostname]}, ip_list[1]: {"aliases": [hostname]}, } ) add_host.reset_mock() rm_host.reset_mock() with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": add_host, "hosts.rm_host": rm_host, }, ): ret = host.present(hostname, ip_list) assert ret["result"] is True assert f"Host {hostname} ({ip_list[0]}) already present" in ret["comment"] assert f"Host {hostname} ({ip_list[1]}) already present" in ret["comment"] assert ret["changes"] == {}, ret["changes"] assert add_host.mock_calls == [], add_host.mock_calls assert rm_host.mock_calls == [], rm_host.mock_calls # Case 8: Passing a comment to host.present with multiple IPs list_hosts = MagicMock(return_value={"127.0.0.1": {"aliases": ["localhost"]}}) add_host_mock = MagicMock(return_value=True) rm_host_mock = MagicMock(return_value=True) set_comment_mock = MagicMock(return_value=True) add_host_mock.reset_mock() rm_host_mock.reset_mock() set_comment_mock.reset_mock() with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": add_host_mock, "hosts.rm_host": rm_host_mock, "hosts.set_comment": set_comment_mock, }, ): ret = host.present(hostname, ip_list, comment="A comment") assert ret["result"] is True assert f"Added host {hostname} ({ip_list[0]})" in ret["comment"] assert f"Added host {hostname} ({ip_list[1]})" in ret["comment"] assert f"Set comment for host {ip_list[0]} (A comment)" in ret["comment"] assert f"Set comment for host {ip_list[1]} (A comment)" in ret["comment"] assert ret["changes"] == { "added": {ip_list[0]: [hostname], ip_list[1]: [hostname]}, "comment_added": {ip_list[0]: ["A comment"], ip_list[1]: ["A comment"]}, }, ret["changes"] expected = sorted(call(x, hostname) for x in ip_list) assert sorted(add_host_mock.mock_calls) == expected, add_host_mock.mock_calls expected = sorted(call(x, "A comment") for x in ip_list) assert ( sorted(set_comment_mock.mock_calls) == expected ), set_comment_mock.mock_calls assert rm_host_mock.mock_calls == [], rm_host_mock.mock_calls def test_host_present_should_return_True_if_test_and_no_changes(): add_host_mock = MagicMock(return_value=True) rm_host_mock = MagicMock(return_value=True) expected = { "comment": "Host {} ({}) already present".format( hostname, ip_list[0], ), "changes": {}, "name": hostname, "result": True, } list_hosts = MagicMock( return_value={ip_list[0]: {"aliases": [hostname]}}, ) with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": add_host_mock, "hosts.rm_host": rm_host_mock, }, ): with patch.dict(host.__opts__, {"test": True}): ret = host.present(hostname, ip_list[:1]) assert ret == expected def test_host_present_should_return_None_if_test_and_adding(): add_host_mock = MagicMock(return_value=True) rm_host_mock = MagicMock(return_value=True) expected = { "comment": "\n".join( ["Host {} ({}) already present", "Host {} ({}) would be added"] ).format( hostname, ip_list[0], hostname, ip_list[1], ), "changes": {"added": {ip_list[1]: [hostname]}}, "name": hostname, "result": None, } list_hosts = MagicMock( return_value={ip_list[0]: {"aliases": [hostname]}}, ) with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": add_host_mock, "hosts.rm_host": rm_host_mock, }, ): with patch.dict(host.__opts__, {"test": True}): ret = host.present(hostname, ip_list) assert ret == expected def test_host_present_should_return_None_if_test_and_removing(): add_host_mock = MagicMock(return_value=True) rm_host_mock = MagicMock(return_value=True) list_hosts_mock = MagicMock(return_value=default_hosts) expected = { "comment": "\n".join( ["Host {} ({}) already present", "Host {} ({}) would be removed"] ).format( hostname, ip_list[0], hostname, ip_list[1], ), "changes": {"removed": {ip_list[1]: [hostname]}}, "name": hostname, "result": None, } with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts_mock, "hosts.add_host": add_host_mock, "hosts.rm_host": rm_host_mock, }, ): with patch.dict(host.__opts__, {"test": True}): ret = host.present(hostname, ip_list[:1], clean=True) assert ret == expected def test_absent(): """ Test to ensure that the named host is absent """ ret = { "changes": {}, "comment": "Host salt (127.0.0.1) already absent", "name": "salt", "result": True, } mock = MagicMock(return_value=False) with patch.dict(host.__salt__, {"hosts.has_pair": mock}): assert host.absent("salt", "127.0.0.1") == ret def test_only_already(): """ Test only() when the state hasn't changed """ expected = { "name": "127.0.1.1", "changes": {}, "result": True, "comment": 'IP address 127.0.1.1 already set to "foo.bar"', } mock1 = MagicMock(return_value=["foo.bar"]) with patch.dict(host.__salt__, {"hosts.get_alias": mock1}): mock2 = MagicMock(return_value=True) with patch.dict(host.__salt__, {"hosts.set_host": mock2}): with patch.dict(host.__opts__, {"test": False}): assert expected == host.only("127.0.1.1", "foo.bar") def test_only_dryrun(): """ Test only() when state would change, but it's a dry run """ expected = { "name": "127.0.1.1", "changes": {}, "result": None, "comment": 'Would change 127.0.1.1 from "foo.bar" to "foo.bar foo"', } mock1 = MagicMock(return_value=["foo.bar"]) with patch.dict(host.__salt__, {"hosts.get_alias": mock1}): mock2 = MagicMock(return_value=True) with patch.dict(host.__salt__, {"hosts.set_host": mock2}): with patch.dict(host.__opts__, {"test": True}): assert expected == host.only("127.0.1.1", ["foo.bar", "foo"]) def test_only_fail(): """ Test only() when state change fails """ expected = { "name": "127.0.1.1", "changes": {}, "result": False, "comment": "hosts.set_host failed to change 127.0.1.1" + ' from "foo.bar" to "foo.bar foo"', } mock = MagicMock(return_value=["foo.bar"]) with patch.dict(host.__salt__, {"hosts.get_alias": mock}): mock = MagicMock(return_value=False) with patch.dict(host.__salt__, {"hosts.set_host": mock}): with patch.dict(host.__opts__, {"test": False}): assert expected == host.only("127.0.1.1", ["foo.bar", "foo"]) def test_only_success(): """ Test only() when state successfully changes """ expected = { "name": "127.0.1.1", "changes": {"127.0.1.1": {"old": "foo.bar", "new": "foo.bar foo"}}, "result": True, "comment": "successfully changed 127.0.1.1" + ' from "foo.bar" to "foo.bar foo"', } mock = MagicMock(return_value=["foo.bar"]) with patch.dict(host.__salt__, {"hosts.get_alias": mock}): mock = MagicMock(return_value=True) with patch.dict(host.__salt__, {"hosts.set_host": mock}): with patch.dict(host.__opts__, {"test": False}): assert expected == host.only("127.0.1.1", ["foo.bar", "foo"])