class _ResolverTestMixin(object):
- def skipOnCares(self):
- # Some DNS-hijacking ISPs (e.g. Time Warner) return non-empty results
- # with an NXDOMAIN status code. Most resolvers treat this as an error;
- # C-ares returns the results, making the "bad_host" tests unreliable.
- # C-ares will try to resolve even malformed names, such as the
- # name with spaces used in this test.
- if self.resolver.__class__.__name__ == 'CaresResolver':
- self.skipTest("CaresResolver doesn't recognize fake NXDOMAIN")
-
def test_localhost(self):
self.resolver.resolve('localhost', 80, callback=self.stop)
result = self.wait()
self.assertIn((socket.AF_INET, ('127.0.0.1', 80)),
addrinfo)
+
+# It is impossible to quickly and consistently generate an error in name
+# resolution, so test this case separately, using mocks as needed.
+class _ResolverErrorTestMixin(object):
def test_bad_host(self):
- self.skipOnCares()
def handler(exc_typ, exc_val, exc_tb):
self.stop(exc_val)
return True # Halt propagation.
@gen_test
def test_future_interface_bad_host(self):
- self.skipOnCares()
with self.assertRaises(Exception):
yield self.resolver.resolve('an invalid domain', 80,
socket.AF_UNSPEC)
+def _failing_getaddrinfo(*args):
+ """Dummy implementation of getaddrinfo for use in mocks"""
+ raise socket.gaierror("mock: lookup failed")
@skipIfNoNetwork
class BlockingResolverTest(AsyncTestCase, _ResolverTestMixin):
self.resolver = BlockingResolver(io_loop=self.io_loop)
+# getaddrinfo-based tests need mocking to reliably generate errors;
+# some configurations are slow to produce errors and take longer than
+# our default timeout.
+class BlockingResolverErrorTest(AsyncTestCase, _ResolverErrorTestMixin):
+ def setUp(self):
+ super(BlockingResolverErrorTest, self).setUp()
+ self.resolver = BlockingResolver(io_loop=self.io_loop)
+ self.real_getaddrinfo = socket.getaddrinfo
+ socket.getaddrinfo = _failing_getaddrinfo
+
+ def tearDown(self):
+ socket.getaddrinfo = self.real_getaddrinfo
+ super(BlockingResolverErrorTest, self).tearDown()
+
+
@skipIfNoNetwork
@unittest.skipIf(futures is None, "futures module not present")
class ThreadedResolverTest(AsyncTestCase, _ResolverTestMixin):
super(ThreadedResolverTest, self).tearDown()
+class ThreadedResolverErrorTest(AsyncTestCase, _ResolverErrorTestMixin):
+ def setUp(self):
+ super(ThreadedResolverErrorTest, self).setUp()
+ self.resolver = BlockingResolver(io_loop=self.io_loop)
+ self.real_getaddrinfo = socket.getaddrinfo
+ socket.getaddrinfo = _failing_getaddrinfo
+
+ def tearDown(self):
+ socket.getaddrinfo = self.real_getaddrinfo
+ super(ThreadedResolverErrorTest, self).tearDown()
+
+
@skipIfNoNetwork
@unittest.skipIf(futures is None, "futures module not present")
@unittest.skipIf(sys.platform == 'win32', "preexec_fn not available on win32")
self.fail("import timed out")
+# We do not test errors with CaresResolver:
+# Some DNS-hijacking ISPs (e.g. Time Warner) return non-empty results
+# with an NXDOMAIN status code. Most resolvers treat this as an error;
+# C-ares returns the results, making the "bad_host" tests unreliable.
+# C-ares will try to resolve even malformed names, such as the
+# name with spaces used in this test.
@skipIfNoNetwork
@unittest.skipIf(pycares is None, "pycares module not present")
class CaresResolverTest(AsyncTestCase, _ResolverTestMixin):
self.resolver = CaresResolver(io_loop=self.io_loop)
+# TwistedResolver produces consistent errors in our test cases so we
+# can test the regular and error cases in the same class.
@skipIfNoNetwork
@unittest.skipIf(twisted is None, "twisted module not present")
@unittest.skipIf(getattr(twisted, '__version__', '0.0') < "12.1", "old version of twisted")
-class TwistedResolverTest(AsyncTestCase, _ResolverTestMixin):
+class TwistedResolverTest(AsyncTestCase, _ResolverTestMixin,
+ _ResolverErrorTestMixin):
def setUp(self):
super(TwistedResolverTest, self).setUp()
self.resolver = TwistedResolver(io_loop=self.io_loop)