def test_inventory_file_collision(mocker):
    inventory_filename = "test.hetzner_dns.yaml"
    C.INVENTORY_ENABLED = ['community.dns.hetzner_dns_records']
    inventory_file = {inventory_filename: textwrap.dedent("""\
    ---
    plugin: community.dns.hetzner_dns_records
    hetzner_token: '{{ "foo" }}'
    zone_name: '{{ "example." ~ "com" }}'
    filters:
      type:
        - A
        - AAAA
    """)}

    open_url = OpenUrlProxy([
        OpenUrlCall('GET', 200)
        .expect_header('accept', 'application/json')
        .expect_header('auth-api-token', 'foo')
        .expect_url('https://dns.hetzner.com/api/v1/zones', without_query=True)
        .expect_query_values('name', 'example.com')
        .return_header('Content-Type', 'application/json')
        .result_json(HETZNER_JSON_ZONE_LIST_RESULT),
        OpenUrlCall('GET', 200)
        .expect_header('accept', 'application/json')
        .expect_header('auth-api-token', 'foo')
        .expect_url('https://dns.hetzner.com/api/v1/records', without_query=True)
        .expect_query_values('zone_id', '42')
        .expect_query_values('page', '1')
        .expect_query_values('per_page', '100')
        .return_header('Content-Type', 'application/json')
        .result_json(HETZNER_JSON_ZONE_RECORDS_GET_RESULT),
    ])
    mocker.patch('ansible_collections.community.dns.plugins.module_utils.http.open_url', open_url)
    mocker.patch('ansible.inventory.manager.unfrackpath', mock_unfrackpath_noop)
    mocker.patch('os.path.exists', exists_mock(inventory_filename))
    mocker.patch('os.access', access_mock(inventory_filename))
    im = InventoryManager(loader=DictDataLoader(inventory_file), sources=inventory_filename)

    open_url.assert_is_done()

    assert im._inventory.hosts
    assert 'example.com' in im._inventory.hosts
    assert '*.example.com' in im._inventory.hosts
    assert 'foo.example.com' in im._inventory.hosts
    assert 'bar.example.com' not in im._inventory.hosts
    assert im._inventory.get_host('example.com') in im._inventory.groups['ungrouped'].hosts
    assert im._inventory.get_host('*.example.com') in im._inventory.groups['ungrouped'].hosts
    assert im._inventory.get_host('foo.example.com') in im._inventory.groups['ungrouped'].hosts
    assert im._inventory.get_host('example.com').get_vars()['ansible_host'] == '2001:1:2::3'
    assert im._inventory.get_host('*.example.com').get_vars()['ansible_host'] == '1.2.3.5'
    assert im._inventory.get_host('foo.example.com').get_vars()['ansible_host'] == '2001:1:2::4'
    assert len(im._inventory.groups['ungrouped'].hosts) == 3
    assert len(im._inventory.groups['all'].hosts) == 0
    def test_get_single(self):
        open_url = OpenUrlProxy([
            OpenUrlCall('POST', 200).expect_content_predicate(
                validate_wsdl_call([
                    expect_authentication('foo', 'bar'),
                    expect_value([
                        lxmletree.QName('https://ns1.hosttech.eu/public/api',
                                        'getZone').text, 'sZoneName'
                    ], 'example.com', ('http://www.w3.org/2001/XMLSchema',
                                       'string')),
                ])).result_str(DEFAULT_ZONE_RESULT),
        ])
        with patch(
                'ansible_collections.felixfontein.hosttech_dns.plugins.module_utils.wsdl.open_url',
                open_url):
            with pytest.raises(AnsibleExitJson) as e:
                set_module_args({
                    'hosttech_username': '******',
                    'hosttech_password': '******',
                    'zone': 'example.com',
                    'record': 'example.com',
                    'type': 'A',
                    '_ansible_remote_tmp': '/tmp/tmp',
                    '_ansible_keep_remote_files': True,
                })
                hosttech_dns_record_info.main()

        print(e.value.args[0])
        assert e.value.args[0]['changed'] is False
        assert 'set' in e.value.args[0]
        assert e.value.args[0]['set']['record'] == 'example.com'
        assert e.value.args[0]['set']['ttl'] == 3600
        assert e.value.args[0]['set']['type'] == 'A'
        assert e.value.args[0]['set']['value'] == ['1.2.3.4']
        assert 'sets' not in e.value.args[0]
