1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 Tests for L{twisted.internet.base}.
9 from Queue import Queue
11 from zope.interface import implements
13 from twisted.python.threadpool import ThreadPool
14 from twisted.python.util import setIDFunction
15 from twisted.internet.interfaces import IReactorTime, IReactorThreads
16 from twisted.internet.error import DNSLookupError
17 from twisted.internet.base import ThreadedResolver, DelayedCall
18 from twisted.internet.task import Clock
19 from twisted.trial.unittest import TestCase
22 class FakeReactor(object):
24 A fake reactor implementation which just supports enough reactor APIs for
27 implements(IReactorTime, IReactorThreads)
31 self.callLater = self._clock.callLater
33 self._threadpool = ThreadPool()
34 self._threadpool.start()
35 self.getThreadPool = lambda: self._threadpool
37 self._threadCalls = Queue()
40 def callFromThread(self, f, *args, **kwargs):
41 self._threadCalls.put((f, args, kwargs))
44 def _runThreadCalls(self):
45 f, args, kwargs = self._threadCalls.get()
50 self._threadpool.stop()
54 class ThreadedResolverTests(TestCase):
56 Tests for L{ThreadedResolver}.
58 def test_success(self):
60 L{ThreadedResolver.getHostByName} returns a L{Deferred} which fires
61 with the value returned by the call to L{socket.gethostbyname} in the
62 threadpool of the reactor passed to L{ThreadedResolver.__init__}.
65 name = "foo.bar.example.com"
68 reactor = FakeReactor()
69 self.addCleanup(reactor._stop)
73 def fakeGetHostByName(name):
77 self.patch(socket, 'gethostbyname', fakeGetHostByName)
79 resolver = ThreadedResolver(reactor)
80 d = resolver.getHostByName(name, (timeout,))
81 d.addCallback(resolvedTo.append)
83 reactor._runThreadCalls()
85 self.assertEqual(lookedUp, [name])
86 self.assertEqual(resolvedTo, [ip])
88 # Make sure that any timeout-related stuff gets cleaned up.
89 reactor._clock.advance(timeout + 1)
90 self.assertEqual(reactor._clock.calls, [])
93 def test_failure(self):
95 L{ThreadedResolver.getHostByName} returns a L{Deferred} which fires a
96 L{Failure} if the call to L{socket.gethostbyname} raises an exception.
100 reactor = FakeReactor()
101 self.addCleanup(reactor._stop)
103 def fakeGetHostByName(name):
104 raise IOError("ENOBUFS (this is a funny joke)")
106 self.patch(socket, 'gethostbyname', fakeGetHostByName)
109 resolver = ThreadedResolver(reactor)
110 d = resolver.getHostByName("some.name", (timeout,))
111 self.assertFailure(d, DNSLookupError)
112 d.addCallback(failedWith.append)
114 reactor._runThreadCalls()
116 self.assertEqual(len(failedWith), 1)
118 # Make sure that any timeout-related stuff gets cleaned up.
119 reactor._clock.advance(timeout + 1)
120 self.assertEqual(reactor._clock.calls, [])
123 def test_timeout(self):
125 If L{socket.gethostbyname} does not complete before the specified
126 timeout elapsed, the L{Deferred} returned by
127 L{ThreadedResolver.getHostByBame} fails with L{DNSLookupError}.
131 reactor = FakeReactor()
132 self.addCleanup(reactor._stop)
135 def fakeGetHostByName(name):
138 self.patch(socket, 'gethostbyname', fakeGetHostByName)
141 resolver = ThreadedResolver(reactor)
142 d = resolver.getHostByName("some.name", (timeout,))
143 self.assertFailure(d, DNSLookupError)
144 d.addCallback(failedWith.append)
146 reactor._clock.advance(timeout - 1)
147 self.assertEqual(failedWith, [])
148 reactor._clock.advance(1)
149 self.assertEqual(len(failedWith), 1)
151 # Eventually the socket.gethostbyname does finish - in this case, with
152 # an exception. Nobody cares, though.
153 result.put(IOError("The I/O was errorful"))
157 class DelayedCallTests(TestCase):
159 Tests for L{DelayedCall}.
161 def _getDelayedCallAt(self, time):
163 Get a L{DelayedCall} instance at a given C{time}.
165 @param time: The absolute time at which the returned L{DelayedCall}
170 return DelayedCall(time, lambda: None, (), {}, noop, noop, None)
175 Create two L{DelayedCall} instanced scheduled to run at different
178 self.zero = self._getDelayedCallAt(0)
179 self.one = self._getDelayedCallAt(1)
184 The string representation of a L{DelayedCall} instance, as returned by
185 C{str}, includes the unsigned id of the instance, as well as its state,
186 the function to be called, and the function arguments.
190 dc = DelayedCall(12, nothing, (3, ), {"A": 5}, None, None, lambda: 1.5)
195 except (TypeError, KeyError):
197 self.addCleanup(setIDFunction, setIDFunction(fakeID))
200 "<DelayedCall 0xc8 [10.5s] called=0 cancelled=0 nothing(3, A=5)>")
205 For two instances of L{DelayedCall} C{a} and C{b}, C{a < b} is true
206 if and only if C{a} is scheduled to run before C{b}.
208 zero, one = self.zero, self.one
209 self.assertTrue(zero < one)
210 self.assertFalse(one < zero)
211 self.assertFalse(zero < zero)
212 self.assertFalse(one < one)
217 For two instances of L{DelayedCall} C{a} and C{b}, C{a <= b} is true
218 if and only if C{a} is scheduled to run before C{b} or at the same
221 zero, one = self.zero, self.one
222 self.assertTrue(zero <= one)
223 self.assertFalse(one <= zero)
224 self.assertTrue(zero <= zero)
225 self.assertTrue(one <= one)
230 For two instances of L{DelayedCall} C{a} and C{b}, C{a > b} is true
231 if and only if C{a} is scheduled to run after C{b}.
233 zero, one = self.zero, self.one
234 self.assertTrue(one > zero)
235 self.assertFalse(zero > one)
236 self.assertFalse(zero > zero)
237 self.assertFalse(one > one)
242 For two instances of L{DelayedCall} C{a} and C{b}, C{a > b} is true
243 if and only if C{a} is scheduled to run after C{b} or at the same
246 zero, one = self.zero, self.one
247 self.assertTrue(one >= zero)
248 self.assertFalse(zero >= one)
249 self.assertTrue(zero >= zero)
250 self.assertTrue(one >= one)
255 A L{DelayedCall} instance is only equal to itself.
257 # Explicitly use == here, instead of assertEqual, to be more
258 # confident __eq__ is being tested.
259 self.assertFalse(self.zero == self.one)
260 self.assertTrue(self.zero == self.zero)
261 self.assertTrue(self.one == self.one)
266 A L{DelayedCall} instance is not equal to any other object.
268 # Explicitly use != here, instead of assertEqual, to be more
269 # confident __ne__ is being tested.
270 self.assertTrue(self.zero != self.one)
271 self.assertFalse(self.zero != self.zero)
272 self.assertFalse(self.one != self.one)