Skip to content

Commit 426633d

Browse files
committed
Add search method
1 parent aac8df5 commit 426633d

File tree

2 files changed

+129
-2
lines changed

2 files changed

+129
-2
lines changed

aiodns/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,22 @@ def query(self, host: str, qtype: str, qclass: str=None) -> asyncio.Future:
9090
self._channel.query(host, qtype, cb, query_class=qclass)
9191
return fut
9292

93+
def search(self, host: str, qtype: str, qclass: str=None) -> asyncio.Future:
94+
try:
95+
qtype = query_type_map[qtype]
96+
except KeyError:
97+
raise ValueError('invalid query type: {}'.format(qtype))
98+
if qclass is not None:
99+
try:
100+
qclass = query_class_map[qclass]
101+
except KeyError:
102+
raise ValueError('invalid query class: {}'.format(qclass))
103+
104+
fut = asyncio.Future(loop=self.loop) # type: asyncio.Future
105+
cb = functools.partial(self._callback, fut)
106+
self._channel.search(host, qtype, cb, query_class=qclass)
107+
return fut
108+
93109
def gethostbyname(self, host: str, family: socket.AddressFamily) -> asyncio.Future:
94110
fut = asyncio.Future(loop=self.loop) # type: asyncio.Future
95111
cb = functools.partial(self._callback, fut)

tests.py

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import ipaddress
55
import unittest
66
import socket
7-
import sys
87

98
import aiodns
109

@@ -130,6 +129,118 @@ async def coro(self, host, qtype, n=2):
130129
self.assertTrue(result)
131130
self.loop.run_until_complete(coro(self, 'gmail.com', 'MX'))
132131

132+
def test_search_a(self):
133+
f = self.resolver.search('google.com', 'A')
134+
result = self.loop.run_until_complete(f)
135+
self.assertTrue(result)
136+
137+
def test_search_async_await(self):
138+
async def f():
139+
return await self.resolver.search('google.com', 'A')
140+
result = self.loop.run_until_complete(f())
141+
self.assertTrue(result)
142+
143+
def test_search_a_bad(self):
144+
f = self.resolver.search('hgf8g2od29hdohid.com', 'A')
145+
try:
146+
self.loop.run_until_complete(f)
147+
except aiodns.error.DNSError as e:
148+
self.assertEqual(e.args[0], aiodns.error.ARES_ENOTFOUND)
149+
150+
def test_search_aaaa(self):
151+
f = self.resolver.search('ipv6.google.com', 'AAAA')
152+
result = self.loop.run_until_complete(f)
153+
self.assertTrue(result)
154+
155+
def test_search_cname(self):
156+
f = self.resolver.search('www.amazon.com', 'CNAME')
157+
result = self.loop.run_until_complete(f)
158+
self.assertTrue(result)
159+
160+
def test_search_mx(self):
161+
f = self.resolver.search('google.com', 'MX')
162+
result = self.loop.run_until_complete(f)
163+
self.assertTrue(result)
164+
165+
def test_search_ns(self):
166+
f = self.resolver.search('google.com', 'NS')
167+
result = self.loop.run_until_complete(f)
168+
self.assertTrue(result)
169+
170+
def test_search_txt(self):
171+
f = self.resolver.search('google.com', 'TXT')
172+
result = self.loop.run_until_complete(f)
173+
self.assertTrue(result)
174+
175+
def test_search_soa(self):
176+
f = self.resolver.search('google.com', 'SOA')
177+
result = self.loop.run_until_complete(f)
178+
self.assertTrue(result)
179+
180+
def test_search_srv(self):
181+
f = self.resolver.search('_xmpp-server._tcp.jabber.org', 'SRV')
182+
result = self.loop.run_until_complete(f)
183+
self.assertTrue(result)
184+
185+
def test_search_naptr(self):
186+
f = self.resolver.search('sip2sip.info', 'NAPTR')
187+
result = self.loop.run_until_complete(f)
188+
self.assertTrue(result)
189+
190+
def test_search_ptr(self):
191+
ip = '8.8.8.8'
192+
f = self.resolver.search(ipaddress.ip_address(ip).reverse_pointer, 'PTR')
193+
result = self.loop.run_until_complete(f)
194+
self.assertTrue(result)
195+
196+
def test_search_bad_type(self):
197+
self.assertRaises(ValueError, self.resolver.search, 'google.com', 'XXX')
198+
199+
def test_search_txt_chaos(self):
200+
self.resolver = aiodns.DNSResolver(loop=self.loop)
201+
self.resolver.nameservers = ['1.1.1.1']
202+
f = self.resolver.search('id.server', 'TXT', 'CHAOS')
203+
result = self.loop.run_until_complete(f)
204+
self.assertTrue(result)
205+
206+
def test_search_bad_class(self):
207+
self.assertRaises(ValueError, self.resolver.search, 'google.com', 'A', "INVALIDCLASS")
208+
209+
def test_search_timeout(self):
210+
self.resolver = aiodns.DNSResolver(timeout=0.1, loop=self.loop)
211+
self.resolver.nameservers = ['1.2.3.4']
212+
f = self.resolver.search('google.com', 'A')
213+
try:
214+
self.loop.run_until_complete(f)
215+
except aiodns.error.DNSError as e:
216+
self.assertEqual(e.args[0], aiodns.error.ARES_ETIMEOUT)
217+
218+
def test_search_cancel(self):
219+
f = self.resolver.search('google.com', 'A')
220+
self.resolver.cancel()
221+
try:
222+
self.loop.run_until_complete(f)
223+
except aiodns.error.DNSError as e:
224+
self.assertEqual(e.args[0], aiodns.error.ARES_ECANCELLED)
225+
226+
def test_search_future_cancel(self):
227+
f = self.resolver.search('google.com', 'A')
228+
f.cancel()
229+
async def coro():
230+
await asyncio.sleep(0.1)
231+
await f
232+
try:
233+
self.loop.run_until_complete(coro())
234+
except asyncio.CancelledError as e:
235+
self.assertTrue(e)
236+
237+
def test_search_twice(self):
238+
async def coro(self, host, qtype, n=2):
239+
for i in range(n):
240+
result = await self.resolver.search(host, qtype)
241+
self.assertTrue(result)
242+
self.loop.run_until_complete(coro(self, 'gmail.com', 'MX'))
243+
133244
def test_gethostbyname(self):
134245
f = self.resolver.gethostbyname('google.com', socket.AF_INET)
135246
result = self.loop.run_until_complete(f)
@@ -151,7 +262,7 @@ def test_gethostbyname_bad_family(self):
151262
self.loop.run_until_complete(f)
152263

153264
def test_query_bad_chars(self):
154-
f = self.resolver.query('xn--cardeosapeluqueros-r0b.com', 'MX')
265+
f = self.resolver.query('xn--bcher-kva.de', 'A')
155266
result = self.loop.run_until_complete(f)
156267
self.assertTrue(result)
157268

0 commit comments

Comments
 (0)