Пример #3
0
def test_inventory_file_error(mocker):
    inventory_filename = "test.hosttech_dns.yaml"
    C.INVENTORY_ENABLED = ['community.dns.hosttech_dns_records']
    inventory_file = {inventory_filename: textwrap.dedent("""\
    ---
    plugin: community.dns.hosttech_dns_records
    hosttech_token: foo
    zone_id: 42
    """)}

    open_url = OpenUrlProxy([
        OpenUrlCall('GET', 500)
        .expect_header('accept', 'application/json')
        .expect_header('authorization', 'Bearer foo')
        .expect_url('https://api.ns1.hosttech.eu/api/user/v1/zones/42')
        .result_json({}),
    ])
    mocker.patch('ansible_collections.community.dns.plugins.module_utils.http.open_url', open_url)
    mocker.patch('ansible.inventory.manager.unfrackpath', mock_unfrackpath_noop)
    mocker.patch('os.path.exists', exists_mock(inventory_filename))
    mocker.patch('os.access', access_mock(inventory_filename))
    im = InventoryManager(loader=DictDataLoader(inventory_file), sources=inventory_filename)

    open_url.assert_is_done()

    assert not im._inventory.hosts
    assert len(im._inventory.groups['ungrouped'].hosts) == 0
    assert len(im._inventory.groups['all'].hosts) == 0
Пример #4
0
def test_inventory_file_simple(mocker):
    open_url = OpenUrlProxy([
        OpenUrlCall('GET', 200).result_json([
            {
                'server': {
                    'server_ip': '1.2.3.4',
                    'dc': 'foo',
                },
            },
            {
                'server': {
                    'server_ip': '1.2.3.5',
                    'server_name': 'test-server',
                    'dc': 'foo',
                },
            },
            {
                'server': {
                    'server_ip': '1.2.3.6',
                    'server_name': 'test-server-2',
                    'dc': 'bar',
                },
            },
        ]).expect_url('{0}/server'.format(BASE_URL)),
    ])
    mocker.patch(
        'ansible_collections.community.hrobot.plugins.module_utils.robot.open_url',
        open_url)
    mocker.patch('ansible.inventory.manager.unfrackpath',
                 mock_unfrackpath_noop)
    mocker.patch('os.path.exists', lambda x: True)
    mocker.patch('os.access', lambda x, y: True)

    inventory_filename = "test.robot.yaml"
    C.INVENTORY_ENABLED = ['community.hrobot.robot']
    inventory_file = {
        inventory_filename:
        textwrap.dedent("""\
    ---
    plugin: community.hrobot.robot
    hetzner_user: test
    hetzner_password: hunter2
    filters:
      dc: foo
    """)
    }
    im = InventoryManager(loader=DictDataLoader(inventory_file),
                          sources=inventory_filename)
    open_url.assert_is_done()

    assert im._inventory.hosts
    assert '1.2.3.4' in im._inventory.hosts
    assert 'test-server' in im._inventory.hosts
    assert 'test-server-2' not in im._inventory.hosts
    assert im._inventory.get_host(
        '1.2.3.4') in im._inventory.groups['ungrouped'].hosts
    assert im._inventory.get_host(
        'test-server') in im._inventory.groups['ungrouped'].hosts
    assert len(im._inventory.groups['ungrouped'].hosts) == 2
    assert len(im._inventory.groups['all'].hosts) == 0
def test_inventory_file_unauthorized(mocker):
    inventory_filename = "test.hetzner_dns.yaml"
    C.INVENTORY_ENABLED = ['community.dns.hetzner_dns_records']
    inventory_file = {inventory_filename: textwrap.dedent("""\
    ---
    plugin: community.dns.hetzner_dns_records
    hetzner_token: foo
    zone_id: '23'
    """)}

    open_url = OpenUrlProxy([
        OpenUrlCall('GET', 403)
        .expect_header('accept', 'application/json')
        .expect_header('auth-api-token', 'foo')
        .expect_url('https://dns.hetzner.com/api/v1/zones/23')
        .result_json(dict(message="")),
    ])
    mocker.patch('ansible_collections.community.dns.plugins.module_utils.http.open_url', open_url)
    mocker.patch('ansible.inventory.manager.unfrackpath', mock_unfrackpath_noop)
    mocker.patch('os.path.exists', exists_mock(inventory_filename))
    mocker.patch('os.access', access_mock(inventory_filename))
    im = InventoryManager(loader=DictDataLoader(inventory_file), sources=inventory_filename)

    open_url.assert_is_done()

    # TODO: make sure that the correct error was reported

    assert not im._inventory.hosts
    assert len(im._inventory.groups['ungrouped'].hosts) == 0
    assert len(im._inventory.groups['all'].hosts) == 0
