File: dnsq_test.py

package info (click to toggle)
python-dnsq 1.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 96 kB
  • sloc: python: 229; makefile: 3
file content (146 lines) | stat: -rw-r--r-- 5,328 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import socket
import time

import dns
import dns.resolver
import dnsq
from mock import Mock, patch
from nose.tools import eq_, ok_, assert_raises


def test_dns_query():
    # note: we're not mocking DNS, i.e. you need to have internet connection to run this
    # test. perhaps we should change it?
    answer = dnsq.query_dns('mailgun.net', 'mx')
    eq_(2, len(answer))
    ok_("10 mxa.mailgun.org." in answer)
    ok_("10 mxb.mailgun.org." in answer)

    # test TXT concatenation:
    with patch.object(dns.resolver.Resolver, 'query') as query:
        query.reset_mock()
        query.return_value = [Mock()]
        query.return_value[0].to_text = Mock(return_value="\"Hello\" \"world\"")
        eq_(['Helloworld'], dnsq.query_dns('mailgun.us', 'txt'))

        # specify the name server
        eq_(['Helloworld'], dnsq.query_dns('mailgun.us', 'txt',
                                           name_srv='ns1.com'))
        # socket error
        query.side_effect = socket.error
        eq_([], dnsq.query_dns('mailgun.us', 'txt'))

        # test fallback to default nameserver
        query.side_effect = dns.exception.Timeout
        eq_([], dnsq.query_dns('mailgun.us', 'txt', name_srv='ns1.com'))

    # test errors:
    with patch.object(dns.resolver.Resolver, 'query') as query:
        query.side_effect = dns.resolver.NoNameservers()
        eq_([], dnsq.query_dns('mailgun.net', 'mx'))
        query.side_effect = dns.resolver.NXDOMAIN()
        eq_([], dnsq.query_dns('mailgun.net', 'mx'))
        query.side_effect = dns.resolver.NoAnswer()
        eq_([], dnsq.query_dns('mailgun.net', 'mx'))


def test_mx_lookup():
    # query against live DNS server:
    answer = dnsq.mx_hosts_for('gmail.com')[0]
    ok_('google.com' in answer)

    with patch.object(dnsq, '_get_default_resolver') as get_resolver:
        r = Mock()
        get_resolver.return_value = r

        # makes a fake MX reply
        def fake_mx(name):
            class FakeEntry(object):
                @property
                def preference(self): return 1

                @property
                def exchange(self):
                    class Value(object):
                        def to_text(self): return name

                    return Value()

            return FakeEntry()

        # test MX timeout failure:
        with patch.object(r, 'query', Mock(side_effect=dns.exception.Timeout)):
            eq_([], dnsq.mx_hosts_for('host.com'))

        # test querying an invalid domain:
        with patch.object(r, 'query',
                          Mock(side_effect=dns.resolver.NXDOMAIN())):
            eq_([], dnsq.mx_hosts_for('invalid-siteeeee.com'))

        # test querying a domain without MX:
        with patch.object(r, 'query',
                          Mock(side_effect=dns.resolver.NoAnswer())):
            eq_(['host.com'], dnsq.mx_hosts_for('host.com'))

        # test querying a domain with MX:
        with patch.object(r, 'query') as query_mock:
            query_mock.return_value = [fake_mx('mx.host.com.'),
                                       fake_mx('mx2.host.com.')]
            eq_(set(['mx.host.com', 'mx2.host.com']),
                set(dnsq.mx_hosts_for('host.com')))

        # test failure:
        with patch.object(r, 'query', Mock(side_effect=Exception('bam!'))):
            assert_raises(Exception, dnsq.mx_hosts_for, 'host.com')

        # test dns failure
        with patch.object(dnsq, '_exec_query') as exec_query:
            exec_query.side_effect = dns.exception.Timeout
            assert_raises(Exception, dnsq.mx_hosts_for, 'host.com')


@patch.object(dnsq, 'get_primary_nameserver', Mock(return_value='ns.com'))
@patch.object(dnsq, 'query_dns')
def test_spf_record_for(dns):
    # No SPF records
    dns.return_value = ["blah"]
    eq_('', dnsq.spf_record_for('host.com'))

    # Multiple SPF records
    dns.return_value = ["v=spf1 +all", "blah", "v=spf1 -all"]
    eq_('', dnsq.spf_record_for('host.com'))

    # OK - one SPF record
    dns.return_value = ["blah", "v=spf1 +all", "blahblah"]
    eq_("v=spf1 +all", dnsq.spf_record_for('host.com'))


def test_ptr_record_for():
    eq_(dnsq.ptr_record_for('127.0.0.1'), 'localhost')

    # Ev: this one actually "calls the internet". Which is pretty bad from the maintenance
    # perspective, but I am not sure how else to reliably cover it:
    eq_(dnsq.ptr_record_for('50.56.21.178'),
        socket.gethostbyaddr('50.56.21.178')[0])

    # lets test caching:
    with patch.object(dnsq, 'query_dns') as query_dns:
        query_dns.return_value = []
        eq_(None, dnsq.ptr_record_for('1.1.1.1'))
        then = time.time()  # measure time
        eq_(None, dnsq.ptr_record_for('1.1.1.1'))
        eq_(1, query_dns.call_count, "query_dns() should be called only once!" \
                                     "... otherwise the PTR cache is not working!")

        time_elapsed = (time.time() - then)
        ok_(time_elapsed < 0.001,
            "PTR lookup was too slow. The cache is not working?")

        query_dns.side_effect = Exception('Bam!')
        eq_(None, dnsq.ptr_record_for('1.1.1.2'))


@patch.object(dnsq, 'query_dns')
def test_get_primary_nameserver(query_dns):
    query_dns.side_effect = [[], ['srv1.com.', 'srv2.com.']]
    eq_('srv1.com', dnsq.get_primary_nameserver('tratata.ololo.com'))