/tests/test_aioh2.py

https://github.com/decentfox/aioh2 · Python · 339 lines · 263 code · 69 blank · 7 comment · 29 complexity · 12adff4f167d35176f367a23e3e3c233 MD5 · raw file

  1. #!/usr/bin/env python
  2. """
  3. test_aioh2
  4. ----------------------------------
  5. Tests for `aioh2` module.
  6. """
  7. import random
  8. import unittest
  9. import uuid
  10. import asyncio
  11. from h2.events import DataReceived
  12. from h2.events import PingAcknowledged
  13. from h2.events import RemoteSettingsChanged
  14. from h2.events import ResponseReceived
  15. from h2.events import SettingsAcknowledged
  16. from h2.exceptions import FlowControlError
  17. from h2.settings import SettingCodes
  18. from aioh2 import SendException
  19. from aioh2.helper import async_task
  20. from . import async_test, BaseTestCase
  21. class TestServer(BaseTestCase):
  22. def test_connect(self):
  23. pass
  24. @async_test
  25. def test_ping(self):
  26. opaque_data = uuid.uuid4().bytes[:8]
  27. self.conn.ping(opaque_data)
  28. events = yield from self._expect_events()
  29. self.assertIsInstance(events[0], PingAcknowledged)
  30. self.assertEqual(events[0].ping_data, opaque_data)
  31. @async_test
  32. def test_request_headers(self):
  33. yield from self._send_headers()
  34. @asyncio.coroutine
  35. def _test_read_frame(self, *, more, end_stream):
  36. stream_id = yield from self._send_headers()
  37. data = b'x' * random.randint(128, 512)
  38. self.conn.send_data(stream_id, data,
  39. end_stream=not more and end_stream)
  40. extra = b''
  41. if more:
  42. extra = b'y' * random.randint(128, 512)
  43. self.conn.send_data(stream_id, extra, end_stream=end_stream)
  44. yield from self._expect_connection_flow_control_disabled()
  45. yield from self._assert_received(
  46. stream_id, self.server.read_stream(stream_id), data)
  47. if more:
  48. yield from self._assert_received(
  49. stream_id, self.server.read_stream(stream_id), extra)
  50. if end_stream:
  51. frame = yield from self.server.read_stream(stream_id)
  52. self.assertEqual(frame, b'')
  53. else:
  54. try:
  55. yield from asyncio.wait_for(
  56. self.server.read_stream(stream_id), 0.1)
  57. except asyncio.TimeoutError:
  58. pass
  59. else:
  60. self.assertRaises(asyncio.TimeoutError, lambda: None)
  61. @async_test
  62. def test_read_frame(self):
  63. yield from self._test_read_frame(more=True, end_stream=False)
  64. @async_test
  65. def test_read_frame_close(self):
  66. yield from self._test_read_frame(more=True, end_stream=True)
  67. @async_test
  68. def test_read_only_frame(self):
  69. yield from self._test_read_frame(more=False, end_stream=False)
  70. @async_test
  71. def test_read_only_frame_close(self):
  72. yield from self._test_read_frame(more=False, end_stream=True)
  73. @asyncio.coroutine
  74. def _test_read_all(self, *, more, end_stream):
  75. stream_id = yield from self._send_headers()
  76. data = b'x' * random.randint(128, 512)
  77. self.conn.send_data(stream_id, data,
  78. end_stream=not more and end_stream)
  79. if more:
  80. extra = b'y' * random.randint(128, 512)
  81. self.conn.send_data(stream_id, extra, end_stream=end_stream)
  82. data += extra
  83. yield from self._expect_connection_flow_control_disabled()
  84. if end_stream:
  85. yield from self._assert_received(
  86. stream_id, self.server.read_stream(stream_id, -1), data)
  87. frame = yield from self.server.read_stream(stream_id, -1)
  88. self.assertEqual(frame, b'')
  89. else:
  90. try:
  91. yield from asyncio.wait_for(
  92. self.server.read_stream(stream_id, -1), 0.1)
  93. except asyncio.TimeoutError:
  94. pass
  95. else:
  96. self.assertRaises(asyncio.TimeoutError, lambda: None)
  97. @async_test
  98. def test_read_all(self):
  99. yield from self._test_read_all(more=True, end_stream=False)
  100. @async_test
  101. def test_read_all_close(self):
  102. yield from self._test_read_all(more=True, end_stream=True)
  103. @async_test
  104. def test_read_all_only_frame(self):
  105. yield from self._test_read_all(more=False, end_stream=False)
  106. @async_test
  107. def test_read_all_only_frame_close(self):
  108. yield from self._test_read_all(more=False, end_stream=True)
  109. @asyncio.coroutine
  110. def _test_read_exactly(self, *, empty, explicit_close):
  111. stream_id = yield from self._send_headers()
  112. self.conn.send_data(stream_id, b'333')
  113. self.conn.send_data(stream_id, b'55555')
  114. if empty:
  115. self.conn.send_data(stream_id, b'')
  116. yield from self._expect_connection_flow_control_disabled()
  117. yield from self._assert_received(
  118. stream_id, self.server.read_stream(stream_id, 2), b'33')
  119. self.conn.send_data(stream_id, b'88888888',
  120. end_stream=not explicit_close)
  121. if explicit_close:
  122. self.conn.end_stream(stream_id)
  123. yield from self._expect_events(0)
  124. yield from self._assert_received(
  125. stream_id, self.server.read_stream(stream_id, 8), b'35555588')
  126. yield from self._assert_received(
  127. stream_id, self.server.read_stream(stream_id, 2), b'88')
  128. yield from self._assert_received(
  129. stream_id, self.server.read_stream(stream_id, 8), b'8888')
  130. @async_test
  131. def test_read_exactly(self):
  132. yield from self._test_read_exactly(empty=False, explicit_close=False)
  133. @async_test
  134. def test_read_exactly_empty_frame(self):
  135. yield from self._test_read_exactly(empty=True, explicit_close=False)
  136. @async_test
  137. def test_read_exactly_explicit_close(self):
  138. yield from self._test_read_exactly(empty=True, explicit_close=True)
  139. @async_test
  140. def test_read_exactly_empty_frame_explicit_close(self):
  141. yield from self._test_read_exactly(empty=True, explicit_close=True)
  142. @async_test
  143. def test_flow_control_settings(self):
  144. self.server.update_settings({SettingCodes.INITIAL_WINDOW_SIZE: 3})
  145. event = yield from self._expect_events()
  146. self.assertIsInstance(event[0], RemoteSettingsChanged)
  147. event = yield from self.server.events.get()
  148. self.assertIsInstance(event, SettingsAcknowledged)
  149. stream_id = yield from self._send_headers()
  150. self.conn.send_data(stream_id, b'xx')
  151. yield from self._expect_connection_flow_control_disabled()
  152. yield from self._assert_received(
  153. stream_id, self.server.read_stream(stream_id, 2), b'xx')
  154. self.conn.send_data(stream_id, b'xxx')
  155. yield from self._expect_events(0)
  156. yield from self._assert_received(
  157. stream_id, self.server.read_stream(stream_id, 3), b'xxx')
  158. self.assertRaises(FlowControlError,
  159. self.conn.send_data, stream_id, b'xxxx')
  160. @async_test
  161. def test_flow_control(self):
  162. self.conn.update_settings({SettingCodes.INITIAL_WINDOW_SIZE: 3})
  163. event = yield from self._expect_events()
  164. self.assertIsInstance(event[0], SettingsAcknowledged)
  165. event = yield from self.server.events.get()
  166. self.assertIsInstance(event, RemoteSettingsChanged)
  167. stream_id = yield from self._send_headers(end_stream=True)
  168. yield from self.server.start_response(stream_id, [(':status', '200')])
  169. events = yield from self._expect_events()
  170. self.assertIsInstance(events[0], ResponseReceived)
  171. yield from self.server.send_data(stream_id, b'12')
  172. events = yield from self._expect_events()
  173. self.assertIsInstance(events[0], DataReceived)
  174. self.assertEqual(events[0].data, b'12')
  175. try:
  176. yield from asyncio.wait_for(
  177. self.server.send_data(stream_id, b'34'), 0.1)
  178. except asyncio.TimeoutError:
  179. events = yield from self._expect_events()
  180. self.assertIsInstance(events[0], DataReceived)
  181. self.assertEqual(events[0].data, b'3')
  182. else:
  183. self.assertRaises(asyncio.TimeoutError, lambda: None)
  184. self.conn.increment_flow_control_window(3, stream_id=stream_id)
  185. yield from self._expect_events(0)
  186. try:
  187. yield from asyncio.wait_for(
  188. self.server.send_data(stream_id, b'5678'), 0.1)
  189. except asyncio.TimeoutError:
  190. events = yield from self._expect_events()
  191. self.assertIsInstance(events[0], DataReceived)
  192. self.assertEqual(events[0].data, b'567')
  193. else:
  194. self.assertRaises(asyncio.TimeoutError, lambda: None)
  195. @async_test
  196. def test_broken_send(self):
  197. self.conn.update_settings({SettingCodes.INITIAL_WINDOW_SIZE: 3})
  198. event = yield from self._expect_events()
  199. self.assertIsInstance(event[0], SettingsAcknowledged)
  200. event = yield from self.server.events.get()
  201. self.assertIsInstance(event, RemoteSettingsChanged)
  202. stream_id = yield from self._send_headers(end_stream=True)
  203. yield from self.server.start_response(stream_id, [(':status', '200')])
  204. events = yield from self._expect_events()
  205. self.assertIsInstance(events[0], ResponseReceived)
  206. yield from self.server.send_data(stream_id, b'12')
  207. events = yield from self._expect_events()
  208. self.assertIsInstance(events[0], DataReceived)
  209. self.assertEqual(events[0].data, b'12')
  210. f = async_task(self.server.send_data(stream_id, b'345678'))
  211. events = yield from self._expect_events()
  212. self.assertIsInstance(events[0], DataReceived)
  213. self.assertEqual(events[0].data, b'3')
  214. self.conn.reset_stream(stream_id)
  215. yield from self._expect_events(0)
  216. try:
  217. yield from f
  218. except SendException as e:
  219. self.assertEqual(e.data, b'45678')
  220. else:
  221. self.assertRaises(SendException, lambda: None)
  222. @unittest.skip("flakey - https://github.com/decentfox/aioh2/issues/17")
  223. @async_test(timeout=8)
  224. def test_priority(self):
  225. self.conn.update_settings({
  226. SettingCodes.MAX_FRAME_SIZE: 16384,
  227. SettingCodes.INITIAL_WINDOW_SIZE: 16384 * 1024 * 32,
  228. })
  229. event = yield from self._expect_events()
  230. self.assertIsInstance(event[0], SettingsAcknowledged)
  231. event = yield from self.server.events.get()
  232. self.assertIsInstance(event, RemoteSettingsChanged)
  233. stream_1 = yield from self._send_headers()
  234. yield from self.server.start_response(stream_1, [(':status', '200')])
  235. events = yield from self._expect_events()
  236. self.assertIsInstance(events[0], ResponseReceived)
  237. stream_2 = yield from self._send_headers()
  238. yield from self.server.start_response(stream_2, [(':status', '200')])
  239. events = yield from self._expect_events()
  240. self.assertIsInstance(events[0], ResponseReceived)
  241. p1 = 32
  242. p2 = 20
  243. self.server.reprioritize(stream_1, weight=p1)
  244. self.server.reprioritize(stream_2, weight=p2)
  245. self.server.pause_writing()
  246. running = [True]
  247. @asyncio.coroutine
  248. def _write(stream_id):
  249. count = 0
  250. while running[0]:
  251. yield from self.server.send_data(stream_id, b'x')
  252. count += 1
  253. yield from self.server.end_stream(stream_id)
  254. return count
  255. task_1 = async_task(_write(stream_1))
  256. task_2 = async_task(_write(stream_2))
  257. for i in range(1000):
  258. self.server.resume_writing()
  259. yield from asyncio.sleep(0.004)
  260. self.server.pause_writing()
  261. yield from asyncio.sleep(0.001)
  262. running[0] = False
  263. self.server.resume_writing()
  264. count_1 = yield from task_1
  265. count_2 = yield from task_2
  266. self.assertAlmostEqual(count_1 / count_2, p1 / p2, 1)
  267. if __name__ == '__main__':
  268. import sys
  269. sys.exit(unittest.main())