Пример #6
0
def test_inventory_file_simple(mocker):
    inventory_filename = "test.hosttech_dns.yaml"
    C.INVENTORY_ENABLED = ['community.dns.hosttech_dns_records']
    inventory_file = {inventory_filename: textwrap.dedent("""\
    ---
    plugin: community.dns.hosttech_dns_records
    hosttech_token: foo
    zone_name: example.com
    filters:
      type: A
    """)}

    open_url = OpenUrlProxy([
        OpenUrlCall('GET', 200)
        .expect_header('accept', 'application/json')
        .expect_header('authorization', 'Bearer foo')
        .expect_url('https://api.ns1.hosttech.eu/api/user/v1/zones', without_query=True)
        .expect_query_values('query', 'example.com')
        .return_header('Content-Type', 'application/json')
        .result_json(HOSTTECH_JSON_ZONE_LIST_RESULT),
        OpenUrlCall('GET', 200)
        .expect_header('accept', 'application/json')
        .expect_header('authorization', 'Bearer foo')
        .expect_url('https://api.ns1.hosttech.eu/api/user/v1/zones/42')
        .return_header('Content-Type', 'application/json')
        .result_json(HOSTTECH_JSON_ZONE_GET_RESULT),
    ])
    mocker.patch('ansible_collections.community.dns.plugins.module_utils.http.open_url', open_url)
    mocker.patch('ansible.inventory.manager.unfrackpath', mock_unfrackpath_noop)
    mocker.patch('os.path.exists', exists_mock(inventory_filename))
    mocker.patch('os.access', access_mock(inventory_filename))
    im = InventoryManager(loader=DictDataLoader(inventory_file), sources=inventory_filename)

    open_url.assert_is_done()

    assert im._inventory.hosts
    assert 'example.com' in im._inventory.hosts
    assert '*.example.com' in im._inventory.hosts
    assert 'foo.example.com' not in im._inventory.hosts
    assert 'bar.example.com' not in im._inventory.hosts
    assert im._inventory.get_host('example.com') in im._inventory.groups['ungrouped'].hosts
    assert im._inventory.get_host('*.example.com') in im._inventory.groups['ungrouped'].hosts
    assert im._inventory.get_host('example.com').get_vars()['ansible_host'] == '1.2.3.4'
    assert im._inventory.get_host('*.example.com').get_vars()['ansible_host'] == '1.2.3.5'
    assert len(im._inventory.groups['ungrouped'].hosts) == 2
    assert len(im._inventory.groups['all'].hosts) == 0
def test_inventory_file_record_conversion_error(mocker):
    inventory_filename = "test.hetzner_dns.yaml"
    C.INVENTORY_ENABLED = ['community.dns.hetzner_dns_records']
    inventory_file = {inventory_filename: textwrap.dedent("""\
    ---
    plugin: community.dns.hetzner_dns_records
    hetzner_token: foo
    zone_id: "{{ '42' }}"
    """)}

    open_url = OpenUrlProxy([
        OpenUrlCall('GET', 200)
        .expect_header('accept', 'application/json')
        .expect_header('auth-api-token', 'foo')
        .expect_url('https://dns.hetzner.com/api/v1/zones/42')
        .return_header('Content-Type', 'application/json')
        .result_json(HETZNER_JSON_ZONE_GET_RESULT),
        OpenUrlCall('GET', 200)
        .expect_header('accept', 'application/json')
        .expect_header('auth-api-token', 'foo')
        .expect_url('https://dns.hetzner.com/api/v1/records', without_query=True)
        .expect_query_values('zone_id', '42')
        .expect_query_values('page', '1')
        .expect_query_values('per_page', '100')
        .return_header('Content-Type', 'application/json')
        .result_json(HETZNER_JSON_ZONE_RECORDS_GET_RESULT_2),
    ])
    mocker.patch('ansible_collections.community.dns.plugins.module_utils.http.open_url', open_url)
    mocker.patch('ansible.inventory.manager.unfrackpath', mock_unfrackpath_noop)
    mocker.patch('os.path.exists', exists_mock(inventory_filename))
    mocker.patch('os.access', access_mock(inventory_filename))
    im = InventoryManager(loader=DictDataLoader(inventory_file), sources=inventory_filename)

    open_url.assert_is_done()

    # TODO: make sure that the correct error was reported

    assert not im._inventory.hosts
    assert len(im._inventory.groups['ungrouped'].hosts) == 0
    assert len(im._inventory.groups['all'].hosts) == 0
    def test_change_add_one(self):
        new_entry = (131, 42, 'CAA', '', 'test', 3600, None, None)
        open_url = OpenUrlProxy([
            OpenUrlCall('POST', 200).expect_content_predicate(
                validate_wsdl_call([
                    expect_authentication('foo', 'bar'),
                    expect_value([
                        lxmletree.QName('https://ns1.hosttech.eu/public/api',
                                        'getZone').text, 'sZoneName'
                    ], 'example.com', ('http://www.w3.org/2001/XMLSchema',
                                       'string')),
                ])).result_str(DEFAULT_ZONE_RESULT),
            OpenUrlCall('POST', 200).expect_content_predicate(
                validate_wsdl_call([
                    expect_authentication('foo', 'bar'),
                    validate_add_request('example.com', new_entry),
                ])).result_str(create_add_result(new_entry)),
        ])
        with patch(
                'ansible_collections.felixfontein.hosttech_dns.plugins.module_utils.wsdl.open_url',
                open_url):
            with pytest.raises(AnsibleExitJson) as e:
                set_module_args({
                    'hosttech_username': '******',
                    'hosttech_password': '******',
                    'state': 'present',
                    'zone': 'example.com',
                    'record': 'example.com',
                    'type': 'CAA',
                    'ttl': 3600,
                    'value': [
                        'test',
                    ],
                    '_ansible_remote_tmp': '/tmp/tmp',
                    '_ansible_keep_remote_files': True,
                })
                hosttech_dns_record.main()

        print(e.value.args[0])
        assert e.value.args[0]['changed'] is True
