test_doc.py 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. # coding: utf-8
  2. import marshmallow
  3. import bottle
  4. from marshmallow.validate import OneOf
  5. from hapic import Hapic
  6. from tests.base import Base
  7. from tests.base import MyContext
  8. class TestDocGeneration(Base):
  9. def test_func__input_files_doc__ok__one_file(self):
  10. hapic = Hapic()
  11. # TODO BS 20171113: Make this test non-bottle
  12. app = bottle.Bottle()
  13. hapic.set_context(MyContext(app=app))
  14. class MySchema(marshmallow.Schema):
  15. file_abc = marshmallow.fields.Raw(required=True)
  16. @hapic.with_api_doc()
  17. @hapic.input_files(MySchema())
  18. def my_controller(hapic_data=None):
  19. assert hapic_data
  20. assert hapic_data.files
  21. app.route('/upload', method='POST', callback=my_controller)
  22. doc = hapic.generate_doc()
  23. assert doc
  24. assert '/upload' in doc['paths']
  25. assert 'consumes' in doc['paths']['/upload']['post']
  26. assert 'multipart/form-data' in doc['paths']['/upload']['post']['consumes'] # nopep8
  27. assert 'parameters' in doc['paths']['/upload']['post']
  28. assert {
  29. 'name': 'file_abc',
  30. 'required': True,
  31. 'in': 'formData',
  32. 'type': 'file',
  33. } in doc['paths']['/upload']['post']['parameters']
  34. def test_func__input_files_doc__ok__two_file(self):
  35. hapic = Hapic()
  36. # TODO BS 20171113: Make this test non-bottle
  37. app = bottle.Bottle()
  38. hapic.set_context(MyContext(app=app))
  39. class MySchema(marshmallow.Schema):
  40. file_abc = marshmallow.fields.Raw(required=True)
  41. file_def = marshmallow.fields.Raw(required=False)
  42. @hapic.with_api_doc()
  43. @hapic.input_files(MySchema())
  44. def my_controller(hapic_data=None):
  45. assert hapic_data
  46. assert hapic_data.files
  47. app.route('/upload', method='POST', callback=my_controller)
  48. doc = hapic.generate_doc()
  49. assert doc
  50. assert '/upload' in doc['paths']
  51. assert 'consumes' in doc['paths']['/upload']['post']
  52. assert 'multipart/form-data' in doc['paths']['/upload']['post']['consumes'] # nopep8
  53. assert 'parameters' in doc['paths']['/upload']['post']
  54. assert {
  55. 'name': 'file_abc',
  56. 'required': True,
  57. 'in': 'formData',
  58. 'type': 'file',
  59. } in doc['paths']['/upload']['post']['parameters']
  60. assert {
  61. 'name': 'file_def',
  62. 'required': False,
  63. 'in': 'formData',
  64. 'type': 'file',
  65. } in doc['paths']['/upload']['post']['parameters']
  66. def test_func__output_file_doc__ok__nominal_case(self):
  67. hapic = Hapic()
  68. # TODO BS 20171113: Make this test non-bottle
  69. app = bottle.Bottle()
  70. hapic.set_context(MyContext(app=app))
  71. @hapic.with_api_doc()
  72. @hapic.output_file(['image/jpeg'])
  73. def my_controller():
  74. return b'101010100101'
  75. app.route('/avatar', method='GET', callback=my_controller)
  76. doc = hapic.generate_doc()
  77. assert doc
  78. assert '/avatar' in doc['paths']
  79. assert 'produces' in doc['paths']['/avatar']['get']
  80. assert 'image/jpeg' in doc['paths']['/avatar']['get']['produces']
  81. assert 200 in doc['paths']['/avatar']['get']['responses']
  82. def test_func__input_files_doc__ok__one_file_and_text(self):
  83. hapic = Hapic()
  84. # TODO BS 20171113: Make this test non-bottle
  85. app = bottle.Bottle()
  86. hapic.set_context(MyContext(app=app))
  87. class MySchema(marshmallow.Schema):
  88. name = marshmallow.fields.String(required=True)
  89. class MyFilesSchema(marshmallow.Schema):
  90. file_abc = marshmallow.fields.Raw(required=True)
  91. @hapic.with_api_doc()
  92. @hapic.input_files(MyFilesSchema())
  93. @hapic.input_body(MySchema())
  94. def my_controller(hapic_data=None):
  95. assert hapic_data
  96. assert hapic_data.files
  97. app.route('/upload', method='POST', callback=my_controller)
  98. doc = hapic.generate_doc()
  99. assert doc
  100. assert '/upload' in doc['paths']
  101. assert 'consumes' in doc['paths']['/upload']['post']
  102. assert 'multipart/form-data' in doc['paths']['/upload']['post']['consumes'] # nopep8
  103. assert 'parameters' in doc['paths']['/upload']['post']
  104. assert {
  105. 'name': 'file_abc',
  106. 'required': True,
  107. 'in': 'formData',
  108. 'type': 'file',
  109. } in doc['paths']['/upload']['post']['parameters']
  110. def test_func__docstring__ok__simple_case(self):
  111. hapic = Hapic()
  112. app = bottle.Bottle()
  113. hapic.set_context(MyContext(app=app))
  114. # TODO BS 20171113: Make this test non-bottle
  115. @hapic.with_api_doc()
  116. def my_controller(hapic_data=None):
  117. """
  118. Hello doc
  119. """
  120. assert hapic_data
  121. assert hapic_data.files
  122. app.route('/upload', method='POST', callback=my_controller)
  123. doc = hapic.generate_doc()
  124. assert doc.get('paths')
  125. assert '/upload' in doc['paths']
  126. assert 'post' in doc['paths']['/upload']
  127. assert 'description' in doc['paths']['/upload']['post']
  128. assert 'Hello doc' == doc['paths']['/upload']['post']['description']
  129. def test_func__tags__ok__nominal_case(self):
  130. hapic = Hapic()
  131. app = bottle.Bottle()
  132. hapic.set_context(MyContext(app=app))
  133. @hapic.with_api_doc(tags=['foo', 'bar'])
  134. def my_controller(hapic_data=None):
  135. assert hapic_data
  136. assert hapic_data.files
  137. app.route('/upload', method='POST', callback=my_controller)
  138. doc = hapic.generate_doc()
  139. assert doc.get('paths')
  140. assert '/upload' in doc['paths']
  141. assert 'post' in doc['paths']['/upload']
  142. assert 'tags' in doc['paths']['/upload']['post']
  143. assert ['foo', 'bar'] == doc['paths']['/upload']['post']['tags']
  144. def test_func__errors__nominal_case(self):
  145. hapic = Hapic()
  146. app = bottle.Bottle()
  147. hapic.set_context(MyContext(app=app))
  148. @hapic.with_api_doc()
  149. @hapic.handle_exception()
  150. def my_controller(hapic_data=None):
  151. assert hapic_data
  152. app.route('/upload', method='POST', callback=my_controller)
  153. doc = hapic.generate_doc()
  154. assert doc.get('paths')
  155. assert '/upload' in doc['paths']
  156. assert 'post' in doc['paths']['/upload']
  157. assert 'responses' in doc['paths']['/upload']['post']
  158. assert 500 in doc['paths']['/upload']['post']['responses']
  159. assert {
  160. 'description': "500",
  161. 'schema': {
  162. '$ref': '#/definitions/DefaultErrorBuilder'
  163. }
  164. } == doc['paths']['/upload']['post']['responses'][500]
  165. def test_func__enum__nominal_case(self):
  166. hapic = Hapic()
  167. # TODO BS 20171113: Make this test non-bottle
  168. app = bottle.Bottle()
  169. hapic.set_context(MyContext(app=app))
  170. class MySchema(marshmallow.Schema):
  171. category = marshmallow.fields.String(
  172. validate=OneOf(['foo', 'bar'])
  173. )
  174. @hapic.with_api_doc()
  175. @hapic.input_body(MySchema())
  176. def my_controller():
  177. return
  178. app.route('/paper', method='POST', callback=my_controller)
  179. doc = hapic.generate_doc()
  180. assert ['foo', 'bar'] == doc.get('definitions', {})\
  181. .get('MySchema', {})\
  182. .get('properties', {})\
  183. .get('category', {})\
  184. .get('enum')
  185. def test_func__schema_in_doc__ok__nominal_case(self):
  186. hapic = Hapic()
  187. app = bottle.Bottle()
  188. hapic.set_context(MyContext(app=app))
  189. class MySchema(marshmallow.Schema):
  190. name = marshmallow.fields.String(required=True)
  191. @hapic.with_api_doc()
  192. @hapic.input_body(MySchema())
  193. def my_controller():
  194. return {'name': 'test',}
  195. app.route('/paper', method='POST', callback=my_controller)
  196. doc = hapic.generate_doc()
  197. assert doc.get('definitions', {}).get('MySchema', {})
  198. schema_def = doc.get('definitions', {}).get('MySchema', {})
  199. assert schema_def.get('properties', {}).get('name', {}).get('type')
  200. assert doc.get('paths').get('/paper').get('post').get('parameters')[0]
  201. schema_ref = doc.get('paths').get('/paper').get('post').get('parameters')[0]
  202. assert schema_ref.get('in') == 'body'
  203. assert schema_ref.get('name') == 'body'
  204. assert schema_ref['schema']['$ref'] == '#/definitions/MySchema'
  205. def test_func__schema_in_doc__ok__many_case(self):
  206. hapic = Hapic()
  207. app = bottle.Bottle()
  208. hapic.set_context(MyContext(app=app))
  209. class MySchema(marshmallow.Schema):
  210. name = marshmallow.fields.String(required=True)
  211. @hapic.with_api_doc()
  212. @hapic.input_body(MySchema(many=True))
  213. def my_controller():
  214. return {'name': 'test'}
  215. app.route('/paper', method='POST', callback=my_controller)
  216. doc = hapic.generate_doc()
  217. assert doc.get('definitions', {}).get('MySchema', {})
  218. schema_def = doc.get('definitions', {}).get('MySchema', {})
  219. assert schema_def.get('properties', {}).get('name', {}).get('type')
  220. assert doc.get('paths').get('/paper').get('post').get('parameters')[0]
  221. schema_ref = doc.get('paths').get('/paper').get('post').get('parameters')[0]
  222. assert schema_ref.get('in') == 'body'
  223. assert schema_ref.get('name') == 'body'
  224. assert schema_ref['schema'] == {
  225. 'items': {'$ref': '#/definitions/MySchema'},
  226. 'type': 'array'
  227. }
  228. def test_func__schema_in_doc__ok__exclude_case(self):
  229. hapic = Hapic()
  230. app = bottle.Bottle()
  231. hapic.set_context(MyContext(app=app))
  232. class MySchema(marshmallow.Schema):
  233. name = marshmallow.fields.String(required=True)
  234. name2 = marshmallow.fields.String(required=True)
  235. @hapic.with_api_doc()
  236. @hapic.input_body(MySchema(exclude=('name2',)))
  237. def my_controller():
  238. return {'name': 'test',}
  239. app.route('/paper', method='POST', callback=my_controller)
  240. doc = hapic.generate_doc()
  241. definitions = doc.get('definitions', {})
  242. # TODO - G-M - Find better way to find our new schema
  243. # Do Better test when we were able to set correctly schema name
  244. # according to content
  245. schema_name = None
  246. for elem in definitions.keys():
  247. if elem != 'MySchema':
  248. schema_name = elem
  249. break
  250. assert schema_name
  251. schema_def = definitions[schema_name]
  252. assert schema_def.get('properties', {}).get('name', {}).get('type') == 'string'
  253. assert doc.get('paths').get('/paper').get('post').get('parameters')[0]
  254. schema_ref = doc.get('paths').get('/paper').get('post').get('parameters')[0]
  255. assert schema_ref.get('in') == 'body'
  256. assert schema_ref['schema']['$ref'] == '#/definitions/{}'.format(schema_name)
  257. @hapic.with_api_doc()
  258. @hapic.input_body(MySchema(only=('name',)))
  259. def my_controller():
  260. return {'name': 'test'}
  261. app.route('/paper', method='POST', callback=my_controller)
  262. doc = hapic.generate_doc()
  263. # TODO - G-M - Find better way to find our new schema
  264. # Do Better test when we were able to set correctly schema name
  265. # according to content
  266. definitions = doc.get('definitions', {})
  267. schema_name = None
  268. for elem in definitions.keys():
  269. if elem != 'MySchema':
  270. schema_name = elem
  271. break
  272. assert schema_name
  273. schema_def = definitions[schema_name]
  274. assert schema_def.get('properties', {}).get('name', {}).get('type') == 'string'
  275. assert doc.get('paths').get('/paper').get('post').get('parameters')[0]
  276. schema_ref = doc.get('paths').get('/paper').get('post').get('parameters')[0]
  277. assert schema_ref.get('in') == 'body'
  278. assert schema_ref['schema']['$ref'] == '#/definitions/{}'.format(schema_name)
  279. def test_func__schema_in_doc__ok__many_and_exclude_case(self):
  280. hapic = Hapic()
  281. app = bottle.Bottle()
  282. hapic.set_context(MyContext(app=app))
  283. class MySchema(marshmallow.Schema):
  284. name = marshmallow.fields.String(required=True)
  285. name2 = marshmallow.fields.String(required=True)
  286. @hapic.with_api_doc()
  287. @hapic.input_body(MySchema(exclude=('name2',), many=True))
  288. def my_controller():
  289. return {'name': 'test',}
  290. app.route('/paper', method='POST', callback=my_controller)
  291. doc = hapic.generate_doc()
  292. definitions = doc.get('definitions', {})
  293. # TODO - G-M - Find better way to find our new schema
  294. # Do Better test when we were able to set correctly schema name
  295. # according to content
  296. schema_name = None
  297. for elem in definitions.keys():
  298. if elem != 'MySchema':
  299. schema_name = elem
  300. break
  301. assert schema_name
  302. schema_def = definitions[schema_name]
  303. assert schema_def.get('properties', {}).get('name', {}).get('type') == 'string'
  304. assert doc.get('paths').get('/paper').get('post').get('parameters')[0]
  305. schema_ref = doc.get('paths').get('/paper').get('post').get('parameters')[0]
  306. assert schema_ref.get('in') == 'body'
  307. assert schema_ref['schema'] == {
  308. 'items': {'$ref': '#/definitions/{}'.format(schema_name)},
  309. 'type': 'array'
  310. }