test_aiohttp.py 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. # coding: utf-8
  2. from aiohttp import web
  3. import marshmallow
  4. from hapic import Hapic
  5. from hapic import HapicData
  6. from hapic.ext.aiohttp.context import AiohttpContext
  7. class TestAiohttpExt(object):
  8. async def test_aiohttp_only__ok__nominal_case(
  9. self,
  10. aiohttp_client,
  11. loop,
  12. ):
  13. async def hello(request):
  14. return web.Response(text='Hello, world')
  15. app = web.Application(debug=True)
  16. app.router.add_get('/', hello)
  17. client = await aiohttp_client(app)
  18. resp = await client.get('/')
  19. assert resp.status == 200
  20. text = await resp.text()
  21. assert 'Hello, world' in text
  22. async def test_aiohttp_input_path__ok__nominal_case(
  23. self,
  24. aiohttp_client,
  25. loop,
  26. ):
  27. hapic = Hapic(async_=True)
  28. class InputPathSchema(marshmallow.Schema):
  29. name = marshmallow.fields.String()
  30. @hapic.input_path(InputPathSchema())
  31. async def hello(request, hapic_data: HapicData):
  32. name = hapic_data.path.get('name')
  33. return web.Response(text='Hello, {}'.format(name))
  34. app = web.Application(debug=True)
  35. app.router.add_get('/{name}', hello)
  36. hapic.set_context(AiohttpContext(app))
  37. client = await aiohttp_client(app)
  38. resp = await client.get('/bob')
  39. assert resp.status == 200
  40. text = await resp.text()
  41. assert 'Hello, bob' in text
  42. async def test_aiohttp_input_path__error_wrong_input_parameter(
  43. self,
  44. aiohttp_client,
  45. loop,
  46. ):
  47. hapic = Hapic(async_=True)
  48. class InputPathSchema(marshmallow.Schema):
  49. i = marshmallow.fields.Integer()
  50. @hapic.input_path(InputPathSchema())
  51. async def hello(request, hapic_data: HapicData):
  52. i = hapic_data.path.get('i')
  53. return web.Response(text='integer: {}'.format(str(i)))
  54. app = web.Application(debug=True)
  55. app.router.add_get('/{i}', hello)
  56. hapic.set_context(AiohttpContext(app))
  57. client = await aiohttp_client(app)
  58. resp = await client.get('/bob') # NOTE: should be integer here
  59. assert resp.status == 400
  60. error = await resp.json()
  61. assert 'Validation error of input data' in error.get('message')
  62. assert {'i': ['Not a valid integer.']} == error.get('details')
  63. async def test_aiohttp_input_body__ok_nominal_case(
  64. self,
  65. aiohttp_client,
  66. loop,
  67. ):
  68. hapic = Hapic(async_=True)
  69. class InputBodySchema(marshmallow.Schema):
  70. name = marshmallow.fields.String()
  71. @hapic.input_body(InputBodySchema())
  72. async def hello(request, hapic_data: HapicData):
  73. name = hapic_data.body.get('name')
  74. return web.Response(text='Hello, {}'.format(name))
  75. app = web.Application(debug=True)
  76. app.router.add_post('/', hello)
  77. hapic.set_context(AiohttpContext(app))
  78. client = await aiohttp_client(app)
  79. resp = await client.post('/', data={'name': 'bob'})
  80. assert resp.status == 200
  81. text = await resp.text()
  82. assert 'Hello, bob' in text
  83. async def test_aiohttp_input_body__error__incorrect_input_body(
  84. self,
  85. aiohttp_client,
  86. loop,
  87. ):
  88. hapic = Hapic(async_=True)
  89. class InputBodySchema(marshmallow.Schema):
  90. i = marshmallow.fields.Integer()
  91. @hapic.input_body(InputBodySchema())
  92. async def hello(request, hapic_data: HapicData):
  93. i = hapic_data.body.get('i')
  94. return web.Response(text='integer, {}'.format(i))
  95. app = web.Application(debug=True)
  96. app.router.add_post('/', hello)
  97. hapic.set_context(AiohttpContext(app))
  98. client = await aiohttp_client(app)
  99. resp = await client.post('/', data={'i': 'bob'}) # NOTE: should be int
  100. assert resp.status == 400
  101. error = await resp.json()
  102. assert 'Validation error of input data' in error.get('message')
  103. assert {'i': ['Not a valid integer.']} == error.get('details')
  104. async def test_aiohttp_output_body__ok__nominal_case(
  105. self,
  106. aiohttp_client,
  107. loop,
  108. ):
  109. hapic = Hapic(async_=True)
  110. class OuputBodySchema(marshmallow.Schema):
  111. name = marshmallow.fields.String()
  112. @hapic.output_body(OuputBodySchema())
  113. async def hello(request):
  114. return {
  115. 'name': 'bob',
  116. }
  117. app = web.Application(debug=True)
  118. app.router.add_get('/', hello)
  119. hapic.set_context(AiohttpContext(app))
  120. client = await aiohttp_client(app)
  121. resp = await client.get('/')
  122. assert resp.status == 200
  123. data = await resp.json()
  124. assert 'bob' == data.get('name')
  125. async def test_aiohttp_output_body__error__incorrect_output_body(
  126. self,
  127. aiohttp_client,
  128. loop,
  129. ):
  130. hapic = Hapic(async_=True)
  131. class OuputBodySchema(marshmallow.Schema):
  132. i = marshmallow.fields.Integer(required=True)
  133. @hapic.output_body(OuputBodySchema())
  134. async def hello(request):
  135. return {
  136. 'i': 'bob', # NOTE: should be integer
  137. }
  138. app = web.Application(debug=True)
  139. app.router.add_get('/', hello)
  140. hapic.set_context(AiohttpContext(app))
  141. client = await aiohttp_client(app)
  142. resp = await client.get('/')
  143. assert resp.status == 500
  144. data = await resp.json()
  145. assert 'Validation error of output data' == data.get('message')
  146. assert {
  147. 'i': ['Missing data for required field.'],
  148. } == data.get('details')
  149. async def test_aiohttp_output_stream__ok__nominal_case(
  150. self,
  151. aiohttp_client,
  152. loop,
  153. ):
  154. hapic = Hapic(async_=True)
  155. class AsyncGenerator:
  156. def __init__(self):
  157. self._iterator = iter([
  158. {'name': 'Hello, bob'},
  159. {'name': 'Hello, franck'},
  160. ])
  161. async def __aiter__(self):
  162. return self
  163. async def __anext__(self):
  164. return next(self._iterator)
  165. class OuputStreamItemSchema(marshmallow.Schema):
  166. name = marshmallow.fields.String()
  167. @hapic.output_stream(OuputStreamItemSchema())
  168. async def hello(request):
  169. return AsyncGenerator()
  170. app = web.Application(debug=True)
  171. app.router.add_get('/', hello)
  172. hapic.set_context(AiohttpContext(app))
  173. client = await aiohttp_client(app)
  174. resp = await client.get('/')
  175. assert resp.status == 200
  176. line = await resp.content.readline()
  177. assert b'{"name": "Hello, bob"}\n' == line
  178. line = await resp.content.readline()
  179. assert b'{"name": "Hello, franck"}\n' == line
  180. # TODO BS 2018-07-26: How to ensure we are at end of response ?