Пример #9
0
    def test_multiple(self):
        open_url = OpenUrlProxy([
            OpenUrlCall('POST', 200).result_json({
                '1': 2
            }).return_header(
                'content-type', 'application/json').expect_content(
                    'name=foo&[email protected]'.encode('utf-8')).
            expect_content_predicate(lambda content: True).expect_header(
                'foo', 'bar').expect_header_unset('baz'),
            OpenUrlCall('POST', 500).result_error('Error!'.encode(
                'utf-8')).expect_form_present('name').expect_form_value(
                    'email', '*****@*****.**').expect_form_value_absent(
                        'firstname').expect_url('http://example.org'),
            OpenUrlCall(
                'POST',
                400).result_error().expect_url('http://example.example'),
        ])
        with patch(
                'ansible_collections.community.internal_test_tools.plugins.lookup.open_url_test_lookup.open_url',
                open_url):
            result = self.lookup.run(
                [
                    'http://example.com', 'http://example.org',
                    'http://example.example'
                ],
                [],
                method='POST',
                headers=dict(foo='bar'),
                data=base64.b64encode('name=foo&[email protected]'.encode(
                    'utf-8')).decode('utf-8'),
            )
        open_url.assert_is_done()

        assert len(result) == 3
        assert result[0]['status'] == 200
        assert result[1]['status'] == 500
        assert result[2]['status'] == 400
        assert result[2]['content'] == ''
    def test_change_modify_list_fail(self):
        open_url = OpenUrlProxy([
            OpenUrlCall('POST', 200).expect_content_predicate(
                validate_wsdl_call([
                    expect_authentication('foo', 'bar'),
                    expect_value([
                        lxmletree.QName('https://ns1.hosttech.eu/public/api',
                                        'getZone').text, 'sZoneName'
                    ], 'example.com', ('http://www.w3.org/2001/XMLSchema',
                                       'string')),
                ])).result_str(DEFAULT_ZONE_RESULT),
        ])
        with patch(
                'ansible_collections.felixfontein.hosttech_dns.plugins.module_utils.wsdl.open_url',
                open_url):
            with pytest.raises(AnsibleFailJson) as e:
                set_module_args({
                    'hosttech_username':
                    '******',
                    'hosttech_password':
                    '******',
                    'state':
                    'present',
                    'zone':
                    'example.com',
                    'record':
                    'example.com',
                    'type':
                    'NS',
                    'ttl':
                    10800,
                    'value': [
                        'ns1.hostserv.eu',
                        'ns4.hostserv.eu',
                    ],
                    '_ansible_remote_tmp':
                    '/tmp/tmp',
                    '_ansible_keep_remote_files':
                    True,
                })
                hosttech_dns_record.main()

        print(e.value.args[0])
        assert e.value.args[0]['failed'] is True
        assert e.value.args[0][
            'msg'] == "Record already exists with different value. Set 'overwrite' to replace it"
