test_pagure_flask_api_issue_change_status.py 11 KB

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