| 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 |