Пример #11
0
    def test_basic(self):
        open_url = OpenUrlProxy([
            OpenUrlCall(
                'GET',
                200).result_str('hello').expect_form_value_absent('foo').
            expect_header_unset('foo').expect_url('http://example.com'),
        ])
        with patch(
                'ansible_collections.community.internal_test_tools.plugins.lookup.open_url_test_lookup.open_url',
                open_url):
            result = self.lookup.run(
                ['http://example.com'],
                [],
            )
        open_url.assert_is_done()

        assert len(result) == 1
        assert result[0]['status'] == 200
        assert result[0]['content'] == base64.b64encode(
            'hello'.encode('utf-8')).decode('utf-8')
Пример #12
0
    def test_error_in_test(self):
        open_url = OpenUrlProxy([
            OpenUrlCall('GET', 204).expect_url(
                'http://example.com#asdf',
                without_query=True).expect_query_values('foo', 'bar', 'baz'),
        ])
        with patch(
                'ansible_collections.community.internal_test_tools.plugins.lookup.open_url_test_lookup.open_url',
                open_url):
            with pytest.raises(AnsibleLookupError) as e:
                self.lookup.run(
                    [
                        'http://example.com?foo=bar&foo=baz#asdf',
                        'http://example.org'
                    ],
                    [],
                )
        open_url.assert_is_done()

        print(e.value.message)
        assert e.value.message == 'Error while GETing http://example.com?foo=bar&foo=baz#asdf: OpenUrlCall data has neither body nor error data'
Пример #13
0
def test_populate(inventory, mocker):
    open_url = OpenUrlProxy([
        OpenUrlCall('GET', 200).result_json([
            {
                'server': {
                    'server_ip': '1.2.3.4',
                },
            },
            {
                'server': {
                    'server_ip': '1.2.3.5',
                    'server_name': 'test-server',
                },
            },
        ]).expect_url('{0}/server'.format(BASE_URL)),
    ])
    mocker.patch(
        'ansible_collections.community.hrobot.plugins.module_utils.robot.open_url',
        open_url)

    inventory.get_option = mocker.MagicMock(side_effect=get_option)
    inventory.populate(inventory.get_servers())

    open_url.assert_is_done()

    host_1 = inventory.inventory.get_host('1.2.3.4')
    host_2 = inventory.inventory.get_host('test-server')

    host_1_vars = host_1.get_vars()
    host_2_vars = host_2.get_vars()

    assert host_1_vars['ansible_host'] == '1.2.3.4'
    assert host_1_vars['hrobot_server_ip'] == '1.2.3.4'
    assert 'hrobot_server_name' not in host_1_vars
    assert host_2_vars['ansible_host'] == '1.2.3.5'
    assert host_2_vars['hrobot_server_ip'] == '1.2.3.5'
    assert host_2_vars['hrobot_server_name'] == 'test-server'
