OLD | NEW |
| (Empty) |
1 from __future__ import generators, nested_scopes | |
2 | |
3 import sys | |
4 | |
5 from twisted.internet import reactor | |
6 | |
7 from twisted.trial import unittest, util | |
8 | |
9 from twisted.internet.defer import waitForDeferred, deferredGenerator, Deferred | |
10 from twisted.internet import defer | |
11 | |
12 def getThing(): | |
13 d = Deferred() | |
14 reactor.callLater(0, d.callback, "hi") | |
15 return d | |
16 | |
17 def getOwie(): | |
18 d = Deferred() | |
19 def CRAP(): | |
20 d.errback(ZeroDivisionError('OMG')) | |
21 reactor.callLater(0, CRAP) | |
22 return d | |
23 | |
24 # NOTE: most of the tests in DeferredGeneratorTests are duplicated | |
25 # with slightly different syntax for the InlineCallbacksTests below. | |
26 | |
27 class TerminalException(Exception): | |
28 pass | |
29 | |
30 class BaseDefgenTests: | |
31 """ | |
32 This class sets up a bunch of test cases which will test both | |
33 deferredGenerator and inlineCallbacks based generators. The subclasses | |
34 DeferredGeneratorTests and InlineCallbacksTests each provide the actual | |
35 generator implementations tested. | |
36 """ | |
37 | |
38 def testBasics(self): | |
39 """ | |
40 Test that a normal deferredGenerator works. Tests yielding a | |
41 deferred which callbacks, as well as a deferred errbacks. Also | |
42 ensures returning a final value works. | |
43 """ | |
44 | |
45 return self._genBasics().addCallback(self.assertEqual, 'WOOSH') | |
46 | |
47 def testBuggy(self): | |
48 """ | |
49 Ensure that a buggy generator properly signals a Failure | |
50 condition on result deferred. | |
51 """ | |
52 return self.assertFailure(self._genBuggy(), ZeroDivisionError) | |
53 | |
54 def testNothing(self): | |
55 """Test that a generator which never yields results in None.""" | |
56 | |
57 return self._genNothing().addCallback(self.assertEqual, None) | |
58 | |
59 def testHandledTerminalFailure(self): | |
60 """ | |
61 Create a Deferred Generator which yields a Deferred which fails and | |
62 handles the exception which results. Assert that the Deferred | |
63 Generator does not errback its Deferred. | |
64 """ | |
65 return self._genHandledTerminalFailure().addCallback(self.assertEqual, N
one) | |
66 | |
67 def testHandledTerminalAsyncFailure(self): | |
68 """ | |
69 Just like testHandledTerminalFailure, only with a Deferred which fires | |
70 asynchronously with an error. | |
71 """ | |
72 d = defer.Deferred() | |
73 deferredGeneratorResultDeferred = self._genHandledTerminalAsyncFailure(d
) | |
74 d.errback(TerminalException("Handled Terminal Failure")) | |
75 return deferredGeneratorResultDeferred.addCallback( | |
76 self.assertEqual, None) | |
77 | |
78 def testStackUsage(self): | |
79 """ | |
80 Make sure we don't blow the stack when yielding immediately | |
81 available deferreds. | |
82 """ | |
83 return self._genStackUsage().addCallback(self.assertEqual, 0) | |
84 | |
85 def testStackUsage2(self): | |
86 """ | |
87 Make sure we don't blow the stack when yielding immediately | |
88 available values. | |
89 """ | |
90 return self._genStackUsage2().addCallback(self.assertEqual, 0) | |
91 | |
92 | |
93 | |
94 | |
95 class DeferredGeneratorTests(BaseDefgenTests, unittest.TestCase): | |
96 | |
97 # First provide all the generator impls necessary for BaseDefgenTests | |
98 def _genBasics(self): | |
99 | |
100 x = waitForDeferred(getThing()) | |
101 yield x | |
102 x = x.getResult() | |
103 | |
104 self.assertEquals(x, "hi") | |
105 | |
106 ow = waitForDeferred(getOwie()) | |
107 yield ow | |
108 try: | |
109 ow.getResult() | |
110 except ZeroDivisionError, e: | |
111 self.assertEquals(str(e), 'OMG') | |
112 yield "WOOSH" | |
113 return | |
114 _genBasics = deferredGenerator(_genBasics) | |
115 | |
116 def _genBuggy(self): | |
117 yield waitForDeferred(getThing()) | |
118 1/0 | |
119 _genBuggy = deferredGenerator(_genBuggy) | |
120 | |
121 | |
122 def _genNothing(self): | |
123 if 0: yield 1 | |
124 _genNothing = deferredGenerator(_genNothing) | |
125 | |
126 def _genHandledTerminalFailure(self): | |
127 x = waitForDeferred(defer.fail(TerminalException("Handled Terminal Failu
re"))) | |
128 yield x | |
129 try: | |
130 x.getResult() | |
131 except TerminalException: | |
132 pass | |
133 _genHandledTerminalFailure = deferredGenerator(_genHandledTerminalFailure) | |
134 | |
135 | |
136 def _genHandledTerminalAsyncFailure(self, d): | |
137 x = waitForDeferred(d) | |
138 yield x | |
139 try: | |
140 x.getResult() | |
141 except TerminalException: | |
142 pass | |
143 _genHandledTerminalAsyncFailure = deferredGenerator(_genHandledTerminalAsync
Failure) | |
144 | |
145 | |
146 def _genStackUsage(self): | |
147 for x in range(5000): | |
148 # Test with yielding a deferred | |
149 x = waitForDeferred(defer.succeed(1)) | |
150 yield x | |
151 x = x.getResult() | |
152 yield 0 | |
153 _genStackUsage = deferredGenerator(_genStackUsage) | |
154 | |
155 def _genStackUsage2(self): | |
156 for x in range(5000): | |
157 # Test with yielding a random value | |
158 yield 1 | |
159 yield 0 | |
160 _genStackUsage2 = deferredGenerator(_genStackUsage2) | |
161 | |
162 # Tests unique to deferredGenerator | |
163 | |
164 def testDeferredYielding(self): | |
165 """ | |
166 Ensure that yielding a Deferred directly is trapped as an | |
167 error. | |
168 """ | |
169 # See the comment _deferGenerator about d.callback(Deferred). | |
170 def _genDeferred(): | |
171 yield getThing() | |
172 _genDeferred = deferredGenerator(_genDeferred) | |
173 | |
174 return self.assertFailure(_genDeferred(), TypeError) | |
175 | |
176 | |
177 | |
178 ## This has to be in a string so the new yield syntax doesn't cause a | |
179 ## syntax error in Python 2.4 and before. | |
180 inlineCallbacksTestsSource = ''' | |
181 from twisted.internet.defer import inlineCallbacks, returnValue | |
182 | |
183 class InlineCallbacksTests(BaseDefgenTests, unittest.TestCase): | |
184 # First provide all the generator impls necessary for BaseDefgenTests | |
185 | |
186 def _genBasics(self): | |
187 | |
188 x = yield getThing() | |
189 | |
190 self.assertEquals(x, "hi") | |
191 | |
192 try: | |
193 ow = yield getOwie() | |
194 except ZeroDivisionError, e: | |
195 self.assertEquals(str(e), 'OMG') | |
196 returnValue("WOOSH") | |
197 _genBasics = inlineCallbacks(_genBasics) | |
198 | |
199 def _genBuggy(self): | |
200 yield getThing() | |
201 1/0 | |
202 _genBuggy = inlineCallbacks(_genBuggy) | |
203 | |
204 | |
205 def _genNothing(self): | |
206 if 0: yield 1 | |
207 _genNothing = inlineCallbacks(_genNothing) | |
208 | |
209 | |
210 def _genHandledTerminalFailure(self): | |
211 try: | |
212 x = yield defer.fail(TerminalException("Handled Terminal Failure")) | |
213 except TerminalException: | |
214 pass | |
215 _genHandledTerminalFailure = inlineCallbacks(_genHandledTerminalFailure) | |
216 | |
217 | |
218 def _genHandledTerminalAsyncFailure(self, d): | |
219 try: | |
220 x = yield d | |
221 except TerminalException: | |
222 pass | |
223 _genHandledTerminalAsyncFailure = inlineCallbacks( | |
224 _genHandledTerminalAsyncFailure) | |
225 | |
226 | |
227 def _genStackUsage(self): | |
228 for x in range(5000): | |
229 # Test with yielding a deferred | |
230 x = yield defer.succeed(1) | |
231 returnValue(0) | |
232 _genStackUsage = inlineCallbacks(_genStackUsage) | |
233 | |
234 def _genStackUsage2(self): | |
235 for x in range(5000): | |
236 # Test with yielding a random value | |
237 yield 1 | |
238 returnValue(0) | |
239 _genStackUsage2 = inlineCallbacks(_genStackUsage2) | |
240 | |
241 # Tests unique to inlineCallbacks | |
242 | |
243 def testYieldNonDeferrred(self): | |
244 """ | |
245 Ensure that yielding a non-deferred passes it back as the | |
246 result of the yield expression. | |
247 """ | |
248 def _test(): | |
249 x = yield 5 | |
250 returnValue(5) | |
251 _test = inlineCallbacks(_test) | |
252 | |
253 return _test().addCallback(self.assertEqual, 5) | |
254 | |
255 def testReturnNoValue(self): | |
256 """Ensure a standard python return results in a None result.""" | |
257 def _noReturn(): | |
258 yield 5 | |
259 return | |
260 _noReturn = inlineCallbacks(_noReturn) | |
261 | |
262 return _noReturn().addCallback(self.assertEqual, None) | |
263 | |
264 def testReturnValue(self): | |
265 """Ensure that returnValue works.""" | |
266 def _return(): | |
267 yield 5 | |
268 returnValue(6) | |
269 _return = inlineCallbacks(_return) | |
270 | |
271 return _return().addCallback(self.assertEqual, 6) | |
272 | |
273 ''' | |
274 | |
275 if sys.version_info > (2, 5): | |
276 # Load tests | |
277 exec inlineCallbacksTestsSource | |
278 else: | |
279 # Make a placeholder test case | |
280 class InlineCallbacksTests(unittest.TestCase): | |
281 skip = "defer.defgen doesn't run on python < 2.5." | |
282 def test_everything(self): | |
283 pass | |
OLD | NEW |