test_api.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. # coding: utf-8
  2. import json
  3. from urllib.parse import urljoin
  4. import aiohttp
  5. import pytest
  6. from echod.utils import decode_json
  7. content_type = 'application/json; charset=utf-8'
  8. payload = {
  9. 'name': 'Joaozinho',
  10. 'age': 9,
  11. }
  12. str_payload = {
  13. 'name': 'Joaozinho',
  14. 'age': '9',
  15. }
  16. json_payload = json.dumps(payload)
  17. default_header = {
  18. 'Content-Length': '31',
  19. 'Content-Type': '',
  20. 'Host': 'localhost'
  21. }
  22. zero_length_header = {
  23. 'Content-Length': '0',
  24. 'Content-Type': '',
  25. 'Host': 'localhost'
  26. }
  27. request_headers = {
  28. 'content_type': 'application/json',
  29. 'accept': 'application/json',
  30. }
  31. # Mock tests
  32. @pytest.mark.asyncio
  33. def test_get_mock(api_server):
  34. url = urljoin(api_server, '/mocks/')
  35. response = yield from aiohttp.request('GET', url)
  36. assert response.status == 200
  37. assert response.reason == 'OK'
  38. assert response.headers['content-type'] == content_type
  39. response_json = yield from response.json()
  40. assert response_json == {'mocks': {}}
  41. @pytest.mark.asyncio
  42. def test_put_mock(api_server):
  43. expectation = {
  44. 'method': 'POST',
  45. 'path': '/v1/users/',
  46. 'request': {'body': {'email': 'john@doe.com',
  47. 'name': 'John Doe',
  48. 'password': 'secret'},
  49. 'headers': {'accept': 'application/json',
  50. 'content_type': 'application/json'}},
  51. 'response': {'body': {'email': 'john@doe.com', 'name': 'John Doe'},
  52. 'headers': {'content_type': 'application/json'},
  53. 'status_code': 201}
  54. }
  55. url = urljoin(api_server, '/mocks/')
  56. # Configure the mock
  57. response = yield from aiohttp.request('PUT', url,
  58. data=json.dumps(expectation),
  59. headers=request_headers)
  60. assert response.status == 201
  61. assert response.reason == 'Created'
  62. assert response.headers['content-type'] == content_type
  63. response_json = yield from response.json()
  64. assert 'path' in response_json.keys()
  65. # Use the mock
  66. post_url = urljoin(api_server, response_json['path'])
  67. post_body = json.dumps(expectation['request']['body'])
  68. response = yield from aiohttp.request('POST', post_url,
  69. data=post_body,
  70. headers=request_headers)
  71. assert response.status == 201
  72. assert response.reason == 'Created'
  73. assert response.headers['content-type'] == content_type
  74. response_json = yield from response.json()
  75. assert 'email' in response_json.keys()
  76. assert 'name' in response_json.keys()
  77. @pytest.mark.asyncio
  78. def test_put_mock_without_request_expectation(api_server):
  79. expectation = {
  80. 'method': 'PUT',
  81. 'path': '/v1/users/',
  82. 'response': {'body': {'email': 'john@doe.com', 'name': 'John Doe'},
  83. 'headers': {'content_type': 'application/json'},
  84. 'status_code': 200}
  85. }
  86. url = urljoin(api_server, '/mocks/')
  87. # Configure the mock
  88. response = yield from aiohttp.request('PUT', url,
  89. data=json.dumps(expectation),
  90. headers=request_headers)
  91. assert response.status == 201
  92. assert response.reason == 'Created'
  93. assert response.headers['content-type'] == content_type
  94. response_json = yield from response.json()
  95. assert 'path' in response_json.keys()
  96. # Use the mock
  97. put_url = urljoin(api_server, response_json['path'])
  98. put_body = json.dumps({})
  99. response = yield from aiohttp.request('PUT', put_url,
  100. data=put_body,
  101. headers=request_headers)
  102. assert response.status == 200
  103. assert response.reason == 'OK'
  104. assert response.headers['content-type'] == content_type
  105. response_json = yield from response.json()
  106. assert 'email' in response_json.keys()
  107. assert 'name' in response_json.keys()
  108. @pytest.mark.asyncio
  109. def test_method_not_allowed(api_server):
  110. expectation = {
  111. 'method': 'GET',
  112. 'path': '/v1/users/',
  113. 'response': {'body': {'email': 'john@doe.com', 'name': 'John Doe'},
  114. 'headers': {'content_type': 'application/json'},
  115. 'status_code': 200}
  116. }
  117. url = urljoin(api_server, '/mocks/')
  118. # Configure the mock
  119. response = yield from aiohttp.request('PUT', url,
  120. data=json.dumps(expectation),
  121. headers=request_headers)
  122. assert response.status == 201
  123. assert response.reason == 'Created'
  124. assert response.headers['content-type'] == content_type
  125. response_json = yield from response.json()
  126. assert 'path' in response_json.keys()
  127. # Use the mock
  128. put_url = urljoin(api_server, response_json['path'])
  129. response = yield from aiohttp.request('PUT', put_url)
  130. assert response.status == 405
  131. assert response.reason == 'Method Not Allowed'
  132. @pytest.mark.asyncio
  133. def test_not_found(api_server):
  134. post_url = urljoin(api_server, '/mock/noexist/url/')
  135. post_body = '{}'
  136. response = yield from aiohttp.request('POST', post_url,
  137. data=post_body,
  138. headers=request_headers)
  139. assert response.status == 404
  140. assert response.reason == 'Not Found'
  141. # Health
  142. @pytest.mark.asyncio
  143. def test_health(api_server):
  144. url = urljoin(api_server, '/health/')
  145. response = yield from aiohttp.request('GET', url)
  146. assert response.status == 200
  147. assert response.reason == 'OK'
  148. assert response.headers['content-type'] == content_type
  149. response_json = yield from response.json()
  150. assert response_json == {'status': 'ok'}
  151. # Callback tests
  152. @pytest.mark.asyncio
  153. def test_queue_request_return_status_200(api_server):
  154. url = urljoin(api_server, '/callbacks/app/queue/')
  155. response = yield from aiohttp.request('POST',
  156. url,
  157. data=json_payload)
  158. assert response.status == 200
  159. @pytest.mark.asyncio
  160. def test_queue_request_return_json(api_server):
  161. url = urljoin(api_server, '/callbacks/app/queue/')
  162. response = yield from aiohttp.request('POST', url,
  163. data=json_payload)
  164. response_json = yield from response.json()
  165. assert response_json['request']['method'] == 'POST'
  166. assert response_json['request']['data'] == payload
  167. @pytest.mark.asyncio
  168. def test_queue_request_store_request(api_server, redis):
  169. url = urljoin(api_server, '/callbacks/app/queue/')
  170. yield from aiohttp.request('POST', url, data=json_payload)
  171. assert redis.llen('app-queue') == 1
  172. @pytest.mark.asyncio
  173. def test_queue_request_store_json(api_server, redis):
  174. url = urljoin(api_server, '/callbacks/app/queue/')
  175. yield from aiohttp.request('POST', url, data=json_payload,
  176. headers={'X-Region': 'Sao_Paulo'})
  177. db_json = decode_json(redis.rpop('app-queue').decode('utf-8'))
  178. assert db_json['header']['X-REGION'] == 'Sao_Paulo'
  179. assert db_json['method'] == 'POST'
  180. assert db_json['data'] == payload
  181. """
  182. @pytest.mark.asyncio
  183. def test_queue_request_with_additional_url_return_status_200(api_server):
  184. url = '/callbacks/app/queue/some/more/url/here'
  185. response = yield from aiohttp.request('POST', url,
  186. data=json_payload)
  187. assert response.status == 200
  188. @pytest.mark.asyncio
  189. def test_queue_request_with_additional_url_json(api_server, redis):
  190. url = '/callbacks/app/queue/some/more/url/here'
  191. yield from aiohttp.request('POST', url,
  192. data=json_payload)
  193. expected_data = {
  194. 'method': 'POST',
  195. 'data': payload,
  196. 'additional_url': 'some/more/url/here',
  197. 'header': default_header,
  198. }
  199. assert decode_json(redis.rpop('app-queue')) == expected_data
  200. """
  201. @pytest.mark.asyncio
  202. def test_queue_request_store_multiple_requests(api_server, redis):
  203. url = urljoin(api_server, '/callbacks/app/queue/')
  204. yield from aiohttp.request('POST', url, data=json_payload)
  205. yield from aiohttp.request('POST', url, data=json_payload)
  206. yield from aiohttp.request('POST', url, data=json_payload)
  207. assert redis.llen('app-queue') == 3
  208. @pytest.mark.asyncio
  209. def test_queue_request_store_request_different_apps(api_server, redis):
  210. url1 = urljoin(api_server, '/callbacks/app1/queue/')
  211. url2 = urljoin(api_server, '/callbacks/app2/queue/')
  212. yield from aiohttp.request('POST', url1, data=json_payload)
  213. yield from aiohttp.request('POST', url2, data=json_payload)
  214. assert redis.llen('app1-queue') == 1
  215. assert redis.llen('app2-queue') == 1
  216. @pytest.mark.asyncio
  217. def test_queue_request_store_request_different_queues(api_server, redis):
  218. url1 = urljoin(api_server, '/callbacks/app/queue1/')
  219. url2 = urljoin(api_server, '/callbacks/app/queue2/')
  220. yield from aiohttp.request('POST', url1, data=json_payload)
  221. yield from aiohttp.request('POST', url2, data=json_payload)
  222. assert redis.llen('app-queue1') == 1
  223. assert redis.llen('app-queue2') == 1
  224. @pytest.mark.asyncio
  225. def test_get_requests_return_status_200(api_server):
  226. url = urljoin(api_server, '/callbacks/_all/app/queue/')
  227. response = yield from aiohttp.request('GET', url)
  228. assert response.status == 200
  229. @pytest.mark.asyncio
  230. def test_get_requests_empty(api_server):
  231. url = urljoin(api_server, '/callbacks/_all/app/queue/')
  232. response = yield from aiohttp.request('GET', url)
  233. response_json = yield from response.json()
  234. assert response_json == {'requests': []}
  235. @pytest.mark.asyncio
  236. def test_get_requests_one_request(api_server):
  237. url = urljoin(api_server, '/callbacks/app/queue/')
  238. yield from aiohttp.request('POST', url, data=json_payload)
  239. url_all = urljoin(api_server, '/callbacks/_all/app/queue/')
  240. response = yield from aiohttp.request('GET', url_all)
  241. response_json = yield from response.json()
  242. assert response_json['requests'][0]['method'] == 'POST'
  243. assert response_json['requests'][0]['data'] == payload
  244. # TODO: Make it work
  245. """
  246. @pytest.mark.asyncio
  247. def test_get_requests_multiple_request(api_server):
  248. url = urljoin(api_server, '/callbacks/app/queue/')
  249. yield from aiohttp.request('POST', url, data=json_payload)
  250. yield from aiohttp.request('PUT', url, data=json_payload)
  251. yield from aiohttp.request('PATCH', url, data=json_payload)
  252. # TODO: Make it work
  253. # yield from aiohttp.request('GET', url, query_string=payload)
  254. yield from aiohttp.request('DELETE', url)
  255. url_all = urljoin(api_server, '/callbacks/_all/app/queue/')
  256. response = yield from aiohttp.request('GET', )
  257. expected_data = [
  258. {'method': 'POST', 'data': payload, 'header': default_header,
  259. 'additional_url': ''},
  260. {'method': 'PUT', 'data': payload, 'header': default_header,
  261. 'additional_url': ''},
  262. {'method': 'PATCH', 'data': payload, 'header': default_header,
  263. 'additional_url': ''},
  264. {'method': 'GET', 'data': str_payload, 'header': zero_length_header,
  265. 'additional_url': ''},
  266. {'method': 'DELETE', 'data': {}, 'header': zero_length_header,
  267. 'additional_url': ''},
  268. ]
  269. response_json = yield from response.json()
  270. assert response_json == {'requests': expected_data}
  271. """
  272. @pytest.mark.asyncio
  273. def test_get_requests_remove_key(api_server, redis):
  274. url = urljoin(api_server, '/callbacks/app/queue/')
  275. url_all = urljoin(api_server, '/callbacks/_all/app/queue/')
  276. yield from aiohttp.request('POST', url, data=json_payload)
  277. yield from aiohttp.request('GET', url_all)
  278. assert not redis.exists('app-queue')
  279. @pytest.mark.asyncio
  280. def test_first_request_return_status_200(api_server):
  281. url = urljoin(api_server, '/callbacks/_first/app/queue/')
  282. response = yield from aiohttp.request('GET', url)
  283. assert response.status == 200
  284. @pytest.mark.asyncio
  285. def test_first_request_empty(api_server):
  286. url = urljoin(api_server, '/callbacks/_first/app/queue/')
  287. response = yield from aiohttp.request('GET', url)
  288. response_json = yield from response.json()
  289. assert response_json == {'request': {}}
  290. @pytest.mark.asyncio
  291. def test_first_request_one_request(api_server):
  292. url = urljoin(api_server, '/callbacks/app/queue/')
  293. yield from aiohttp.request('POST', url, data=json_payload)
  294. url_first = urljoin(api_server, '/callbacks/_first/app/queue/')
  295. response = yield from aiohttp.request('GET', url_first)
  296. response_json = yield from response.json()
  297. assert response_json['request']['method'] == 'POST'
  298. assert response_json['request']['data'] == payload
  299. @pytest.mark.asyncio
  300. def test_first_request_multiple_request(api_server):
  301. url = urljoin(api_server, '/callbacks/app/queue/')
  302. yield from aiohttp.request('POST', url, data=json_payload)
  303. yield from aiohttp.request('PUT', url, data=json_payload)
  304. yield from aiohttp.request('PATCH', url, data=json_payload)
  305. # yield from aiohttp.request('GET', url, query_string=payload)
  306. yield from aiohttp.request('DELETE', url)
  307. url_first = urljoin(api_server, '/callbacks/_first/app/queue/')
  308. response = yield from aiohttp.request('GET', url_first)
  309. response_json = yield from response.json()
  310. assert response_json['request']['method'] == 'POST'
  311. assert response_json['request']['data'] == payload
  312. @pytest.mark.asyncio
  313. def test_last_request_return_status_200(api_server):
  314. url = urljoin(api_server, '/callbacks/_last/app/queue/')
  315. response = yield from aiohttp.request('GET', url)
  316. assert response.status == 200
  317. @pytest.mark.asyncio
  318. def test_last_request_empty(api_server):
  319. url = urljoin(api_server, '/callbacks/_last/app/queue/')
  320. response = yield from aiohttp.request('GET', url)
  321. response_json = yield from response.json()
  322. assert response_json == {'request': {}}
  323. @pytest.mark.asyncio
  324. def test_last_request_one_request(api_server):
  325. url = urljoin(api_server, '/callbacks/app/queue/')
  326. yield from aiohttp.request('POST', url, data=json_payload)
  327. url_last = urljoin(api_server, '/callbacks/_last/app/queue/')
  328. response = yield from aiohttp.request('GET', url_last)
  329. response_json = yield from response.json()
  330. assert response_json['request']['method'] == 'POST'
  331. assert response_json['request']['data'] == payload
  332. """
  333. @pytest.mark.asyncio
  334. def test_last_request_multiple_request(api_server):
  335. yield from aiohttp.request('POST', urljoin(api_server, '/callbacks/app/que
  336. yield from aiohttp.request('PUT', urljoin(api_server, '/callbacks/app/queu
  337. yield from aiohttp.request('PATCH', urljoin(api_server, '/callbacks/app/qu
  338. yield from aiohttp.request('GET', urljoin(api_server, '/callbacks/app/queu
  339. yield from aiohttp.request('DELETE', urljoin(api_server, '/callbacks/app/q
  340. response = yield from aiohttp.request('GET', urljoin(api_server, '/callbac
  341. expected_data = {'method': 'DELETE', 'data': {}, 'additional_url': '', 'he
  342. assert decode_json(response.data) == {'request': expected_data}
  343. """
  344. @pytest.mark.asyncio
  345. def test_clean_requests_none_request(api_server, redis):
  346. url = urljoin(api_server, '/callbacks/_clean/app/queue/')
  347. yield from aiohttp.request('GET', url)
  348. assert not redis.exists('app-queue')
  349. @pytest.mark.asyncio
  350. def test_clean_requests_none_request_return_status_200(api_server):
  351. url = urljoin(api_server, '/callbacks/_clean/app/queue/')
  352. response = yield from aiohttp.request('GET', url)
  353. assert response.status == 200
  354. @pytest.mark.asyncio
  355. def test_clean_requests_none_request_return_empty_json(api_server):
  356. url = urljoin(api_server, '/callbacks/_clean/app/queue/')
  357. response = yield from aiohttp.request('GET', url)
  358. response_json = yield from response.json()
  359. assert response_json == {}
  360. @pytest.mark.asyncio
  361. def test_clean_requests_multiple_requests(api_server, redis):
  362. url = urljoin(api_server, '/callbacks/app/queue/')
  363. yield from aiohttp.request('POST', url, data=json_payload)
  364. yield from aiohttp.request('PUT', url, data=json_payload)
  365. yield from aiohttp.request('PATCH', url, data=json_payload)
  366. yield from aiohttp.request('DELETE', url)
  367. url_clean = urljoin(api_server, '/callbacks/_clean/app/queue/')
  368. yield from aiohttp.request('GET', url_clean)
  369. assert not redis.exists('app-queue')