1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 Tests for the I{hosts(5)}-based resolver, L{twisted.names.hosts}.
8 from twisted.trial.unittest import TestCase
9 from twisted.python.filepath import FilePath
10 from twisted.internet.defer import gatherResults
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
17 class SearchHostsFileTests(TestCase):
19 Tests for L{searchFileFor}, a helper which finds the first address for a
20 particular hostname in a I{hosts(5)}-style file.
22 def test_findAddress(self):
24 If there is an IPv4 address for the hostname passed to
25 L{searchFileFor}, it is returned.
27 hosts = FilePath(self.mktemp())
29 "10.2.3.4 foo.example.com\n")
31 "10.2.3.4", searchFileFor(hosts.path, "foo.example.com"))
34 def test_notFoundAddress(self):
36 If there is no address information for the hostname passed to
37 L{searchFileFor}, C{None} is returned.
39 hosts = FilePath(self.mktemp())
41 "10.2.3.4 foo.example.com\n")
43 None, searchFileFor(hosts.path, "bar.example.com"))
46 def test_firstAddress(self):
48 The first address associated with the given hostname is returned.
50 hosts = FilePath(self.mktemp())
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")
56 "::1", searchFileFor(hosts.path, "foo.example.com"))
59 def test_searchFileForAliases(self):
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.
64 hosts = FilePath(self.mktemp())
66 "127.0.1.1 helmut.example.org helmut\n"
68 "::1 localhost ip6-localhost ip6-loopback\n")
69 self.assertEqual(searchFileFor(hosts.path, 'helmut'), '127.0.1.1')
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')
78 class SearchHostsFileForAllTests(TestCase):
80 Tests for L{searchFileForAll}, a helper which finds all addresses for a
81 particular hostname in a I{hosts(5)}-style file.
83 def test_allAddresses(self):
85 L{searchFileForAll} returns a list of all addresses associated with the
88 hosts = FilePath(self.mktemp())
90 "127.0.0.1 foobar.example.com\n"
91 "127.0.0.2 foobar.example.com\n"
92 "::1 foobar.example.com\n")
94 ["127.0.0.1", "127.0.0.2", "::1"],
95 searchFileForAll(hosts, "foobar.example.com"))
98 def test_caseInsensitively(self):
100 L{searchFileForAll} searches for names case-insensitively.
102 hosts = FilePath(self.mktemp())
103 hosts.setContent("127.0.0.1 foobar.EXAMPLE.com\n")
105 ["127.0.0.1"], searchFileForAll(hosts, "FOOBAR.example.com"))
108 def test_readError(self):
110 If there is an error reading the contents of the hosts file,
111 L{searchFileForAll} returns an empty list.
114 [], searchFileForAll(FilePath(self.mktemp()), "example.com"))
118 class HostsTestCase(TestCase):
120 Tests for the I{hosts(5)}-based L{twisted.names.hosts.Resolver}.
123 f = open('EtcHosts', 'w')
125 1.1.1.1 EXAMPLE EXAMPLE.EXAMPLETHING
136 self.resolver = Resolver('EtcHosts', self.ttl)
138 def testGetHostByName(self):
139 data = [('EXAMPLE', '1.1.1.1'),
140 ('EXAMPLE.EXAMPLETHING', '1.1.1.1'),
141 ('MIXED', '1.1.1.2'),
143 ds = [self.resolver.getHostByName(n).addCallback(self.assertEqual, ip)
145 return gatherResults(ds)
148 def test_lookupAddress(self):
150 L{hosts.Resolver.lookupAddress} returns a L{Deferred} which fires with A
151 records from the hosts file.
153 d = self.resolver.lookupAddress('multiple')
154 def resolved((results, authority, additional)):
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))),
161 d.addCallback(resolved)
165 def test_lookupIPV6Address(self):
167 L{hosts.Resolver.lookupIPV6Address} returns a L{Deferred} which fires
168 with AAAA records from the hosts file.
170 d = self.resolver.lookupIPV6Address('ip6-multiple')
171 def resolved((results, authority, additional)):
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))),
178 d.addCallback(resolved)
182 def test_lookupAllRecords(self):
184 L{hosts.Resolver.lookupAllRecords} returns a L{Deferred} which fires
185 with A records from the hosts file.
187 d = self.resolver.lookupAllRecords('mixed')
188 def resolved((results, authority, additional)):
190 (RRHeader("mixed", A, IN, self.ttl,
191 Record_A("1.1.1.2", self.ttl)),),
193 d.addCallback(resolved)
197 def testNotImplemented(self):
198 return self.assertFailure(self.resolver.lookupMailExchange('EXAMPLE'),
202 d = self.resolver.query(Query('EXAMPLE'))
203 d.addCallback(lambda x: self.assertEqual(x[0][0].payload.dottedQuad(),
207 def test_lookupAddressNotFound(self):
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
213 return self.assertFailure(self.resolver.lookupAddress('foueoa'),
216 def test_lookupIPV6AddressNotFound(self):
218 Like L{test_lookupAddressNotFound}, but for
219 L{hosts.Resolver.lookupIPV6Address}.
221 return self.assertFailure(self.resolver.lookupIPV6Address('foueoa'),
224 def test_lookupAllRecordsNotFound(self):
226 Like L{test_lookupAddressNotFound}, but for
227 L{hosts.Resolver.lookupAllRecords}.
229 return self.assertFailure(self.resolver.lookupAllRecords('foueoa'),