test_pagure_flask_api_issue_change_status.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015-2017 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. from __future__ import unicode_literals
  8. __requires__ = ['SQLAlchemy >= 0.8']
  9. import pkg_resources
  10. import copy
  11. import datetime
  12. import unittest
  13. import shutil
  14. import sys
  15. import time
  16. import os
  17. import json
  18. from mock import patch, MagicMock
  19. sys.path.insert(0, os.path.join(os.path.dirname(
  20. os.path.abspath(__file__)), '..'))
  21. import pagure
  22. import pagure.lib
  23. import pagure.lib.model
  24. import tests
  25. class PagureFlaskApiIssueChangeStatustests(tests.Modeltests):
  26. """ Tests for the flask API of pagure for changing the status of an
  27. issue
  28. """
  29. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  30. def setUp(self):
  31. """ Set up the environnment, ran before every tests. """
  32. super(PagureFlaskApiIssueChangeStatustests, self).setUp()
  33. pagure.config.config['TICKETS_FOLDER'] = None
  34. tests.create_projects(self.session)
  35. tests.create_projects_git(os.path.join(self.path, 'tickets'))
  36. tests.create_tokens(self.session)
  37. tests.create_tokens_acl(self.session)
  38. # Create normal issue
  39. repo = pagure.lib.get_authorized_project(self.session, 'test')
  40. msg = pagure.lib.new_issue(
  41. session=self.session,
  42. repo=repo,
  43. title='Test issue #1',
  44. content='We should work on this',
  45. user='pingou',
  46. private=False,
  47. )
  48. self.session.commit()
  49. self.assertEqual(msg.title, 'Test issue #1')
  50. # Create private issue
  51. msg = pagure.lib.new_issue(
  52. session=self.session,
  53. repo=repo,
  54. title='Test issue #2',
  55. content='We should work on this',
  56. user='foo',
  57. private=True,
  58. )
  59. self.session.commit()
  60. self.assertEqual(msg.title, 'Test issue #2')
  61. # Create project-less token for user foo
  62. item = pagure.lib.model.Token(
  63. id='project-less-foo',
  64. user_id=2,
  65. project_id=None,
  66. expiration=datetime.datetime.utcnow()
  67. + datetime.timedelta(days=30)
  68. )
  69. self.session.add(item)
  70. self.session.commit()
  71. tests.create_tokens_acl(self.session, token_id='project-less-foo')
  72. # Create project-less token for user pingou
  73. item = pagure.lib.model.Token(
  74. id='project-less-pingou',
  75. user_id=1,
  76. project_id=None,
  77. expiration=datetime.datetime.utcnow()
  78. + datetime.timedelta(days=30)
  79. )
  80. self.session.add(item)
  81. self.session.commit()
  82. tests.create_tokens_acl(self.session, token_id='project-less-pingou')
  83. def test_api_change_status_issue_invalid_project(self):
  84. """ Test the api_change_status_issue method of the flask api. """
  85. headers = {'Authorization': 'token aaabbbcccddd'}
  86. # Invalid project
  87. output = self.app.post(
  88. '/api/0/foobar/issue/1/status', headers=headers)
  89. self.assertEqual(output.status_code, 404)
  90. data = json.loads(output.get_data(as_text=True))
  91. self.assertDictEqual(
  92. data,
  93. {
  94. "error": "Project not found",
  95. "error_code": "ENOPROJECT",
  96. }
  97. )
  98. def test_api_change_status_issue_token_not_for_project(self):
  99. """ Test the api_change_status_issue method of the flask api. """
  100. headers = {'Authorization': 'token aaabbbcccddd'}
  101. # Valid token, wrong project
  102. output = self.app.post('/api/0/test2/issue/1/status', headers=headers)
  103. self.assertEqual(output.status_code, 401)
  104. data = json.loads(output.get_data(as_text=True))
  105. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  106. data['error_code'])
  107. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  108. def test_api_change_status_issue_invalid_issue(self):
  109. """ Test the api_change_status_issue method of the flask api. """
  110. headers = {'Authorization': 'token aaabbbcccddd'}
  111. # No issue
  112. output = self.app.post('/api/0/test/issue/42/status', headers=headers)
  113. self.assertEqual(output.status_code, 404)
  114. data = json.loads(output.get_data(as_text=True))
  115. self.assertDictEqual(
  116. data,
  117. {
  118. "error": "Issue not found",
  119. "error_code": "ENOISSUE",
  120. }
  121. )
  122. def test_api_change_status_issue_incomplete(self):
  123. """ Test the api_change_status_issue method of the flask api. """
  124. headers = {'Authorization': 'token aaabbbcccddd'}
  125. # Check status before
  126. repo = pagure.lib.get_authorized_project(self.session, 'test')
  127. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  128. self.assertEqual(issue.status, 'Open')
  129. data = {
  130. 'title': 'test issue',
  131. }
  132. # Incomplete request
  133. output = self.app.post(
  134. '/api/0/test/issue/1/status', data=data, headers=headers)
  135. self.assertEqual(output.status_code, 400)
  136. data = json.loads(output.get_data(as_text=True))
  137. self.assertDictEqual(
  138. data,
  139. {
  140. "error": "Invalid or incomplete input submitted",
  141. "error_code": "EINVALIDREQ",
  142. "errors": {"status": ["Not a valid choice"]}
  143. }
  144. )
  145. # No change
  146. repo = pagure.lib.get_authorized_project(self.session, 'test')
  147. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  148. self.assertEqual(issue.status, 'Open')
  149. def test_api_change_status_issue_no_change(self):
  150. """ Test the api_change_status_issue method of the flask api. """
  151. headers = {'Authorization': 'token aaabbbcccddd'}
  152. data = {
  153. 'status': 'Open',
  154. }
  155. # Valid request but no change
  156. output = self.app.post(
  157. '/api/0/test/issue/1/status', data=data, headers=headers)
  158. self.assertEqual(output.status_code, 200)
  159. data = json.loads(output.get_data(as_text=True))
  160. self.assertDictEqual(
  161. data,
  162. {'message': 'No changes'}
  163. )
  164. # No change
  165. repo = pagure.lib.get_authorized_project(self.session, 'test')
  166. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  167. self.assertEqual(issue.status, 'Open')
  168. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  169. @patch(
  170. 'pagure.lib.edit_issue',
  171. MagicMock(side_effect=pagure.exceptions.PagureException('error')))
  172. def test_api_change_status_issue_raise_error(self):
  173. """ Test the api_change_status_issue method of the flask api. """
  174. repo = pagure.lib.get_authorized_project(self.session, 'test')
  175. close_status = repo.close_status
  176. close_status = ['Fixed', 'Upstream', 'Invalid']
  177. repo.close_status = close_status
  178. self.session.add(repo)
  179. self.session.commit()
  180. headers = {'Authorization': 'token aaabbbcccddd'}
  181. data = {
  182. 'status': 'Closed',
  183. 'close_status': 'Fixed'
  184. }
  185. # Valid request
  186. output = self.app.post(
  187. '/api/0/test/issue/1/status', data=data, headers=headers)
  188. self.assertEqual(output.status_code, 400)
  189. data = json.loads(output.get_data(as_text=True))
  190. self.assertDictEqual(
  191. data,
  192. {u'error': u'error', u'error_code': u'ENOCODE'}
  193. )
  194. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  195. def test_api_change_status_issue(self):
  196. """ Test the api_change_status_issue method of the flask api. """
  197. headers = {'Authorization': 'token aaabbbcccddd'}
  198. data = {
  199. 'status': 'Fixed',
  200. }
  201. # Valid request
  202. output = self.app.post(
  203. '/api/0/test/issue/1/status', data=data, headers=headers)
  204. self.assertEqual(output.status_code, 200)
  205. data = json.loads(output.get_data(as_text=True))
  206. self.assertDictEqual(
  207. data,
  208. {'message':[
  209. 'Issue status updated to: Closed (was: Open)',
  210. 'Issue close_status updated to: Fixed'
  211. ]}
  212. )
  213. headers = {'Authorization': 'token pingou_foo'}
  214. # Un-authorized issue
  215. output = self.app.post(
  216. '/api/0/foo/issue/1/status', data=data, headers=headers)
  217. self.assertEqual(output.status_code, 401)
  218. data = json.loads(output.get_data(as_text=True))
  219. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  220. data['error_code'])
  221. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  222. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  223. def test_api_change_status_issue_closed_status(self):
  224. """ Test the api_change_status_issue method of the flask api. """
  225. repo = pagure.lib.get_authorized_project(self.session, 'test')
  226. close_status = repo.close_status
  227. close_status = ['Fixed', 'Upstream', 'Invalid']
  228. repo.close_status = close_status
  229. self.session.add(repo)
  230. self.session.commit()
  231. headers = {'Authorization': 'token aaabbbcccddd'}
  232. data = {
  233. 'status': 'Closed',
  234. 'close_status': 'Fixed'
  235. }
  236. # Valid request
  237. output = self.app.post(
  238. '/api/0/test/issue/1/status', data=data, headers=headers)
  239. self.assertEqual(output.status_code, 200)
  240. data = json.loads(output.get_data(as_text=True))
  241. self.assertDictEqual(
  242. data,
  243. {'message':[
  244. 'Issue status updated to: Closed (was: Open)',
  245. 'Issue close_status updated to: Fixed'
  246. ]}
  247. )
  248. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  249. def test_api_change_status_issue_no_ticket_project_less(self):
  250. """ Test the api_change_status_issue method of the flask api. """
  251. headers = {'Authorization': 'token project-less-foo'}
  252. data = {
  253. 'status': 'Fixed',
  254. }
  255. # Valid request
  256. output = self.app.post(
  257. '/api/0/test/issue/1/status', data=data, headers=headers)
  258. self.assertEqual(output.status_code, 403)
  259. data = json.loads(output.get_data(as_text=True))
  260. self.assertDictEqual(
  261. data,
  262. {
  263. "error": "You are not allowed to view this issue",
  264. "error_code": "EISSUENOTALLOWED"
  265. }
  266. )
  267. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  268. def test_api_change_status_issue_project_less(self):
  269. """ Test the api_change_status_issue method of the flask api. """
  270. headers = {'Authorization': 'token project-less-pingou'}
  271. data = {
  272. 'status': 'Fixed',
  273. }
  274. # Valid request
  275. output = self.app.post(
  276. '/api/0/test/issue/1/status', data=data, headers=headers)
  277. self.assertEqual(output.status_code, 200)
  278. data = json.loads(output.get_data(as_text=True))
  279. self.assertDictEqual(
  280. data,
  281. {
  282. "message": [
  283. "Issue status updated to: Closed (was: Open)",
  284. "Issue close_status updated to: Fixed"
  285. ]
  286. }
  287. )
  288. if __name__ == '__main__':
  289. unittest.main(verbosity=2)