コード例 #1
0
ファイル: test_host.py プロジェクト: whytewolf/salt
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
コード例 #2
0
ファイル: test_host.py プロジェクト: crimv42/saltstack
 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)
コード例 #3
0
ファイル: test_host.py プロジェクト: whytewolf/salt
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
コード例 #4
0
ファイル: test_host.py プロジェクト: crimv42/saltstack
    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]:
                                             [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)
コード例 #5
0
ファイル: test_host.py プロジェクト: arizvisa/saltstack-salt
 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)
コード例 #6
0
ファイル: test_host.py プロジェクト: arizvisa/saltstack-salt
    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)
コード例 #7
0
ファイル: host_test.py プロジェクト: HowardMei/saltstack
    def test_present(self):
        '''
            Test to ensures that the named host is present with the given ip
        '''
        ret = {'changes': {},
               'comment': 'Host salt (127.0.0.1) already present',
               'name': 'salt', 'result': True}

        mock = MagicMock(return_value=True)
        with patch.dict(host.__salt__, {'hosts.has_pair': mock}):
            self.assertDictEqual(host.present("salt", "127.0.0.1"), ret)
コード例 #8
0
ファイル: test_host.py プロジェクト: elisapa/salt-1
    def test_present(self):
        '''
        Test to ensures that the named host is present with the given ip
        '''
        ret = {
            'changes': {},
            'comment': 'Host salt (127.0.0.1) already present',
            'name': 'salt',
            'result': True
        }

        mock = MagicMock(return_value=True)
        with patch.dict(host.__salt__, {'hosts.has_pair': mock}):
            self.assertDictEqual(host.present("salt", "127.0.0.1"), ret)
コード例 #9
0
ファイル: test_host.py プロジェクト: arizvisa/saltstack-salt
 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)
コード例 #10
0
ファイル: test_host.py プロジェクト: dmacvicar/salt-1
    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
コード例 #11
0
ファイル: test_host.py プロジェクト: whytewolf/salt
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