def test_mount(self): """ Test if it mounts an image """ # Test case with non-existing mount folder run_mock = MagicMock(return_value="") with patch( "os.path.join", MagicMock(return_value="/tmp/guest/fedora.qcow") ), patch("os.path.isdir", MagicMock(return_value=False)), patch( "os.makedirs", MagicMock() ) as makedirs_mock, patch( "os.listdir", MagicMock(return_value=False) ), patch.dict( guestfs.__salt__, {"cmd.run": run_mock} ): self.assertTrue(guestfs.mount("/srv/images/fedora.qcow")) run_mock.assert_called_once_with( "guestmount -i -a /srv/images/fedora.qcow --rw /tmp/guest/fedora.qcow", python_shell=False, ) makedirs_mock.assert_called_once() # Test case with existing but empty mount folder run_mock.reset_mock() with patch( "os.path.join", MagicMock(return_value="/tmp/guest/fedora.qcow") ), patch("os.path.isdir", MagicMock(return_value=True)), patch( "os.makedirs", MagicMock() ) as makedirs_mock, patch( "os.listdir", MagicMock(return_value=False) ), patch.dict( guestfs.__salt__, {"cmd.run": run_mock} ): self.assertTrue(guestfs.mount("/srv/images/fedora.qcow")) run_mock.assert_called_once_with( "guestmount -i -a /srv/images/fedora.qcow --rw /tmp/guest/fedora.qcow", python_shell=False, ) makedirs_mock.assert_not_called() # Test case with existing but not empty mount folder run_mock.reset_mock() with patch( "os.path.join", MagicMock( side_effect=["/tmp/guest/fedora.qcow", "/tmp/guest/fedora.qcowabc"] ), ), patch("os.path.isdir", MagicMock(side_effect=[True, False])), patch( "os.makedirs", MagicMock() ) as makedirs_mock, patch( "os.listdir", MagicMock(side_effect=[True, False]) ), patch.dict( guestfs.__salt__, {"cmd.run": run_mock} ): self.assertTrue(guestfs.mount("/srv/images/fedora.qcow")) run_mock.assert_called_once_with( "guestmount -i -a /srv/images/fedora.qcow --rw /tmp/guest/fedora.qcowabc", python_shell=False, ) makedirs_mock.assert_called_once()
def test_configure_op_defaults(self): ''' Test configure_op_defaults method ''' mock_cmd_run = MagicMock(return_value=True) with patch.dict(crmshmod.__salt__, {'cmd.retcode': mock_cmd_run}): result = crmshmod.configure_op_defaults('item', 'value') assert result mock_cmd_run.assert_called_once_with( '{crm_command} configure op_defaults {item}="{value}"'.format( crm_command=crmshmod.CRM_COMMAND, item='item', value='value')) mock_cmd_run.reset_mock() with patch.dict(crmshmod.__salt__, {'cmd.retcode': mock_cmd_run}): result = crmshmod.configure_op_defaults('item', False) assert result mock_cmd_run.assert_called_once_with( '{crm_command} configure op_defaults {item}={value}'.format( crm_command=crmshmod.CRM_COMMAND, item='item', value='false'))
def test_clone(self): """ Test that an integer value for clone_from """ mock_query = MagicMock(return_value="") with patch("salt.cloud.clouds.proxmox._get_properties", MagicMock(return_value=[])), patch( "salt.cloud.clouds.proxmox.query", mock_query): vm_ = { "technology": "qemu", "name": "new2", "host": "myhost", "clone": True, "clone_from": 123, } # CASE 1: Numeric ID result = proxmox.create_node(vm_, ANY) mock_query.assert_called_once_with( "post", "nodes/myhost/qemu/123/clone", {"newid": ANY}, ) assert result == {} # CASE 2: host:ID notation mock_query.reset_mock() vm_["clone_from"] = "otherhost:123" result = proxmox.create_node(vm_, ANY) mock_query.assert_called_once_with( "post", "nodes/otherhost/qemu/123/clone", {"newid": ANY}, ) assert result == {}
def test_crm_init_complete(self): ''' Test _crm_init method ''' mock_cmd_run = MagicMock(return_value=True) with patch.dict(crmshmod.__salt__, {'cmd.retcode': mock_cmd_run}): result = crmshmod._crm_init('hacluster', 'dog', 'eth1', True, '192.168.1.50', True, ['dev1', 'dev2'], True, 'alice', True) assert result mock_cmd_run.assert_called_once_with( '{} cluster init -y -n {} -w {} -i {} -u -A {} ' '-s {} -s {} --no-overwrite-sshkey --qnetd-hostname {} -q'. format(crmshmod.CRM_COMMAND, 'hacluster', 'dog', 'eth1', '192.168.1.50', 'dev1', 'dev2', 'alice')) # SBD diskless mock_cmd_run.reset_mock() with patch.dict(crmshmod.__salt__, {'cmd.retcode': mock_cmd_run}): result = crmshmod._crm_init('hacluster', 'dog', 'eth1', True, '192.168.1.50', True, None, True, 'alice', True) assert result mock_cmd_run.assert_called_once_with( '{} cluster init -y -n {} -w {} -i {} -u -A {} ' '-S --no-overwrite-sshkey --qnetd-hostname {} -q'.format( crmshmod.CRM_COMMAND, 'hacluster', 'dog', 'eth1', '192.168.1.50', 'alice'))
def test_pkg_hold(): """ Tests holding packages with Zypper """ # Test openSUSE 15.3 list_locks_mock = { "bar": { "type": "package", "match_type": "glob", "case_sensitive": "on" }, "minimal_base": { "type": "pattern", "match_type": "glob", "case_sensitive": "on", }, "baz": { "type": "package", "match_type": "glob", "case_sensitive": "on" }, } cmd = MagicMock( return_value={ "pid": 1234, "retcode": 0, "stdout": "Specified lock has been successfully added.", "stderr": "", }) with patch.object(zypper, "list_locks", MagicMock(return_value=list_locks_mock)), patch.dict( zypper.__salt__, {"cmd.run_all": cmd}): ret = zypper.hold("foo") assert ret["foo"]["changes"]["old"] == "" assert ret["foo"]["changes"]["new"] == "hold" assert ret["foo"]["comment"] == "Package foo is now being held." cmd.assert_called_once_with( ["zypper", "--non-interactive", "--no-refresh", "al", "foo"], env={}, output_loglevel="trace", python_shell=False, ) cmd.reset_mock() ret = zypper.hold(pkgs=["foo", "bar"]) assert ret["foo"]["changes"]["old"] == "" assert ret["foo"]["changes"]["new"] == "hold" assert ret["foo"]["comment"] == "Package foo is now being held." assert ret["bar"]["changes"] == {} assert ret["bar"][ "comment"] == "Package bar is already set to be held." cmd.assert_called_once_with( ["zypper", "--non-interactive", "--no-refresh", "al", "foo"], env={}, output_loglevel="trace", python_shell=False, )
def test_install_with_epoch(self): ''' Tests that we properly identify a version containing an epoch as an upgrade instead of a downgrade. ''' name = 'foo' old = '8:3.8.12-6.n.el7' new = '9:3.8.12-4.n.el7' list_pkgs_mock = MagicMock( side_effect=lambda **kwargs: {name: [old] if kwargs.get('versions_as_list', False) else old}) cmd_mock = MagicMock(return_value={ 'pid': 12345, 'retcode': 0, 'stdout': '', 'stderr': '', }) salt_mock = { 'cmd.run_all': cmd_mock, 'lowpkg.version_cmp': rpm.version_cmp, 'pkg_resource.parse_targets': MagicMock(return_value=({ name: new }, 'repository')), } full_pkg_string = '-'.join((name, new[2:])) with patch.object(yumpkg, 'list_pkgs', list_pkgs_mock), \ patch('salt.utils.systemd.has_scope', MagicMock(return_value=False)), \ patch.dict(yumpkg.__salt__, salt_mock): # Test yum expected = ['yum', '-y', 'install', full_pkg_string] with patch.dict(yumpkg.__grains__, { 'os': 'CentOS', 'osrelease': 7 }): yumpkg.install('foo', version=new) call = cmd_mock.mock_calls[0][1][0] assert call == expected, call # Test dnf expected = [ 'dnf', '-y', '--best', '--allowerasing', 'install', full_pkg_string ] yumpkg.__context__.pop('yum_bin') cmd_mock.reset_mock() with patch.dict(yumpkg.__grains__, { 'os': 'Fedora', 'osrelease': 27 }): yumpkg.install('foo', version=new) call = cmd_mock.mock_calls[0][1][0] assert call == expected, call
def test_ext_pillar_with_extra_minion_data_val_dict(self): opts = { "optimization_order": [0, 1, 2], "renderer": "json", "renderer_blacklist": [], "renderer_whitelist": [], "state_top": "", "pillar_roots": { "dev": [], "base": [] }, "file_roots": { "dev": [], "base": [] }, "extension_modules": "", "pillarenv_from_saltenv": True, } mock_ext_pillar_func = MagicMock() with patch( "salt.loader.pillars", MagicMock( return_value={"fake_ext_pillar": mock_ext_pillar_func}), ): pillar = salt.pillar.Pillar(opts, {}, "mocked-minion", "dev", extra_minion_data={"fake_key": "foo"}) # ext pillar function doesn't have the extra_minion_data arg with patch( "salt.utils.args.get_function_argspec", MagicMock(return_value=MagicMock(args=[])), ): pillar._external_pillar_data("fake_pillar", {"arg": "foo"}, "fake_ext_pillar") mock_ext_pillar_func.assert_called_once_with("mocked-minion", "fake_pillar", arg="foo") # ext pillar function has the extra_minion_data arg mock_ext_pillar_func.reset_mock() with patch( "salt.utils.args.get_function_argspec", MagicMock(return_value=MagicMock(args=["extra_minion_data"])), ): pillar._external_pillar_data("fake_pillar", {"arg": "foo"}, "fake_ext_pillar") mock_ext_pillar_func.assert_called_once_with( "mocked-minion", "fake_pillar", arg="foo", extra_minion_data={"fake_key": "foo"}, )
def test_set_setting(self): names = ['Credential Validation', 'IPsec Driver', 'File System', 'SAM'] mock_set = MagicMock(return_value={'retcode': 0, 'stdout': 'Success'}) with patch.object(salt.modules.cmdmod, 'run_all', mock_set): with patch.object(win_lgpo_auditpol, '_get_valid_names', return_value=[k.lower() for k in names]): for name in names: value = random.choice(settings) win_lgpo_auditpol.set_setting(name=name, value=value) switches = win_lgpo_auditpol.settings[value] cmd = 'auditpol /set /subcategory:"{0}" {1}' \ ''.format(name, switches) mock_set.assert_called_once_with(cmd=cmd, python_shell=True) mock_set.reset_mock()
def test_set_setting(self): names = ["Credential Validation", "IPsec Driver", "File System", "SAM"] mock_set = MagicMock(return_value={"retcode": 0, "stdout": "Success"}) with patch.object(salt.modules.cmdmod, "run_all", mock_set): with patch.object( win_lgpo_auditpol, "_get_valid_names", return_value=[k.lower() for k in names], ): for name in names: value = random.choice(settings) win_lgpo_auditpol.set_setting(name=name, value=value) switches = win_lgpo_auditpol.settings[value] cmd = 'auditpol /set /subcategory:"{}" {}' "".format(name, switches) mock_set.assert_called_once_with(cmd=cmd, python_shell=True) mock_set.reset_mock()
def test_ext_pillar_with_extra_minion_data_val_dict(self): opts = { 'optimization_order': [0, 1, 2], 'renderer': 'json', 'renderer_blacklist': [], 'renderer_whitelist': [], 'state_top': '', 'pillar_roots': { 'dev': [], 'base': [] }, 'file_roots': { 'dev': [], 'base': [] }, 'extension_modules': '', 'pillarenv_from_saltenv': True } mock_ext_pillar_func = MagicMock() with patch( 'salt.loader.pillars', MagicMock( return_value={'fake_ext_pillar': mock_ext_pillar_func})): pillar = salt.pillar.Pillar(opts, {}, 'mocked-minion', 'dev', extra_minion_data={'fake_key': 'foo'}) # ext pillar function doesn't have the extra_minion_data arg with patch('salt.utils.args.get_function_argspec', MagicMock(return_value=MagicMock(args=[]))): pillar._external_pillar_data('fake_pillar', {'arg': 'foo'}, 'fake_ext_pillar') mock_ext_pillar_func.assert_called_once_with('mocked-minion', 'fake_pillar', arg='foo') # ext pillar function has the extra_minion_data arg mock_ext_pillar_func.reset_mock() with patch( 'salt.utils.args.get_function_argspec', MagicMock(return_value=MagicMock(args=['extra_minion_data']))): pillar._external_pillar_data('fake_pillar', {'arg': 'foo'}, 'fake_ext_pillar') mock_ext_pillar_func.assert_called_once_with( 'mocked-minion', 'fake_pillar', arg='foo', extra_minion_data={'fake_key': 'foo'})
def test_mount(self): ''' Test if it mounts an image ''' # Test case with non-existing mount folder run_mock = MagicMock(return_value='') with patch('os.path.join', MagicMock(return_value='/tmp/guest/fedora.qcow')), \ patch('os.path.isdir', MagicMock(return_value=False)), \ patch('os.makedirs', MagicMock()) as makedirs_mock, \ patch('os.listdir', MagicMock(return_value=False)), \ patch.dict(guestfs.__salt__, {'cmd.run': run_mock}): self.assertTrue(guestfs.mount('/srv/images/fedora.qcow')) run_mock.assert_called_once_with( 'guestmount -i -a /srv/images/fedora.qcow --rw /tmp/guest/fedora.qcow', python_shell=False) makedirs_mock.assert_called_once() # Test case with existing but empty mount folder run_mock.reset_mock() with patch('os.path.join', MagicMock(return_value='/tmp/guest/fedora.qcow')), \ patch('os.path.isdir', MagicMock(return_value=True)), \ patch('os.makedirs', MagicMock()) as makedirs_mock, \ patch('os.listdir', MagicMock(return_value=False)), \ patch.dict(guestfs.__salt__, {'cmd.run': run_mock}): self.assertTrue(guestfs.mount('/srv/images/fedora.qcow')) run_mock.assert_called_once_with( 'guestmount -i -a /srv/images/fedora.qcow --rw /tmp/guest/fedora.qcow', python_shell=False) makedirs_mock.assert_not_called() # Test case with existing but not empty mount folder run_mock.reset_mock() with patch('os.path.join', MagicMock(side_effect=['/tmp/guest/fedora.qcow', '/tmp/guest/fedora.qcowabc'])), \ patch('os.path.isdir', MagicMock(side_effect=[True, False])), \ patch('os.makedirs', MagicMock()) as makedirs_mock, \ patch('os.listdir', MagicMock(side_effect=[True, False])), \ patch.dict(guestfs.__salt__, {'cmd.run': run_mock}): self.assertTrue(guestfs.mount('/srv/images/fedora.qcow')) run_mock.assert_called_once_with( 'guestmount -i -a /srv/images/fedora.qcow --rw /tmp/guest/fedora.qcowabc', python_shell=False) makedirs_mock.assert_called_once()
def test_ha_cluster_init_complete(self, mock_corosync, mock_watchdog): ''' Test _ha_cluster_init method ''' mock_cmd_run = MagicMock(return_value=0) mock_get_hostname = MagicMock(return_value='node') mock_interface_ip = MagicMock(return_value='1.0.1.0') with patch.dict( crmshmod.__salt__, { 'cmd.retcode': mock_cmd_run, 'network.get_hostname': mock_get_hostname, 'network.interface_ip': mock_interface_ip }): result = crmshmod._ha_cluster_init('dog', 'eth1', True, '192.168.1.50', True, ['dev1', 'dev2'], 'alice', True) assert result == 0 mock_watchdog.assert_called_once_with('dog') mock_corosync.assert_called_once_with('1.0.1.0', 'node') mock_interface_ip.assert_called_once_with('eth1') mock_cmd_run.assert_called_once_with( '{} -y -i {} -A {} -s {} -s {} --qnetd-hostname {} -q'.format( crmshmod.HA_INIT_COMMAND, 'eth1', '192.168.1.50', 'dev1', 'dev2', 'alice')) # SBD diskless mock_cmd_run.reset_mock() with patch.dict( crmshmod.__salt__, { 'cmd.retcode': mock_cmd_run, 'network.get_hostname': mock_get_hostname, 'network.interface_ip': mock_interface_ip }): result = crmshmod._ha_cluster_init('dog', 'eth1', True, '192.168.1.50', True, None, 'alice', True) assert result == 0 mock_cmd_run.assert_called_once_with( '{} -y -i {} -A {} -S --qnetd-hostname {} -q'.format( crmshmod.HA_INIT_COMMAND, 'eth1', '192.168.1.50', 'alice'))
def test_userpass_mech_domain_unused(self): mock_sc = MagicMock() with patch('salt.utils.vmware.SmartConnect', mock_sc): salt.utils.vmware._get_service_instance( host='fake_host.fqdn', username='******', password='******', protocol='fake_protocol', port=1, mechanism='userpass', principal='fake principal', domain='fake_domain') mock_sc.assert_called_once_with( host='fake_host.fqdn', user='******', pwd='fake_password', protocol='fake_protocol', port=1, b64token=None, mechanism='userpass') mock_sc.reset_mock() salt.utils.vmware._get_service_instance( host='fake_host.fqdn', username='******', password='******', protocol='fake_protocol', port=1, mechanism='userpass', principal='fake principal', domain='fake_domain') mock_sc.assert_called_once_with( host='fake_host.fqdn', user='******', pwd='fake_password', protocol='fake_protocol', port=1, b64token=None, mechanism='userpass')
def test_query(self): """ Confirm that using a different root affects the HTTP query made """ body = '{"result": "success"}' server_id = "foo" expected = salt.utils.json.loads(body) http_query = MagicMock(return_value=DummyRequest(200, body=body)) utils_dunder = {"http.query": http_query} with patch.dict(scaleway.__utils__, utils_dunder): # Case 1: use default api_root profile = copy.copy(self._profile) with patch.object(scaleway, "get_configured_provider", lambda: profile): result = scaleway.query(server_id=server_id) assert result == expected, result http_query.assert_called_once_with( "https://cp-par1.scaleway.com/servers/foo/", data="{}", headers={ "X-Auth-Token": "foobarbaz", "User-Agent": "salt-cloud", "Content-Type": "application/json", }, method="GET", ) # Case 2: api_root overridden in profile http_query.reset_mock() profile = copy.copy(self._profile) profile["api_root"] = "https://my.api.root" with patch.object(scaleway, "get_configured_provider", lambda: profile): result = scaleway.query(server_id=server_id) assert result == expected, result http_query.assert_called_once_with( "https://my.api.root/servers/foo/", data="{}", headers={ "X-Auth-Token": "foobarbaz", "User-Agent": "salt-cloud", "Content-Type": "application/json", }, method="GET", ) # Case 3: use default alternative root http_query.reset_mock() profile = copy.copy(self._profile) with patch.object(scaleway, "get_configured_provider", lambda: profile): result = scaleway.query(server_id=server_id, root="alt_root") assert result == expected, result http_query.assert_called_once_with( "https://api-marketplace.scaleway.com/servers/foo/", data="{}", headers={ "X-Auth-Token": "foobarbaz", "User-Agent": "salt-cloud", "Content-Type": "application/json", }, method="GET", ) # Case 4: use alternative root specified in profile http_query.reset_mock() profile = copy.copy(self._profile) profile["alt_root"] = "https://my.alt.api.root" with patch.object(scaleway, "get_configured_provider", lambda: profile): result = scaleway.query(server_id=server_id, root="alt_root") assert result == expected, result http_query.assert_called_once_with( "https://my.alt.api.root/servers/foo/", data="{}", headers={ "X-Auth-Token": "foobarbaz", "User-Agent": "salt-cloud", "Content-Type": "application/json", }, method="GET", )
def test_held_unheld(package_manager): """ Test pkg.held and pkg.unheld with Zypper, YUM/DNF and APT """ if package_manager == "Zypper": list_holds_func = "pkg.list_locks" list_holds_mock = MagicMock( return_value={ "bar": { "type": "package", "match_type": "glob", "case_sensitive": "on", }, "minimal_base": { "type": "pattern", "match_type": "glob", "case_sensitive": "on", }, "baz": { "type": "package", "match_type": "glob", "case_sensitive": "on", }, }) elif package_manager == "YUM/DNF": list_holds_func = "pkg.list_holds" list_holds_mock = MagicMock(return_value=[ "bar-0:1.2.3-1.1.*", "baz-0:2.3.4-2.1.*", ]) elif package_manager == "APT": list_holds_func = "pkg.get_selections" list_holds_mock = MagicMock(return_value={"hold": [ "bar", "baz", ]}) def pkg_hold(name, pkgs=None, *_args, **__kwargs): if name and pkgs is None: pkgs = [name] ret = {} for pkg in pkgs: ret.update({ pkg: { "name": pkg, "changes": { "new": "hold", "old": "" }, "result": True, "comment": "Package {} is now being held.".format(pkg), } }) return ret def pkg_unhold(name, pkgs=None, *_args, **__kwargs): if name and pkgs is None: pkgs = [name] ret = {} for pkg in pkgs: ret.update({ pkg: { "name": pkg, "changes": { "new": "", "old": "hold" }, "result": True, "comment": "Package {} is no longer held.".format(pkg), } }) return ret hold_mock = MagicMock(side_effect=pkg_hold) unhold_mock = MagicMock(side_effect=pkg_unhold) # Testing with Zypper with patch.dict( pkg.__salt__, { list_holds_func: list_holds_mock, "pkg.hold": hold_mock, "pkg.unhold": unhold_mock, }, ): # Holding one of two packages ret = pkg.held("held-test", pkgs=["foo", "bar"]) assert "foo" in ret["changes"] assert len(ret["changes"]) == 1 hold_mock.assert_called_once_with(name="held-test", pkgs=["foo"]) unhold_mock.assert_not_called() hold_mock.reset_mock() unhold_mock.reset_mock() # Holding one of two packages and replacing all the rest held packages ret = pkg.held("held-test", pkgs=["foo", "bar"], replace=True) assert "foo" in ret["changes"] assert "baz" in ret["changes"] assert len(ret["changes"]) == 2 hold_mock.assert_called_once_with(name="held-test", pkgs=["foo"]) unhold_mock.assert_called_once_with(name="held-test", pkgs=["baz"]) hold_mock.reset_mock() unhold_mock.reset_mock() # Remove all holds ret = pkg.held("held-test", pkgs=[], replace=True) assert "bar" in ret["changes"] assert "baz" in ret["changes"] assert len(ret["changes"]) == 2 hold_mock.assert_not_called() unhold_mock.assert_any_call(name="held-test", pkgs=["baz"]) unhold_mock.assert_any_call(name="held-test", pkgs=["bar"]) hold_mock.reset_mock() unhold_mock.reset_mock() # Unolding one of two packages ret = pkg.unheld("held-test", pkgs=["foo", "bar"]) assert "bar" in ret["changes"] assert len(ret["changes"]) == 1 unhold_mock.assert_called_once_with(name="held-test", pkgs=["bar"]) hold_mock.assert_not_called() hold_mock.reset_mock() unhold_mock.reset_mock() # Remove all holds ret = pkg.unheld("held-test", all=True) assert "bar" in ret["changes"] assert "baz" in ret["changes"] assert len(ret["changes"]) == 2 hold_mock.assert_not_called() unhold_mock.assert_any_call(name="held-test", pkgs=["baz"]) unhold_mock.assert_any_call(name="held-test", pkgs=["bar"])
class HostTestCase(TestCase, LoaderModuleMockMixin): """ Validate the host state """ 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] }, } def setUp(self): self.add_host_mock = MagicMock(return_value=True) self.rm_host_mock = MagicMock(return_value=True) self.set_comment_mock = MagicMock(return_value=True) self.list_hosts_mock = MagicMock(return_value=self.default_hosts) def setup_loader_modules(self): return { host: { "__opts__": { "test": False } }, } def test_present(self): """ 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) set_comment = 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"] == "Added host {0} ({1})".format( 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 "Added host {0} ({1})".format(hostname, ip_list[0]) in ret["comment"] assert "Added host {0} ({1})".format(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 "Added host {0} ({1})".format(hostname, ip_str) in ret["comment"] assert ("Host {0} present for IP address {1}".format( hostname, 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 "Added host {0} ({1})".format(hostname, ip_str) in ret["comment"] assert ("Removed host {0} ({1})".format(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 "Added host {0} ({1})".format(hostname, ip_list[0]) in ret["comment"] assert "Added host {0} ({1})".format(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 "Added host {0} ({1})".format(hostname, ip_list[0]) in ret["comment"] assert "Added host {0} ({1})".format(hostname, ip_list[1]) in ret["comment"] assert "Removed host {0} ({1})".format(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 "Added host {0} ({1})".format(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 "Added host {0} ({1})".format(hostname, ip_list[1]) in ret["comment"] assert "Removed host {0} ({1})".format(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 (ret["comment"] == "Host {0} ({1}) already present".format( hostname, ip_str) 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 ("Host {0} ({1}) already present".format( hostname, ip_list[0]) in ret["comment"]) assert ("Host {0} ({1}) already present".format( hostname, ip_list[1]) 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"] }}) self.add_host_mock.reset_mock() self.rm_host_mock.reset_mock() self.set_comment_mock.reset_mock() with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": self.add_host_mock, "hosts.rm_host": self.rm_host_mock, "hosts.set_comment": self.set_comment_mock, }, ): ret = host.present(self.hostname, self.ip_list, comment="A comment") assert ret["result"] is True assert ("Added host {0} ({1})".format(self.hostname, self.ip_list[0]) in ret["comment"]) assert ("Added host {0} ({1})".format(self.hostname, self.ip_list[1]) in ret["comment"]) assert ("Set comment for host {0} (A comment)".format( self.ip_list[0]) in ret["comment"]) assert ("Set comment for host {0} (A comment)".format( self.ip_list[1]) in ret["comment"]) assert ret["changes"] == { "added": { self.ip_list[0]: [self.hostname], self.ip_list[1]: [self.hostname], }, "comment_added": { self.ip_list[0]: ["A comment"], self.ip_list[1]: ["A comment"], }, }, ret["changes"] expected = sorted([call(x, self.hostname) for x in self.ip_list]) assert (sorted(self.add_host_mock.mock_calls) == expected ), self.add_host_mock.mock_calls expected = sorted([call(x, "A comment") for x in self.ip_list]) assert (sorted(self.set_comment_mock.mock_calls) == expected ), self.set_comment_mock.mock_calls assert self.rm_host_mock.mock_calls == [], self.rm_host_mock.mock_calls def test_host_present_should_return_True_if_test_and_no_changes(self): expected = { "comment": "Host {} ({}) already present".format( self.hostname, self.ip_list[0], ), "changes": {}, "name": self.hostname, "result": True, } list_hosts = MagicMock( return_value={self.ip_list[0]: { "aliases": [self.hostname] }}, ) with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": self.add_host_mock, "hosts.rm_host": self.rm_host_mock, }, ): with patch.dict(host.__opts__, {"test": True}): ret = host.present(self.hostname, self.ip_list[:1]) self.assertDictEqual(ret, expected) def test_host_present_should_return_None_if_test_and_adding(self): expected = { "comment": "\n".join([ "Host {} ({}) already present", "Host {} ({}) would be added" ]).format( self.hostname, self.ip_list[0], self.hostname, self.ip_list[1], ), "changes": { "added": { self.ip_list[1]: [self.hostname] } }, "name": self.hostname, "result": None, } list_hosts = MagicMock( return_value={self.ip_list[0]: { "aliases": [self.hostname] }}, ) with patch.dict( host.__salt__, { "hosts.list_hosts": list_hosts, "hosts.add_host": self.add_host_mock, "hosts.rm_host": self.rm_host_mock, }, ): with patch.dict(host.__opts__, {"test": True}): ret = host.present(self.hostname, self.ip_list) self.assertDictEqual(ret, expected) def test_host_present_should_return_None_if_test_and_removing(self): expected = { "comment": "\n".join([ "Host {} ({}) already present", "Host {} ({}) would be removed" ]).format( self.hostname, self.ip_list[0], self.hostname, self.ip_list[1], ), "changes": { "removed": { self.ip_list[1]: [self.hostname] } }, "name": self.hostname, "result": None, } with patch.dict( host.__salt__, { "hosts.list_hosts": self.list_hosts_mock, "hosts.add_host": self.add_host_mock, "hosts.rm_host": self.rm_host_mock, }, ): with patch.dict(host.__opts__, {"test": True}): ret = host.present(self.hostname, self.ip_list[:1], clean=True) self.assertDictEqual(ret, expected) def test_absent(self): """ 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}): self.assertDictEqual(host.absent("salt", "127.0.0.1"), ret) def test_only_already(self): """ 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}): self.assertDictEqual(expected, host.only("127.0.1.1", "foo.bar")) def test_only_dryrun(self): """ 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}): self.assertDictEqual( expected, host.only("127.0.1.1", ["foo.bar", "foo"])) def test_only_fail(self): """ 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}): self.assertDictEqual( expected, host.only("127.0.1.1", ["foo.bar", "foo"])) def test_only_success(self): """ 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}): self.assertDictEqual( expected, host.only("127.0.1.1", ["foo.bar", "foo"]))
def test_enable(self): """ Test for Enable the named service to start at boot """ rc_update_mock = MagicMock(return_value=0) with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue(gentoo_service.enable("name")) rc_update_mock.assert_called_once_with("rc-update add name", ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # move service from 'l1' to 'l2' runlevel service_name = "name" runlevels = ["l1"] level_list_mock = MagicMock( return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue(gentoo_service.enable("name", runlevels="l2")) rc_update_mock.assert_has_calls([ call("rc-update delete name l1", ignore_retcode=False, python_shell=False), call("rc-update add name l2", ignore_retcode=False, python_shell=False), ]) rc_update_mock.reset_mock() # requested levels are the same as the current ones with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue(gentoo_service.enable("name", runlevels="l1")) self.assertTrue(rc_update_mock.call_count == 0) rc_update_mock.reset_mock() # same as above with the list instead of the string with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue(gentoo_service.enable("name", runlevels=["l1"])) self.assertTrue(rc_update_mock.call_count == 0) rc_update_mock.reset_mock() # add service to 'l2' runlevel with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue( gentoo_service.enable("name", runlevels=["l2", "l1"])) rc_update_mock.assert_called_once_with("rc-update add name l2", ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # remove service from 'l1' runlevel runlevels = ["l1", "l2"] level_list_mock = MagicMock( return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue(gentoo_service.enable("name", runlevels=["l2"])) rc_update_mock.assert_called_once_with("rc-update delete name l1", ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # move service from 'l2' add to 'l3', leaving at l1 with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue( gentoo_service.enable("name", runlevels=["l1", "l3"])) rc_update_mock.assert_has_calls([ call("rc-update delete name l2", ignore_retcode=False, python_shell=False), call("rc-update add name l3", ignore_retcode=False, python_shell=False), ]) rc_update_mock.reset_mock() # remove from l1, l3, and add to l2, l4, and leave at l5 runlevels = ["l1", "l3", "l5"] level_list_mock = MagicMock( return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue( gentoo_service.enable("name", runlevels=["l2", "l4", "l5"])) rc_update_mock.assert_has_calls([ call( "rc-update delete name l1 l3", ignore_retcode=False, python_shell=False, ), call("rc-update add name l2 l4", ignore_retcode=False, python_shell=False), ]) rc_update_mock.reset_mock() # rc-update failed rc_update_mock = MagicMock(return_value=1) with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertFalse(gentoo_service.enable("name")) rc_update_mock.assert_called_once_with("rc-update add name", ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # move service delete failed runlevels = ["l1"] level_list_mock = MagicMock( return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertFalse(gentoo_service.enable("name", runlevels="l2")) rc_update_mock.assert_called_once_with("rc-update delete name l1", ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # move service delete succeeds. add fails rc_update_mock = MagicMock() rc_update_mock.side_effect = [0, 1] with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertFalse(gentoo_service.enable("name", runlevels="l2")) rc_update_mock.assert_has_calls([ call("rc-update delete name l1", ignore_retcode=False, python_shell=False), call("rc-update add name l2", ignore_retcode=False, python_shell=False), ]) rc_update_mock.reset_mock()
def run_checks(isdir=mock_t, strptime_format=None, test=False): expected_ret = { "name": fake_name, "changes": {"retained": [], "deleted": [], "ignored": []}, "result": True, "comment": "Name provided to file.retention must be a directory", } if strptime_format: fake_file_list = sorted(fake_matching_file_list + fake_no_match_file_list) else: fake_file_list = sorted(fake_matching_file_list) mock_readdir = MagicMock(return_value=fake_file_list) with patch.dict(filestate.__opts__, {"test": test}): with patch.object(os.path, "isdir", isdir): mock_readdir.reset_mock() with patch.dict(filestate.__salt__, {"file.readdir": mock_readdir}): with patch.dict(filestate.__salt__, {"file.lstat": mock_lstat}): mock_remove.reset_mock() with patch.dict( filestate.__salt__, {"file.remove": mock_remove} ): if strptime_format: actual_ret = filestate.retention_schedule( fake_name, fake_retain, strptime_format=fake_strptime_format, ) else: actual_ret = filestate.retention_schedule( fake_name, fake_retain ) if not isdir(): mock_readdir.assert_has_calls([]) expected_ret["result"] = False else: mock_readdir.assert_called_once_with(fake_name) ignored_files = fake_no_match_file_list if strptime_format else [] retained_files = set( generate_fake_files(maxfiles=fake_retain["most_recent"]) ) junk_list = [ ("first_of_hour", relativedelta(hours=1)), ("first_of_day", relativedelta(days=1)), ("first_of_week", relativedelta(weeks=1)), ("first_of_month", relativedelta(months=1)), ("first_of_year", relativedelta(years=1)), ] for retainable, retain_interval in junk_list: new_retains = set( generate_fake_files( maxfiles=fake_retain[retainable], every=retain_interval ) ) # if we generate less than the number of files expected, # then the oldest file will also be retained # (correctly, since its the first in it's category) if ( fake_retain[retainable] == "all" or len(new_retains) < fake_retain[retainable] ): new_retains.add(fake_file_list[0]) retained_files |= new_retains deleted_files = sorted( list(set(fake_file_list) - retained_files - set(ignored_files)), reverse=True, ) retained_files = sorted(list(retained_files), reverse=True) expected_ret["changes"] = { "retained": retained_files, "deleted": deleted_files, "ignored": ignored_files, } if test: expected_ret["result"] = None expected_ret[ "comment" ] = "{} backups would have been removed from {}.\n" "".format( len(deleted_files), fake_name ) else: expected_ret[ "comment" ] = "{} backups were removed from {}.\n" "".format( len(deleted_files), fake_name ) mock_remove.assert_has_calls( [call(os.path.join(fake_name, x)) for x in deleted_files], any_order=True, ) assert actual_ret == expected_ret
def test_disable(self): """ Test for Disable the named service to start at boot """ rc_update_mock = MagicMock(return_value=0) with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue(gentoo_service.disable("name")) rc_update_mock.assert_called_once_with("rc-update delete name", ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # disable service service_name = "name" runlevels = ["l1"] level_list_mock = MagicMock( return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue(gentoo_service.disable("name", runlevels="l1")) rc_update_mock.assert_called_once_with("rc-update delete name l1", ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # same as above with list runlevels = ["l1"] level_list_mock = MagicMock( return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue( gentoo_service.disable("name", runlevels=["l1"])) rc_update_mock.assert_called_once_with("rc-update delete name l1", ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # remove from 'l1', and leave at 'l2' runlevels = ["l1", "l2"] level_list_mock = MagicMock( return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue( gentoo_service.disable("name", runlevels=["l1"])) rc_update_mock.assert_called_once_with("rc-update delete name l1", ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # remove from non-enabled level runlevels = ["l2"] level_list_mock = MagicMock( return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue( gentoo_service.disable("name", runlevels=["l1"])) self.assertTrue(rc_update_mock.call_count == 0) rc_update_mock.reset_mock() # remove from 'l1' and 'l3', leave at 'l2' runlevels = ["l1", "l2", "l3"] level_list_mock = MagicMock( return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertTrue( gentoo_service.disable("name", runlevels=["l1", "l3"])) rc_update_mock.assert_called_once_with("rc-update delete name l1 l3", ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # rc-update failed rc_update_mock = MagicMock(return_value=1) with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertFalse(gentoo_service.disable("name")) rc_update_mock.assert_called_once_with("rc-update delete name", ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # move service delete failed runlevels = ["l1"] level_list_mock = MagicMock( return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertFalse(gentoo_service.disable("name", runlevels="l1")) rc_update_mock.assert_called_once_with("rc-update delete name l1", ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # move service delete succeeds. add fails runlevels = ["l1", "l2", "l3"] level_list_mock = MagicMock( return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {"cmd.run": level_list_mock}): with patch.dict(gentoo_service.__salt__, {"cmd.retcode": rc_update_mock}): self.assertFalse( gentoo_service.disable("name", runlevels=["l1", "l3"])) rc_update_mock.assert_called_once_with("rc-update delete name l1 l3", ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock()
def test_present(self): ''' 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': ['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'] == 'Added host {0} ({1})'.format(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': ['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 'Added host {0} ({1})'.format(hostname, ip_list[0]) in ret['comment'] assert 'Added host {0} ({1})'.format(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': ['localhost'], ip_list[0]: [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 'Added host {0} ({1})'.format(hostname, ip_str) in ret['comment'] assert 'Host {0} present for IP address {1}'.format(hostname, 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 'Added host {0} ({1})'.format(hostname, ip_str) in ret['comment'] assert 'Removed host {0} ({1})'.format(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': ['localhost'], cur_ip: [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 'Added host {0} ({1})'.format(hostname, ip_list[0]) in ret['comment'] assert 'Added host {0} ({1})'.format(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 'Added host {0} ({1})'.format(hostname, ip_list[0]) in ret['comment'] assert 'Added host {0} ({1})'.format(hostname, ip_list[1]) in ret['comment'] assert 'Removed host {0} ({1})'.format(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': ['localhost'], cur_ip: [hostname], ip_list[0]: [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 'Added host {0} ({1})'.format(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 'Added host {0} ({1})'.format(hostname, ip_list[1]) in ret['comment'] assert 'Removed host {0} ({1})'.format(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: [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 ret['comment'] == 'Host {0} ({1}) already present'.format(hostname, ip_str) 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]: [hostname], ip_list[1]: [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 'Host {0} ({1}) already present'.format(hostname, ip_list[0]) in ret['comment'] assert 'Host {0} ({1}) already present'.format(hostname, ip_list[1]) 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
def test__tidied(): name = os.sep + "test" if salt.utils.platform.is_windows(): name = "c:" + name walker = [ (os.path.join("test", "test1"), [], ["file1"]), (os.path.join("test", "test2", "test3"), [], []), (os.path.join("test", "test2"), ["test3"], ["file2"]), ("test", ["test1", "test2"], ["file3"]), ] today_delta = datetime.today() - datetime.utcfromtimestamp(0) remove = MagicMock(name="file.remove") with patch("os.walk", return_value=walker), patch( "os.path.islink", return_value=False), patch( "os.path.getatime", return_value=today_delta.total_seconds()), patch( "os.path.getsize", return_value=10), patch.dict( filestate.__opts__, {"test": False}), patch.dict( filestate.__salt__, {"file.remove": remove}), patch("os.path.isdir", return_value=True): ret = filestate.tidied(name=name) exp = { "name": name, "changes": { "removed": [ os.path.join("test", "test1", "file1"), os.path.join("test", "test2", "file2"), os.path.join("test", "file3"), ] }, "result": True, "comment": "Removed 3 files or directories from directory {}".format(name), } assert exp == ret assert remove.call_count == 3 remove.reset_mock() with patch("os.walk", return_value=walker), patch( "os.path.islink", return_value=False), patch( "os.path.getatime", return_value=today_delta.total_seconds()), patch( "os.path.getsize", return_value=10), patch.dict( filestate.__opts__, {"test": False}), patch.dict( filestate.__salt__, {"file.remove": remove}), patch("os.path.isdir", return_value=True): ret = filestate.tidied(name=name, rmdirs=True) exp = { "name": name, "changes": { "removed": [ os.path.join("test", "test1", "file1"), os.path.join("test", "test2", "file2"), os.path.join("test", "test2", "test3"), os.path.join("test", "file3"), os.path.join("test", "test1"), os.path.join("test", "test2"), ] }, "result": True, "comment": "Removed 6 files or directories from directory {}".format(name), } assert exp == ret assert remove.call_count == 6
def test_enable(self): ''' Test for Enable the named service to start at boot ''' rc_update_mock = MagicMock(return_value=0) with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.enable('name')) rc_update_mock.assert_called_once_with('rc-update add name', ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # move service from 'l1' to 'l2' runlevel service_name = 'name' runlevels = ['l1'] level_list_mock = MagicMock(return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.enable('name', runlevels='l2')) rc_update_mock.assert_has_calls([call('rc-update delete name l1', ignore_retcode=False, python_shell=False), call('rc-update add name l2', ignore_retcode=False, python_shell=False)]) rc_update_mock.reset_mock() # requested levels are the same as the current ones with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.enable('name', runlevels='l1')) self.assertTrue(rc_update_mock.call_count == 0) rc_update_mock.reset_mock() # same as above with the list instead of the string with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.enable('name', runlevels=['l1'])) self.assertTrue(rc_update_mock.call_count == 0) rc_update_mock.reset_mock() # add service to 'l2' runlevel with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.enable('name', runlevels=['l2', 'l1'])) rc_update_mock.assert_called_once_with('rc-update add name l2', ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # remove service from 'l1' runlevel runlevels = ['l1', 'l2'] level_list_mock = MagicMock(return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.enable('name', runlevels=['l2'])) rc_update_mock.assert_called_once_with('rc-update delete name l1', ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # move service from 'l2' add to 'l3', leaving at l1 with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.enable('name', runlevels=['l1', 'l3'])) rc_update_mock.assert_has_calls([call('rc-update delete name l2', ignore_retcode=False, python_shell=False), call('rc-update add name l3', ignore_retcode=False, python_shell=False)]) rc_update_mock.reset_mock() # remove from l1, l3, and add to l2, l4, and leave at l5 runlevels = ['l1', 'l3', 'l5'] level_list_mock = MagicMock(return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.enable('name', runlevels=['l2', 'l4', 'l5'])) rc_update_mock.assert_has_calls([call('rc-update delete name l1 l3', ignore_retcode=False, python_shell=False), call('rc-update add name l2 l4', ignore_retcode=False, python_shell=False)]) rc_update_mock.reset_mock() # rc-update failed rc_update_mock = MagicMock(return_value=1) with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertFalse(gentoo_service.enable('name')) rc_update_mock.assert_called_once_with('rc-update add name', ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # move service delete failed runlevels = ['l1'] level_list_mock = MagicMock(return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertFalse(gentoo_service.enable('name', runlevels='l2')) rc_update_mock.assert_called_once_with('rc-update delete name l1', ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # move service delete succeeds. add fails rc_update_mock = MagicMock() rc_update_mock.side_effect = [0, 1] with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertFalse(gentoo_service.enable('name', runlevels='l2')) rc_update_mock.assert_has_calls([call('rc-update delete name l1', ignore_retcode=False, python_shell=False), call('rc-update add name l2', ignore_retcode=False, python_shell=False)]) rc_update_mock.reset_mock()
def test_disable(self): ''' Test for Disable the named service to start at boot ''' rc_update_mock = MagicMock(return_value=0) with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.disable('name')) rc_update_mock.assert_called_once_with('rc-update delete name', ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # disable service service_name = 'name' runlevels = ['l1'] level_list_mock = MagicMock(return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.disable('name', runlevels='l1')) rc_update_mock.assert_called_once_with('rc-update delete name l1', ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # same as above with list runlevels = ['l1'] level_list_mock = MagicMock(return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.disable('name', runlevels=['l1'])) rc_update_mock.assert_called_once_with('rc-update delete name l1', ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # remove from 'l1', and leave at 'l2' runlevels = ['l1', 'l2'] level_list_mock = MagicMock(return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.disable('name', runlevels=['l1'])) rc_update_mock.assert_called_once_with('rc-update delete name l1', ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # remove from non-enabled level runlevels = ['l2'] level_list_mock = MagicMock(return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.disable('name', runlevels=['l1'])) self.assertTrue(rc_update_mock.call_count == 0) rc_update_mock.reset_mock() # remove from 'l1' and 'l3', leave at 'l2' runlevels = ['l1', 'l2', 'l3'] level_list_mock = MagicMock(return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertTrue(gentoo_service.disable('name', runlevels=['l1', 'l3'])) rc_update_mock.assert_called_once_with('rc-update delete name l1 l3', ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # rc-update failed rc_update_mock = MagicMock(return_value=1) with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertFalse(gentoo_service.disable('name')) rc_update_mock.assert_called_once_with('rc-update delete name', ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # move service delete failed runlevels = ['l1'] level_list_mock = MagicMock(return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertFalse(gentoo_service.disable('name', runlevels='l1')) rc_update_mock.assert_called_once_with('rc-update delete name l1', ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock() # move service delete succeeds. add fails runlevels = ['l1', 'l2', 'l3'] level_list_mock = MagicMock(return_value=self.__services({service_name: runlevels})) with patch.dict(gentoo_service.__salt__, {'cmd.run': level_list_mock}): with patch.dict(gentoo_service.__salt__, {'cmd.retcode': rc_update_mock}): self.assertFalse(gentoo_service.disable('name', runlevels=['l1', 'l3'])) rc_update_mock.assert_called_once_with('rc-update delete name l1 l3', ignore_retcode=False, python_shell=False) rc_update_mock.reset_mock()
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"] == "Added host {} ({})".format( 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 "Added host {} ({})".format(hostname, ip_list[0]) in ret["comment"] assert "Added host {} ({})".format(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 "Added host {} ({})".format(hostname, ip_str) in ret["comment"] assert ("Host {} present for IP address {}".format( hostname, 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 "Added host {} ({})".format(hostname, ip_str) in ret["comment"] assert "Removed host {} ({})".format(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 "Added host {} ({})".format(hostname, ip_list[0]) in ret["comment"] assert "Added host {} ({})".format(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 "Added host {} ({})".format(hostname, ip_list[0]) in ret["comment"] assert "Added host {} ({})".format(hostname, ip_list[1]) in ret["comment"] assert "Removed host {} ({})".format(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 "Added host {} ({})".format(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 "Added host {} ({})".format(hostname, ip_list[1]) in ret["comment"] assert "Removed host {} ({})".format(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 (ret["comment"] == "Host {} ({}) already present".format( hostname, ip_str) 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 ("Host {} ({}) already present".format(hostname, ip_list[0]) in ret["comment"]) assert ("Host {} ({}) already present".format(hostname, ip_list[1]) 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 "Added host {} ({})".format(hostname, ip_list[0]) in ret["comment"] assert "Added host {} ({})".format(hostname, ip_list[1]) in ret["comment"] assert ("Set comment for host {} (A comment)".format(ip_list[0]) in ret["comment"]) assert ("Set comment for host {} (A comment)".format(ip_list[1]) 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