PageRenderTime 86ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/desktop/core/ext-py/Twisted/twisted/flow/test/test_flow.py

https://github.com/jcrobak/hue
Python | 491 lines | 441 code | 4 blank | 46 comment | 1 complexity | 55cf4b947b9a11dba82da29f213e2273 MD5 | raw file
  1. # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. #
  4. # Author: Clark C. Evans
  5. #
  6. from __future__ import nested_scopes
  7. from __future__ import generators
  8. from twisted.flow import flow
  9. from twisted.flow.threads import Threaded, QueryIterator
  10. from twisted.trial import unittest
  11. from twisted.python import failure
  12. from twisted.internet import defer, reactor, protocol, interfaces
  13. from time import sleep
  14. class slowlist:
  15. """ this is a generator based list
  16. def slowlist(list):
  17. list = list[:]
  18. while list:
  19. yield list.pop(0)
  20. It is primarly used to simulate generators by using
  21. a list (for testing purposes) without being wrapped
  22. as a flow.List, which has all kinds of shortcuts we
  23. don't want for testing.
  24. """
  25. def __init__(self, list):
  26. self.list = list[:]
  27. def __iter__(self):
  28. return self
  29. def next(self):
  30. if self.list:
  31. return self.list.pop(0)
  32. raise StopIteration
  33. _onetwothree = ['one','two',flow.Cooperate(),'three']
  34. class producer:
  35. """ iterator version of the following generator...
  36. def producer():
  37. lst = flow.wrap(slowlist([1,2,3]))
  38. nam = flow.wrap(slowlist(_onetwothree))
  39. while True:
  40. yield lst
  41. yield nam
  42. yield (lst.next(),nam.next())
  43. """
  44. def __iter__(self):
  45. self.lst = flow.wrap(slowlist([1,2,3]))
  46. self.nam = flow.wrap(slowlist(_onetwothree))
  47. self.next = self.yield_lst
  48. return self
  49. def yield_lst(self):
  50. self.next = self.yield_nam
  51. return self.lst
  52. def yield_nam(self):
  53. self.next = self.yield_results
  54. return self.nam
  55. def yield_results(self):
  56. self.next = self.yield_lst
  57. return (self.lst.next(), self.nam.next())
  58. class consumer:
  59. """ iterator version of the following generator...
  60. def consumer():
  61. title = flow.wrap(['Title'])
  62. prod = flow.wrap(producer())
  63. yield title
  64. yield title.next()
  65. yield prod
  66. for data in prod:
  67. yield data
  68. yield prod
  69. """
  70. def __iter__(self):
  71. self.title = flow.wrap(['Title'])
  72. self.lst = flow.wrap(producer())
  73. self.next = self.yield_title
  74. return self
  75. def yield_title(self):
  76. self.next = self.yield_title_result
  77. return self.title
  78. def yield_title_result(self):
  79. self.next = self.yield_lst
  80. return self.title.next()
  81. def yield_lst(self):
  82. self.next = self.yield_result
  83. return self.lst
  84. def yield_result(self):
  85. self.next = self.yield_lst
  86. return self.lst.next()
  87. class badgen:
  88. """ a bad generator...
  89. def badgen():
  90. yield 'x'
  91. err = 3/ 0
  92. """
  93. def __iter__(self):
  94. self.next = self.yield_x
  95. return self
  96. def yield_x(self):
  97. self.next = self.yield_done
  98. return 'x'
  99. def yield_done(self):
  100. err = 3 / 0
  101. raise StopIteration
  102. class buildlist:
  103. """ building a list
  104. def buildlist(src):
  105. out = []
  106. yield src
  107. for itm in src:
  108. out.append(itm)
  109. yield src
  110. yield out
  111. """
  112. def __init__(self, src):
  113. self.src = src
  114. def __iter__(self):
  115. self.out = []
  116. self.next = self.yield_src
  117. return self
  118. def yield_src(self):
  119. self.next = self.yield_append
  120. return self.src
  121. def yield_append(self):
  122. try:
  123. self.out.append(self.src.next())
  124. except StopIteration:
  125. self.next = self.yield_finish
  126. return self.out
  127. return self.src
  128. def yield_finish(self):
  129. raise StopIteration
  130. class testconcur:
  131. """ interweving two concurrent stages
  132. def testconcur(*stages):
  133. both = flow.Concurrent(*stages)
  134. yield both
  135. for stage in both:
  136. yield (stage.name, stage.result)
  137. yield both
  138. """
  139. def __init__(self, *stages):
  140. self.both = flow.Concurrent(*stages)
  141. def __iter__(self):
  142. self.next = self.yield_both
  143. return self
  144. def yield_both(self):
  145. self.next = self.yield_result
  146. return self.both
  147. def yield_result(self):
  148. self.next = self.yield_both
  149. stage = self.both.next()
  150. return (stage.name, stage.next())
  151. class echoServer:
  152. """ a simple echo protocol, server side
  153. def echoServer(conn):
  154. yield conn
  155. for data in conn:
  156. yield data
  157. yield conn
  158. """
  159. def __init__(self, conn):
  160. self.conn = conn
  161. def __iter__(self):
  162. self.next = self.yield_conn
  163. return self
  164. def yield_conn(self):
  165. self.next = self.yield_data
  166. return self.conn
  167. def yield_data(self):
  168. self.next = self.yield_conn
  169. return self.conn.next()
  170. class echoClient:
  171. """ a simple echo client tester
  172. def echoClient(conn):
  173. yield "testing"
  174. yield conn
  175. # signal that we are done
  176. conn.d.callback(conn.next())
  177. """
  178. def __init__(self, conn):
  179. self.conn = conn
  180. def __iter__(self):
  181. self.next = self.yield_testing
  182. return self
  183. def yield_testing(self):
  184. self.next = self.yield_conn
  185. return "testing"
  186. def yield_conn(self):
  187. self.next = self.yield_stop
  188. return self.conn
  189. def yield_stop(self):
  190. # signal that we are done
  191. self.conn.factory.d.callback(self.conn.next())
  192. raise StopIteration()
  193. class CountIterator:
  194. def __init__(self, count):
  195. self.count = count
  196. def __iter__(self):
  197. return self
  198. def next(self): # this is run in a separate thread
  199. sleep(.1)
  200. val = self.count
  201. if not(val):
  202. raise StopIteration
  203. self.count -= 1
  204. return val
  205. class FlowTest(unittest.TestCase):
  206. def testNotReady(self):
  207. x = flow.wrap([1,2,3])
  208. self.assertRaises(flow.NotReadyError,x.next)
  209. def testBasic(self):
  210. lhs = ['string']
  211. rhs = list(flow.Block('string'))
  212. self.assertEqual(lhs,rhs)
  213. def testBasicList(self):
  214. lhs = [1,2,3]
  215. rhs = list(flow.Block([1,2,flow.Cooperate(),3]))
  216. self.assertEqual(lhs,rhs)
  217. def testBasicIterator(self):
  218. lhs = ['one','two','three']
  219. rhs = list(flow.Block(slowlist(_onetwothree)))
  220. self.assertEqual(lhs,rhs)
  221. def testCallable(self):
  222. lhs = ['one','two','three']
  223. rhs = list(flow.Block(slowlist(_onetwothree)))
  224. self.assertEqual(lhs,rhs)
  225. def testProducer(self):
  226. lhs = [(1,'one'),(2,'two'),(3,'three')]
  227. rhs = list(flow.Block(producer()))
  228. self.assertEqual(lhs,rhs)
  229. def testConsumer(self):
  230. lhs = ['Title',(1,'one'),(2,'two'),(3,'three')]
  231. rhs = list(flow.Block(consumer))
  232. self.assertEqual(lhs,rhs)
  233. def testFailure(self):
  234. self.assertRaises(ZeroDivisionError, list, flow.Block(badgen()))
  235. self.assertEqual(['x',ZeroDivisionError],
  236. list(flow.Block(badgen(),ZeroDivisionError)))
  237. self.assertEqual(['x',ZeroDivisionError],
  238. list(flow.Block(flow.wrap(badgen()),
  239. ZeroDivisionError)))
  240. def testZip(self):
  241. lhs = [(1,'a'),(2,'b'),(3,None)]
  242. mrg = flow.Zip([1,2,flow.Cooperate(),3],['a','b'])
  243. rhs = list(flow.Block(mrg))
  244. self.assertEqual(lhs,rhs)
  245. def testMerge(self):
  246. lhs = ['one', 1, 'two', 2, 3, 'three']
  247. mrg = flow.Merge(slowlist(_onetwothree),slowlist([1,2,3]))
  248. rhs = list(flow.Block(mrg))
  249. self.assertEqual(lhs,rhs)
  250. def testFilter(self):
  251. def odd(val):
  252. if val % 2:
  253. return True
  254. lhs = [ 1, 3 ]
  255. mrg = flow.Filter(odd,slowlist([1,2,flow.Cooperate(),3]))
  256. rhs = list(flow.Block(mrg))
  257. self.assertEqual(lhs,rhs)
  258. def testLineBreak(self):
  259. lhs = [ "Hello World", "Happy Days Are Here" ]
  260. rhs = ["Hello ","World\nHappy", flow.Cooperate(),
  261. " Days"," Are Here\n"]
  262. mrg = flow.LineBreak(slowlist(rhs), delimiter='\n')
  263. rhs = list(flow.Block(mrg))
  264. self.assertEqual(lhs,rhs)
  265. def testDeferred(self):
  266. lhs = ['Title', (1,'one'),(2,'two'),(3,'three')]
  267. d = flow.Deferred(consumer())
  268. d.addCallback(self.assertEquals, lhs)
  269. return d
  270. def testBuildList(self):
  271. src = flow.wrap([1,2,3])
  272. out = flow.Block(buildlist(src)).next()
  273. self.assertEquals(out,[1,2,3])
  274. def testDeferredFailure(self):
  275. d = flow.Deferred(badgen())
  276. return self.assertFailure(d, ZeroDivisionError)
  277. def testDeferredTrap(self):
  278. d = flow.Deferred(badgen(), ZeroDivisionError)
  279. d.addCallback(self.assertEqual, ['x', ZeroDivisionError])
  280. return d
  281. def testZipFailure(self):
  282. lhs = [(1,'a'),(2,'b'),(3,'c')]
  283. mrg = flow.Zip([1,2,flow.Cooperate(),3],badgen())
  284. d = flow.Deferred(mrg)
  285. return self.assertFailure(d, ZeroDivisionError)
  286. def testDeferredWrapper(self):
  287. a = defer.Deferred()
  288. reactor.callLater(0, lambda: a.callback("test"))
  289. b = flow.Merge(a, slowlist([1,2,flow.Cooperate(),3]))
  290. d = flow.Deferred(b)
  291. d.addCallback(self.assertEqual, [1, 2, 'test', 3])
  292. return d
  293. def testDeferredWrapperImmediate(self):
  294. from twisted.internet import defer
  295. a = defer.Deferred()
  296. a.callback("test")
  297. self.assertEquals(["test"], list(flow.Block(a)))
  298. def testDeferredWrapperFail(self):
  299. d = defer.Deferred()
  300. f = lambda: d.errback(flow.Failure(IOError()))
  301. reactor.callLater(0, f)
  302. return self.assertFailure(d, IOError)
  303. def testCallback(self):
  304. cb = flow.Callback()
  305. d = flow.Deferred(buildlist(cb))
  306. for x in range(9):
  307. cb.result(x)
  308. cb.finish()
  309. d.addCallback(self.assertEqual, [range(9)])
  310. return d
  311. def testCallbackFailure(self):
  312. cb = flow.Callback()
  313. d = flow.Deferred(buildlist(cb))
  314. for x in range(3):
  315. cb.result(x)
  316. cb.errback(flow.Failure(IOError()))
  317. return self.assertFailure(d, IOError)
  318. def testConcurrentCallback(self):
  319. ca = flow.Callback()
  320. ca.name = 'a'
  321. cb = flow.Callback()
  322. cb.name = 'b'
  323. d = flow.Deferred(testconcur(ca,cb))
  324. ca.result(1)
  325. cb.result(2)
  326. ca.result(3)
  327. ca.result(4)
  328. ca.finish()
  329. cb.result(5)
  330. cb.finish()
  331. d.addCallback(self.assertEquals,
  332. [('a',1),('b',2),('a',3),('a',4),('b',5)])
  333. return d
  334. def testProtocolLocalhost(self):
  335. # this fails if parallel tests are run on the same box
  336. server = protocol.ServerFactory()
  337. server.protocol = flow.Protocol
  338. server.protocol.controller = echoServer
  339. port = reactor.listenTCP(0, server)
  340. client = protocol.ClientFactory()
  341. client.protocol = flow.makeProtocol(echoClient)
  342. client.d = defer.Deferred()
  343. reactor.connectTCP("127.0.0.1", port.getHost().port, client)
  344. client.d.addCallback(self.assertEquals, 'testing')
  345. client.d.addBoth(lambda x :
  346. client.protocol.transport.loseConnection())
  347. client.d.addBoth(lambda x :
  348. defer.maybeDeferred(port.stopListening))
  349. return client.d
  350. #testProtocolLocalhost.skip = "XXX freezes, fixme"
  351. def testProtocol(self):
  352. from twisted.protocols import loopback
  353. server = flow.Protocol()
  354. server.controller = echoServer
  355. client = flow.makeProtocol(echoClient)()
  356. client.factory = protocol.ClientFactory()
  357. client.factory.d = defer.Deferred()
  358. d2 = loopback.loopbackAsync(server, client)
  359. client.factory.d.addCallback(self.assertEquals, 'testing')
  360. return defer.gatherResults([client.factory.d, d2])
  361. class ThreadedFlowTest(unittest.TestCase):
  362. if interfaces.IReactorThreads(reactor, None) is None:
  363. skip = ("No thread support in reactor, "
  364. "cannot test threaded flow constructs.")
  365. def testThreaded(self):
  366. expect = [5,4,3,2,1]
  367. d = flow.Deferred(Threaded(CountIterator(5)))
  368. d.addCallback(self.assertEquals, expect)
  369. return d
  370. def testThreadedError(self):
  371. # is this the expected behaviour?
  372. def iterator():
  373. yield 1
  374. raise ValueError
  375. d = flow.Deferred(Threaded(iterator()))
  376. return self.assertFailure(d, ValueError)
  377. def testThreadedSleep(self):
  378. expect = [5,4,3,2,1]
  379. d = flow.Deferred(Threaded(CountIterator(5)))
  380. sleep(.5)
  381. d.addCallback(self.assertEquals, expect)
  382. return d
  383. def testQueryIterator(self):
  384. try:
  385. from pyPgSQL import PgSQL
  386. dbpool = PgSQL
  387. c = dbpool.connect()
  388. r = c.cursor()
  389. r.execute("SELECT 'x'")
  390. r.fetchone()
  391. except:
  392. # PostgreSQL is not installed or bad permissions
  393. return
  394. expect = [['one'],['two'],['three']]
  395. sql = """
  396. (SELECT 'one')
  397. UNION ALL
  398. (SELECT 'two')
  399. UNION ALL
  400. (SELECT 'three')
  401. """
  402. d = flow.Deferred(Threaded(QueryIterator(dbpool, sql)))
  403. d.addCallback(self.assertEquals, expect)
  404. return d
  405. def testThreadedImmediate(self):
  406. """
  407. The goal of this test is to test the callback mechanism with
  408. regard to threads, namely to assure that results can be
  409. accumulated before they are needed; and that left-over results
  410. are immediately made available on the next round (even though
  411. the producing thread has shut down). This is a very tough thing
  412. to test due to the timing issues. So it may fail on some
  413. platforms, I'm not sure.
  414. """
  415. expect = [5,4,3,2,1]
  416. result = []
  417. f = Threaded(CountIterator(5))
  418. d = defer.Deferred()
  419. def process():
  420. coop = f._yield()
  421. if f.results:
  422. result.extend(f.results)
  423. del f.results[:len(result)]
  424. reactor.callLater(0, process)
  425. return
  426. if coop:
  427. sleep(.3)
  428. reactor.callLater(0, coop.callLater, process)
  429. return
  430. if f.stop:
  431. reactor.callLater(0, d.callback, result)
  432. reactor.callLater(0, process)
  433. d.addCallback(self.assertEquals, expect)
  434. return d