Пример #14
0
    def test_error(self):
        open_url = OpenUrlProxy([
            OpenUrlCall(
                'PUT',
                404).exception(lambda: Exception('foo bar!')).expect_header(
                    'foo', 'bar').expect_header_unset('baz').expect_url(
                        'http://example.com',
                        without_query=True,
                        without_fragment=True).expect_query_values('foo', ''),
        ])
        with patch(
                'ansible_collections.community.internal_test_tools.plugins.lookup.open_url_test_lookup.open_url',
                open_url):
            with pytest.raises(AnsibleLookupError) as e:
                self.lookup.run(
                    ['http://example.com?foo', 'http://example.org'],
                    [],
                    method='PUT',
                    headers=dict(foo='bar'),
                )
        open_url.assert_is_done()

        print(e.value.message)
        assert e.value.message == 'Error while PUTing http://example.com?foo: foo bar!'
    def test_get_all(self):
        open_url = OpenUrlProxy([
            OpenUrlCall('POST', 200).expect_content_predicate(
                validate_wsdl_call([
                    expect_authentication('foo', 'bar'),
                    expect_value([
                        lxmletree.QName('https://ns1.hosttech.eu/public/api',
                                        'getZone').text, 'sZoneName'
                    ], 'example.com', ('http://www.w3.org/2001/XMLSchema',
                                       'string')),
                ])).result_str(DEFAULT_ZONE_RESULT),
        ])
        with patch(
                'ansible_collections.felixfontein.hosttech_dns.plugins.module_utils.wsdl.open_url',
                open_url):
            with pytest.raises(AnsibleExitJson) as e:
                set_module_args({
                    'hosttech_username': '******',
                    'hosttech_password': '******',
                    'what': 'all_records',
                    'zone': 'example.com.',
                    '_ansible_remote_tmp': '/tmp/tmp',
                    '_ansible_keep_remote_files': True,
                })
                hosttech_dns_record_info.main()

        print(e.value.args[0])
        assert e.value.args[0]['changed'] is False
        assert 'set' not in e.value.args[0]
        assert 'sets' in e.value.args[0]
        sets = e.value.args[0]['sets']
        assert len(sets) == 6
        assert sets[0] == {
            'record': '*.example.com',
            'ttl': 3600,
            'type': 'A',
            'value': ['1.2.3.5'],
        }
        assert sets[1] == {
            'record': '*.example.com',
            'ttl': 3600,
            'type': 'AAAA',
            'value': ['2001:1:2::4'],
        }
        assert sets[2] == {
            'record': 'example.com',
            'ttl': 3600,
            'type': 'A',
            'value': ['1.2.3.4'],
        }
        assert sets[3] == {
            'record': 'example.com',
            'ttl': 3600,
            'type': 'AAAA',
            'value': ['2001:1:2::3'],
        }
        assert sets[4] == {
            'record': 'example.com',
            'ttl': 3600,
            'type': 'MX',
            'value': ['example.com'],
        }
        assert sets[5] == {
            'record': 'example.com',
            'ttl': 10800,
            'type': 'NS',
            'value': ['ns3.hostserv.eu', 'ns2.hostserv.eu', 'ns1.hostserv.eu'],
        }
    def test_change_modify_list(self):
        del_entry = (130, 42, 'NS', '', 'ns3.hostserv.eu', 10800, None, None)
        update_entry = (131, 42, 'NS', '', 'ns4.hostserv.eu', 10800, None,
                        None)
        open_url = OpenUrlProxy([
            OpenUrlCall('POST', 200).expect_content_predicate(
                validate_wsdl_call([
                    expect_authentication('foo', 'bar'),
                    expect_value([
                        lxmletree.QName('https://ns1.hosttech.eu/public/api',
                                        'getZone').text, 'sZoneName'
                    ], 'example.com', ('http://www.w3.org/2001/XMLSchema',
                                       'string')),
                ])).result_str(DEFAULT_ZONE_RESULT),
            OpenUrlCall('POST', 200).expect_content_predicate(
                validate_wsdl_call([
                    expect_authentication('foo', 'bar'),
                    validate_del_request(del_entry),
                ])).result_str(create_del_result(True)),
            OpenUrlCall('POST', 200).expect_content_predicate(
                validate_wsdl_call([
                    expect_authentication('foo', 'bar'),
                    validate_update_request(update_entry),
                ])).result_str(create_update_result(update_entry)),
        ])
        with patch(
                'ansible_collections.felixfontein.hosttech_dns.plugins.module_utils.wsdl.open_url',
                open_url):
            with pytest.raises(AnsibleExitJson) as e:
                set_module_args({
                    'hosttech_username':
                    '******',
                    'hosttech_password':
                    '******',
                    'state':
                    'present',
                    'zone':
                    'example.com',
                    'record':
                    'example.com',
                    'type':
                    'NS',
                    'ttl':
                    10800,
                    'value': [
                        'ns1.hostserv.eu',
                        'ns4.hostserv.eu',
                    ],
                    'overwrite':
                    True,
                    '_ansible_diff':
                    True,
                    '_ansible_remote_tmp':
                    '/tmp/tmp',
                    '_ansible_keep_remote_files':
                    True,
                })
                hosttech_dns_record.main()

        print(e.value.args[0])
        assert e.value.args[0]['changed'] is True
        assert 'diff' in e.value.args[0]
        assert 'before' in e.value.args[0]['diff']
        assert 'after' in e.value.args[0]['diff']
        assert e.value.args[0]['diff']['before'] == {
            'record': 'example.com',
            'type': 'NS',
            'ttl': 10800,
            'value': ['ns1.hostserv.eu', 'ns2.hostserv.eu', 'ns3.hostserv.eu'],
        }
        assert e.value.args[0]['diff']['after'] == {
            'record': 'example.com',
            'type': 'NS',
            'ttl': 10800,
            'value': ['ns1.hostserv.eu', 'ns4.hostserv.eu'],
        }