Imported Upstream version 12.1.0
[contrib/python-twisted.git] / twisted / names / test / test_hosts.py
1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4 """
5 Tests for the I{hosts(5)}-based resolver, L{twisted.names.hosts}.
6 """
7
8 from twisted.trial.unittest import TestCase
9 from twisted.python.filepath import FilePath
10 from twisted.internet.defer import gatherResults
11
12 from twisted.names.dns import (
13     A, AAAA, IN, DomainError, RRHeader, Query, Record_A, Record_AAAA)
14 from twisted.names.hosts import Resolver, searchFileFor, searchFileForAll
15
16
17 class SearchHostsFileTests(TestCase):
18     """
19     Tests for L{searchFileFor}, a helper which finds the first address for a
20     particular hostname in a I{hosts(5)}-style file.
21     """
22     def test_findAddress(self):
23         """
24         If there is an IPv4 address for the hostname passed to
25         L{searchFileFor}, it is returned.
26         """
27         hosts = FilePath(self.mktemp())
28         hosts.setContent(
29             "10.2.3.4 foo.example.com\n")
30         self.assertEqual(
31             "10.2.3.4", searchFileFor(hosts.path, "foo.example.com"))
32
33
34     def test_notFoundAddress(self):
35         """
36         If there is no address information for the hostname passed to
37         L{searchFileFor}, C{None} is returned.
38         """
39         hosts = FilePath(self.mktemp())
40         hosts.setContent(
41             "10.2.3.4 foo.example.com\n")
42         self.assertIdentical(
43             None, searchFileFor(hosts.path, "bar.example.com"))
44
45
46     def test_firstAddress(self):
47         """
48         The first address associated with the given hostname is returned.
49         """
50         hosts = FilePath(self.mktemp())
51         hosts.setContent(
52             "::1 foo.example.com\n"
53             "10.1.2.3 foo.example.com\n"
54             "fe80::21b:fcff:feee:5a1d foo.example.com\n")
55         self.assertEqual(
56             "::1", searchFileFor(hosts.path, "foo.example.com"))
57
58
59     def test_searchFileForAliases(self):
60         """
61         For a host with a canonical name and one or more aliases,
62         L{searchFileFor} can find an address given any of the names.
63         """
64         hosts = FilePath(self.mktemp())
65         hosts.setContent(
66             "127.0.1.1  helmut.example.org      helmut\n"
67             "# a comment\n"
68             "::1     localhost ip6-localhost ip6-loopback\n")
69         self.assertEqual(searchFileFor(hosts.path, 'helmut'), '127.0.1.1')
70         self.assertEqual(
71             searchFileFor(hosts.path, 'helmut.example.org'), '127.0.1.1')
72         self.assertEqual(searchFileFor(hosts.path, 'ip6-localhost'), '::1')
73         self.assertEqual(searchFileFor(hosts.path, 'ip6-loopback'), '::1')
74         self.assertEqual(searchFileFor(hosts.path, 'localhost'), '::1')
75
76
77
78 class SearchHostsFileForAllTests(TestCase):
79     """
80     Tests for L{searchFileForAll}, a helper which finds all addresses for a
81     particular hostname in a I{hosts(5)}-style file.
82     """
83     def test_allAddresses(self):
84         """
85         L{searchFileForAll} returns a list of all addresses associated with the
86         name passed to it.
87         """
88         hosts = FilePath(self.mktemp())
89         hosts.setContent(
90             "127.0.0.1     foobar.example.com\n"
91             "127.0.0.2     foobar.example.com\n"
92             "::1           foobar.example.com\n")
93         self.assertEqual(
94             ["127.0.0.1", "127.0.0.2", "::1"],
95             searchFileForAll(hosts, "foobar.example.com"))
96
97
98     def test_caseInsensitively(self):
99         """
100         L{searchFileForAll} searches for names case-insensitively.
101         """
102         hosts = FilePath(self.mktemp())
103         hosts.setContent("127.0.0.1     foobar.EXAMPLE.com\n")
104         self.assertEqual(
105             ["127.0.0.1"], searchFileForAll(hosts, "FOOBAR.example.com"))
106
107
108     def test_readError(self):
109         """
110         If there is an error reading the contents of the hosts file,
111         L{searchFileForAll} returns an empty list.
112         """
113         self.assertEqual(
114             [], searchFileForAll(FilePath(self.mktemp()), "example.com"))
115
116
117
118 class HostsTestCase(TestCase):
119     """
120     Tests for the I{hosts(5)}-based L{twisted.names.hosts.Resolver}.
121     """
122     def setUp(self):
123         f = open('EtcHosts', 'w')
124         f.write('''
125 1.1.1.1    EXAMPLE EXAMPLE.EXAMPLETHING
126 ::2        mixed
127 1.1.1.2    MIXED
128 ::1        ip6thingy
129 1.1.1.3    multiple
130 1.1.1.4    multiple
131 ::3        ip6-multiple
132 ::4        ip6-multiple
133 ''')
134         f.close()
135         self.ttl = 4200
136         self.resolver = Resolver('EtcHosts', self.ttl)
137
138     def testGetHostByName(self):
139         data = [('EXAMPLE', '1.1.1.1'),
140                 ('EXAMPLE.EXAMPLETHING', '1.1.1.1'),
141                 ('MIXED', '1.1.1.2'),
142                 ]
143         ds = [self.resolver.getHostByName(n).addCallback(self.assertEqual, ip)
144               for n, ip in data]
145         return gatherResults(ds)
146
147
148     def test_lookupAddress(self):
149         """
150         L{hosts.Resolver.lookupAddress} returns a L{Deferred} which fires with A
151         records from the hosts file.
152         """
153         d = self.resolver.lookupAddress('multiple')
154         def resolved((results, authority, additional)):
155             self.assertEqual(
156                 (RRHeader("multiple", A, IN, self.ttl,
157                           Record_A("1.1.1.3", self.ttl)),
158                  RRHeader("multiple", A, IN, self.ttl,
159                           Record_A("1.1.1.4", self.ttl))),
160                 results)
161         d.addCallback(resolved)
162         return d
163
164
165     def test_lookupIPV6Address(self):
166         """
167         L{hosts.Resolver.lookupIPV6Address} returns a L{Deferred} which fires
168         with AAAA records from the hosts file.
169         """
170         d = self.resolver.lookupIPV6Address('ip6-multiple')
171         def resolved((results, authority, additional)):
172             self.assertEqual(
173                 (RRHeader("ip6-multiple", AAAA, IN, self.ttl,
174                           Record_AAAA("::3", self.ttl)),
175                  RRHeader("ip6-multiple", AAAA, IN, self.ttl,
176                           Record_AAAA("::4", self.ttl))),
177                 results)
178         d.addCallback(resolved)
179         return d
180
181
182     def test_lookupAllRecords(self):
183         """
184         L{hosts.Resolver.lookupAllRecords} returns a L{Deferred} which fires
185         with A records from the hosts file.
186         """
187         d = self.resolver.lookupAllRecords('mixed')
188         def resolved((results, authority, additional)):
189             self.assertEqual(
190                 (RRHeader("mixed", A, IN, self.ttl,
191                           Record_A("1.1.1.2", self.ttl)),),
192                 results)
193         d.addCallback(resolved)
194         return d
195
196
197     def testNotImplemented(self):
198         return self.assertFailure(self.resolver.lookupMailExchange('EXAMPLE'),
199                                   NotImplementedError)
200
201     def testQuery(self):
202         d = self.resolver.query(Query('EXAMPLE'))
203         d.addCallback(lambda x: self.assertEqual(x[0][0].payload.dottedQuad(),
204                                                  '1.1.1.1'))
205         return d
206
207     def test_lookupAddressNotFound(self):
208         """
209         L{hosts.Resolver.lookupAddress} returns a L{Deferred} which fires with
210         L{dns.DomainError} if the name passed in has no addresses in the hosts
211         file.
212         """
213         return self.assertFailure(self.resolver.lookupAddress('foueoa'),
214                                   DomainError)
215
216     def test_lookupIPV6AddressNotFound(self):
217         """
218         Like L{test_lookupAddressNotFound}, but for
219         L{hosts.Resolver.lookupIPV6Address}.
220         """
221         return self.assertFailure(self.resolver.lookupIPV6Address('foueoa'),
222                                   DomainError)
223
224     def test_lookupAllRecordsNotFound(self):
225         """
226         Like L{test_lookupAddressNotFound}, but for
227         L{hosts.Resolver.lookupAllRecords}.
228         """
229         return self.assertFailure(self.resolver.lookupAllRecords('foueoa'),
230                                   DomainError)
231
232