test_pagure_flask_api_issue.py 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. __requires__ = ['SQLAlchemy >= 0.8']
  8. import pkg_resources
  9. import datetime
  10. import unittest
  11. import shutil
  12. import sys
  13. import os
  14. import json
  15. from mock import patch
  16. sys.path.insert(0, os.path.join(os.path.dirname(
  17. os.path.abspath(__file__)), '..'))
  18. import pagure.lib
  19. import tests
  20. class PagureFlaskApiIssuetests(tests.Modeltests):
  21. """ Tests for the flask API of pagure for issue """
  22. def setUp(self):
  23. """ Set up the environnment, ran before every tests. """
  24. super(PagureFlaskApiIssuetests, self).setUp()
  25. pagure.APP.config['TESTING'] = True
  26. pagure.SESSION = self.session
  27. pagure.api.SESSION = self.session
  28. pagure.api.issue.SESSION = self.session
  29. pagure.lib.SESSION = self.session
  30. pagure.APP.config['TICKETS_FOLDER'] = None
  31. self.app = pagure.APP.test_client()
  32. def test_api_new_issue(self):
  33. """ Test the api_new_issue method of the flask api. """
  34. tests.create_projects(self.session)
  35. tests.create_projects_git(os.path.join(tests.HERE, 'tickets'))
  36. tests.create_tokens(self.session)
  37. tests.create_tokens_acl(self.session)
  38. headers = {'Authorization': 'token aaabbbcccddd'}
  39. # Valid token, wrong project
  40. output = self.app.post('/api/0/test2/new_issue', headers=headers)
  41. self.assertEqual(output.status_code, 401)
  42. data = json.loads(output.data)
  43. self.assertDictEqual(
  44. data,
  45. {
  46. "error": "Invalid or expired token. Please visit " \
  47. "https://pagure.org/ to get or renew your API token.",
  48. "error_code": "EINVALIDTOK",
  49. }
  50. )
  51. # No input
  52. output = self.app.post('/api/0/test/new_issue', headers=headers)
  53. self.assertEqual(output.status_code, 400)
  54. data = json.loads(output.data)
  55. self.assertDictEqual(
  56. data,
  57. {
  58. "error": "Invalid or incomplete input submited",
  59. "error_code": "EINVALIDREQ",
  60. }
  61. )
  62. data = {
  63. 'title': 'test issue',
  64. }
  65. # Invalid repo
  66. output = self.app.post(
  67. '/api/0/foo/new_issue', data=data, headers=headers)
  68. self.assertEqual(output.status_code, 404)
  69. data = json.loads(output.data)
  70. self.assertDictEqual(
  71. data,
  72. {
  73. "error": "Project not found",
  74. "error_code": "ENOPROJECT",
  75. }
  76. )
  77. # Incomplete request
  78. output = self.app.post(
  79. '/api/0/test/new_issue', data=data, headers=headers)
  80. self.assertEqual(output.status_code, 400)
  81. data = json.loads(output.data)
  82. self.assertDictEqual(
  83. data,
  84. {
  85. "error": "Invalid or incomplete input submited",
  86. "error_code": "EINVALIDREQ",
  87. }
  88. )
  89. data = {
  90. 'title': 'test issue',
  91. 'issue_content': 'This issue needs attention',
  92. }
  93. # Valid request
  94. output = self.app.post(
  95. '/api/0/test/new_issue', data=data, headers=headers)
  96. self.assertEqual(output.status_code, 200)
  97. data = json.loads(output.data)
  98. self.assertDictEqual(
  99. data,
  100. {'message': 'Issue created'}
  101. )
  102. def test_api_view_issues(self):
  103. """ Test the api_view_issues method of the flask api. """
  104. self.test_api_new_issue()
  105. # Invalid repo
  106. output = self.app.get('/api/0/foo/issues')
  107. self.assertEqual(output.status_code, 404)
  108. data = json.loads(output.data)
  109. self.assertDictEqual(
  110. data,
  111. {
  112. "error": "Project not found",
  113. "error_code": "ENOPROJECT",
  114. }
  115. )
  116. # List all opened issues
  117. output = self.app.get('/api/0/test/issues')
  118. self.assertEqual(output.status_code, 200)
  119. data = json.loads(output.data)
  120. data['issues'][0]['date_created'] = '1431414800'
  121. self.assertDictEqual(
  122. data,
  123. {
  124. "args": {
  125. "assignee": None,
  126. "author": None,
  127. "status": None,
  128. "tags": []
  129. },
  130. "total_issues": 1,
  131. "issues": [
  132. {
  133. "assignee": None,
  134. "blocks": [],
  135. "comments": [],
  136. "content": "This issue needs attention",
  137. "date_created": "1431414800",
  138. "closed_at": None,
  139. "depends": [],
  140. "id": 1,
  141. "priority": None,
  142. "private": False,
  143. "status": "Open",
  144. "tags": [],
  145. "title": "test issue",
  146. "user": {
  147. "fullname": "PY C",
  148. "name": "pingou"
  149. }
  150. }
  151. ]
  152. }
  153. )
  154. # Create private issue
  155. repo = pagure.lib.get_project(self.session, 'test')
  156. msg = pagure.lib.new_issue(
  157. session=self.session,
  158. repo=repo,
  159. title='Test issue',
  160. content='We should work on this',
  161. user='pingou',
  162. ticketfolder=None,
  163. private=True,
  164. )
  165. self.session.commit()
  166. self.assertEqual(msg.title, 'Test issue')
  167. # Access issues un-authenticated
  168. output = self.app.get('/api/0/test/issues')
  169. self.assertEqual(output.status_code, 200)
  170. data = json.loads(output.data)
  171. data['issues'][0]['date_created'] = '1431414800'
  172. self.assertDictEqual(
  173. data,
  174. {
  175. "args": {
  176. "assignee": None,
  177. "author": None,
  178. "status": None,
  179. "tags": []
  180. },
  181. "total_issues": 1,
  182. "issues": [
  183. {
  184. "assignee": None,
  185. "blocks": [],
  186. "comments": [],
  187. "content": "This issue needs attention",
  188. "date_created": "1431414800",
  189. "closed_at": None,
  190. "depends": [],
  191. "id": 1,
  192. "priority": None,
  193. "private": False,
  194. "status": "Open",
  195. "tags": [],
  196. "title": "test issue",
  197. "user": {
  198. "fullname": "PY C",
  199. "name": "pingou"
  200. }
  201. }
  202. ]
  203. }
  204. )
  205. headers = {'Authorization': 'token aaabbbccc'}
  206. # Access issues authenticated but non-existing token
  207. output = self.app.get('/api/0/test/issues', headers=headers)
  208. self.assertEqual(output.status_code, 401)
  209. # Create a new token for another user
  210. item = pagure.lib.model.Token(
  211. id='bar_token',
  212. user_id=2,
  213. project_id=1,
  214. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  215. days=30)
  216. )
  217. self.session.add(item)
  218. headers = {'Authorization': 'token bar_token'}
  219. # Access issues authenticated but wrong token
  220. output = self.app.get('/api/0/test/issues', headers=headers)
  221. self.assertEqual(output.status_code, 200)
  222. data = json.loads(output.data)
  223. data['issues'][0]['date_created'] = '1431414800'
  224. self.assertDictEqual(
  225. data,
  226. {
  227. "args": {
  228. "assignee": None,
  229. "author": None,
  230. "status": None,
  231. "tags": []
  232. },
  233. "total_issues": 1,
  234. "issues": [
  235. {
  236. "assignee": None,
  237. "blocks": [],
  238. "comments": [],
  239. "content": "This issue needs attention",
  240. "date_created": "1431414800",
  241. "closed_at": None,
  242. "depends": [],
  243. "id": 1,
  244. "priority": None,
  245. "private": False,
  246. "status": "Open",
  247. "tags": [],
  248. "title": "test issue",
  249. "user": {
  250. "fullname": "PY C",
  251. "name": "pingou"
  252. }
  253. }
  254. ]
  255. }
  256. )
  257. headers = {'Authorization': 'token aaabbbcccddd'}
  258. # Access issues authenticated correctly
  259. output = self.app.get('/api/0/test/issues', headers=headers)
  260. self.assertEqual(output.status_code, 200)
  261. data = json.loads(output.data)
  262. data['issues'][0]['date_created'] = '1431414800'
  263. data['issues'][1]['date_created'] = '1431414800'
  264. self.assertDictEqual(
  265. data,
  266. {
  267. "args": {
  268. "assignee": None,
  269. "author": None,
  270. "status": None,
  271. "tags": []
  272. },
  273. "total_issues": 2,
  274. "issues": [
  275. {
  276. "assignee": None,
  277. "blocks": [],
  278. "comments": [],
  279. "content": "This issue needs attention",
  280. "date_created": "1431414800",
  281. "closed_at": None,
  282. "depends": [],
  283. "id": 1,
  284. "priority": None,
  285. "private": False,
  286. "status": "Open",
  287. "tags": [],
  288. "title": "test issue",
  289. "user": {
  290. "fullname": "PY C",
  291. "name": "pingou"
  292. }
  293. },
  294. {
  295. "assignee": None,
  296. "blocks": [],
  297. "comments": [],
  298. "content": "We should work on this",
  299. "date_created": "1431414800",
  300. "closed_at": None,
  301. "depends": [],
  302. "id": 2,
  303. "priority": None,
  304. "private": True,
  305. "status": "Open",
  306. "tags": [],
  307. "title": "Test issue",
  308. "user": {
  309. "fullname": "PY C",
  310. "name": "pingou"
  311. }
  312. }
  313. ]
  314. }
  315. )
  316. # List closed issue
  317. output = self.app.get('/api/0/test/issues?status=Closed', headers=headers)
  318. self.assertEqual(output.status_code, 200)
  319. data = json.loads(output.data)
  320. self.assertDictEqual(
  321. data,
  322. {
  323. "args": {
  324. "assignee": None,
  325. "author": None,
  326. "status": "Closed",
  327. "tags": []
  328. },
  329. "total_issues": 0,
  330. "issues": []
  331. }
  332. )
  333. # List closed issue
  334. output = self.app.get('/api/0/test/issues?status=Invalid', headers=headers)
  335. self.assertEqual(output.status_code, 200)
  336. data = json.loads(output.data)
  337. self.assertDictEqual(
  338. data,
  339. {
  340. "args": {
  341. "assignee": None,
  342. "author": None,
  343. "status": "Invalid",
  344. "tags": []
  345. },
  346. "total_issues": 0,
  347. "issues": []
  348. }
  349. )
  350. # List all issues
  351. output = self.app.get('/api/0/test/issues?status=All', headers=headers)
  352. self.assertEqual(output.status_code, 200)
  353. data = json.loads(output.data)
  354. data['issues'][0]['date_created'] = '1431414800'
  355. data['issues'][1]['date_created'] = '1431414800'
  356. self.assertDictEqual(
  357. data,
  358. {
  359. "args": {
  360. "assignee": None,
  361. "author": None,
  362. "status": "All",
  363. "tags": []
  364. },
  365. "total_issues": 2,
  366. "issues": [
  367. {
  368. "assignee": None,
  369. "blocks": [],
  370. "comments": [],
  371. "content": "This issue needs attention",
  372. "date_created": "1431414800",
  373. "closed_at": None,
  374. "depends": [],
  375. "id": 1,
  376. "priority": None,
  377. "private": False,
  378. "status": "Open",
  379. "tags": [],
  380. "title": "test issue",
  381. "user": {
  382. "fullname": "PY C",
  383. "name": "pingou"
  384. }
  385. },
  386. {
  387. "assignee": None,
  388. "blocks": [],
  389. "comments": [],
  390. "content": "We should work on this",
  391. "date_created": "1431414800",
  392. "closed_at": None,
  393. "depends": [],
  394. "id": 2,
  395. "priority": None,
  396. "private": True,
  397. "status": "Open",
  398. "tags": [],
  399. "title": "Test issue",
  400. "user": {
  401. "fullname": "PY C",
  402. "name": "pingou"
  403. }
  404. }
  405. ],
  406. }
  407. )
  408. def test_api_view_issue(self):
  409. """ Test the api_view_issue method of the flask api. """
  410. self.test_api_new_issue()
  411. # Invalid repo
  412. output = self.app.get('/api/0/foo/issue/1')
  413. self.assertEqual(output.status_code, 404)
  414. data = json.loads(output.data)
  415. self.assertDictEqual(
  416. data,
  417. {
  418. "error": "Project not found",
  419. "error_code": "ENOPROJECT",
  420. }
  421. )
  422. # Invalid issue for this repo
  423. output = self.app.get('/api/0/test2/issue/1')
  424. self.assertEqual(output.status_code, 404)
  425. data = json.loads(output.data)
  426. self.assertDictEqual(
  427. data,
  428. {
  429. "error": "Issue not found",
  430. "error_code": "ENOISSUE",
  431. }
  432. )
  433. # Valid issue
  434. output = self.app.get('/api/0/test/issue/1')
  435. self.assertEqual(output.status_code, 200)
  436. data = json.loads(output.data)
  437. data['date_created'] = '1431414800'
  438. self.assertDictEqual(
  439. data,
  440. {
  441. "assignee": None,
  442. "blocks": [],
  443. "comments": [],
  444. "content": "This issue needs attention",
  445. "date_created": "1431414800",
  446. "closed_at": None,
  447. "depends": [],
  448. "id": 1,
  449. "priority": None,
  450. "private": False,
  451. "status": "Open",
  452. "tags": [],
  453. "title": "test issue",
  454. "user": {
  455. "fullname": "PY C",
  456. "name": "pingou"
  457. }
  458. }
  459. )
  460. # Create private issue
  461. repo = pagure.lib.get_project(self.session, 'test')
  462. msg = pagure.lib.new_issue(
  463. session=self.session,
  464. repo=repo,
  465. title='Test issue',
  466. content='We should work on this',
  467. user='pingou',
  468. ticketfolder=None,
  469. private=True,
  470. issue_uid='aaabbbccc',
  471. )
  472. self.session.commit()
  473. self.assertEqual(msg.title, 'Test issue')
  474. # Access private issue un-authenticated
  475. output = self.app.get('/api/0/test/issue/2')
  476. self.assertEqual(output.status_code, 403)
  477. data = json.loads(output.data)
  478. self.assertDictEqual(
  479. data,
  480. {
  481. "error": "You are not allowed to view this issue",
  482. "error_code": "EISSUENOTALLOWED",
  483. }
  484. )
  485. headers = {'Authorization': 'token aaabbbccc'}
  486. # Access private issue authenticated but non-existing token
  487. output = self.app.get('/api/0/test/issue/2', headers=headers)
  488. self.assertEqual(output.status_code, 401)
  489. data = json.loads(output.data)
  490. self.assertDictEqual(
  491. data,
  492. {
  493. "error": "Invalid or expired token. Please visit https://pagure.org/ to get or renew your API token.",
  494. "error_code": "EINVALIDTOK"
  495. }
  496. )
  497. # Create a new token for another user
  498. item = pagure.lib.model.Token(
  499. id='bar_token',
  500. user_id=2,
  501. project_id=1,
  502. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  503. days=30)
  504. )
  505. self.session.add(item)
  506. headers = {'Authorization': 'token bar_token'}
  507. # Access private issue authenticated but wrong token
  508. output = self.app.get('/api/0/test/issue/2', headers=headers)
  509. self.assertEqual(output.status_code, 403)
  510. data = json.loads(output.data)
  511. self.assertDictEqual(
  512. data,
  513. {
  514. "error": "You are not allowed to view this issue",
  515. "error_code": "EISSUENOTALLOWED",
  516. }
  517. )
  518. headers = {'Authorization': 'token aaabbbcccddd'}
  519. # Access private issue authenticated correctly
  520. output = self.app.get('/api/0/test/issue/2', headers=headers)
  521. self.assertEqual(output.status_code, 200)
  522. data = json.loads(output.data)
  523. data['date_created'] = '1431414800'
  524. self.assertDictEqual(
  525. data,
  526. {
  527. "assignee": None,
  528. "blocks": [],
  529. "comments": [],
  530. "content": "We should work on this",
  531. "date_created": "1431414800",
  532. "closed_at": None,
  533. "depends": [],
  534. "id": 2,
  535. "priority": None,
  536. "private": True,
  537. "status": "Open",
  538. "tags": [],
  539. "title": "Test issue",
  540. "user": {
  541. "fullname": "PY C",
  542. "name": "pingou"
  543. }
  544. }
  545. )
  546. # Access private issue authenticated correctly using the issue's uid
  547. output = self.app.get('/api/0/test/issue/aaabbbccc', headers=headers)
  548. self.assertEqual(output.status_code, 200)
  549. data = json.loads(output.data)
  550. data['date_created'] = '1431414800'
  551. self.assertDictEqual(
  552. data,
  553. {
  554. "assignee": None,
  555. "blocks": [],
  556. "comments": [],
  557. "content": "We should work on this",
  558. "date_created": "1431414800",
  559. "closed_at": None,
  560. "depends": [],
  561. "id": 2,
  562. "priority": None,
  563. "private": True,
  564. "status": "Open",
  565. "tags": [],
  566. "title": "Test issue",
  567. "user": {
  568. "fullname": "PY C",
  569. "name": "pingou"
  570. }
  571. }
  572. )
  573. def test_api_change_status_issue(self):
  574. """ Test the api_change_status_issue method of the flask api. """
  575. tests.create_projects(self.session)
  576. tests.create_projects_git(os.path.join(tests.HERE, 'tickets'))
  577. tests.create_tokens(self.session)
  578. tests.create_tokens_acl(self.session)
  579. headers = {'Authorization': 'token aaabbbcccddd'}
  580. # Invalid project
  581. output = self.app.post('/api/0/foo/issue/1/status', headers=headers)
  582. self.assertEqual(output.status_code, 404)
  583. data = json.loads(output.data)
  584. self.assertDictEqual(
  585. data,
  586. {
  587. "error": "Project not found",
  588. "error_code": "ENOPROJECT",
  589. }
  590. )
  591. # Valid token, wrong project
  592. output = self.app.post('/api/0/test2/issue/1/status', headers=headers)
  593. self.assertEqual(output.status_code, 401)
  594. data = json.loads(output.data)
  595. self.assertDictEqual(
  596. data,
  597. {
  598. "error": "Invalid or expired token. Please visit " \
  599. "https://pagure.org/ to get or renew your API token.",
  600. "error_code": "EINVALIDTOK",
  601. }
  602. )
  603. # No input
  604. output = self.app.post('/api/0/test/issue/1/status', headers=headers)
  605. self.assertEqual(output.status_code, 404)
  606. data = json.loads(output.data)
  607. self.assertDictEqual(
  608. data,
  609. {
  610. "error": "Issue not found",
  611. "error_code": "ENOISSUE",
  612. }
  613. )
  614. # Create normal issue
  615. repo = pagure.lib.get_project(self.session, 'test')
  616. msg = pagure.lib.new_issue(
  617. session=self.session,
  618. repo=repo,
  619. title='Test issue #1',
  620. content='We should work on this',
  621. user='pingou',
  622. ticketfolder=None,
  623. private=False,
  624. )
  625. self.session.commit()
  626. self.assertEqual(msg.title, 'Test issue #1')
  627. # Create another project
  628. item = pagure.lib.model.Project(
  629. user_id=2, # pingou
  630. name='foo',
  631. description='test project #3',
  632. hook_token='aaabbbdddeee',
  633. )
  634. self.session.add(item)
  635. self.session.commit()
  636. # Create a token for pingou for this project
  637. item = pagure.lib.model.Token(
  638. id='pingou_foo',
  639. user_id=1,
  640. project_id=3,
  641. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  642. days=30)
  643. )
  644. self.session.add(item)
  645. self.session.commit()
  646. # Give `change_status_issue` to this token
  647. item = pagure.lib.model.TokenAcl(
  648. token_id='pingou_foo',
  649. acl_id=6,
  650. )
  651. self.session.add(item)
  652. self.session.commit()
  653. repo = pagure.lib.get_project(self.session, 'foo')
  654. # Create private issue
  655. msg = pagure.lib.new_issue(
  656. session=self.session,
  657. repo=repo,
  658. title='Test issue',
  659. content='We should work on this',
  660. user='foo',
  661. ticketfolder=None,
  662. private=True,
  663. )
  664. self.session.commit()
  665. self.assertEqual(msg.title, 'Test issue')
  666. # Check status before
  667. repo = pagure.lib.get_project(self.session, 'test')
  668. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  669. self.assertEqual(issue.status, 'Open')
  670. data = {
  671. 'title': 'test issue',
  672. }
  673. # Incomplete request
  674. output = self.app.post(
  675. '/api/0/test/issue/1/status', data=data, headers=headers)
  676. self.assertEqual(output.status_code, 400)
  677. data = json.loads(output.data)
  678. self.assertDictEqual(
  679. data,
  680. {
  681. "error": "Invalid or incomplete input submited",
  682. "error_code": "EINVALIDREQ",
  683. }
  684. )
  685. # No change
  686. repo = pagure.lib.get_project(self.session, 'test')
  687. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  688. self.assertEqual(issue.status, 'Open')
  689. data = {
  690. 'status': 'Open',
  691. }
  692. # Valid request but no change
  693. output = self.app.post(
  694. '/api/0/test/issue/1/status', data=data, headers=headers)
  695. self.assertEqual(output.status_code, 200)
  696. data = json.loads(output.data)
  697. self.assertDictEqual(
  698. data,
  699. {'message': 'No changes'}
  700. )
  701. # No change
  702. repo = pagure.lib.get_project(self.session, 'test')
  703. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  704. self.assertEqual(issue.status, 'Open')
  705. data = {
  706. 'status': 'Fixed',
  707. }
  708. # Valid request
  709. output = self.app.post(
  710. '/api/0/test/issue/1/status', data=data, headers=headers)
  711. self.assertEqual(output.status_code, 200)
  712. data = json.loads(output.data)
  713. self.assertDictEqual(
  714. data,
  715. {'message': 'Successfully edited issue #1'}
  716. )
  717. headers = {'Authorization': 'token pingou_foo'}
  718. # Un-authorized issue
  719. output = self.app.post(
  720. '/api/0/foo/issue/1/status', data=data, headers=headers)
  721. self.assertEqual(output.status_code, 401)
  722. data = json.loads(output.data)
  723. self.assertDictEqual(
  724. data,
  725. {
  726. "error": "Invalid or expired token. Please "
  727. "visit https://pagure.org/ to get or renew your API token.",
  728. "error_code": "EINVALIDTOK"
  729. }
  730. )
  731. @patch('pagure.lib.git.update_git')
  732. @patch('pagure.lib.notify.send_email')
  733. def test_api_comment_issue(self, p_send_email, p_ugt):
  734. """ Test the api_comment_issue method of the flask api. """
  735. p_send_email.return_value = True
  736. p_ugt.return_value = True
  737. tests.create_projects(self.session)
  738. tests.create_tokens(self.session)
  739. tests.create_tokens_acl(self.session)
  740. headers = {'Authorization': 'token aaabbbcccddd'}
  741. # Invalid project
  742. output = self.app.post('/api/0/foo/issue/1/comment', headers=headers)
  743. self.assertEqual(output.status_code, 404)
  744. data = json.loads(output.data)
  745. self.assertDictEqual(
  746. data,
  747. {
  748. "error": "Project not found",
  749. "error_code": "ENOPROJECT",
  750. }
  751. )
  752. # Valid token, wrong project
  753. output = self.app.post('/api/0/test2/issue/1/comment', headers=headers)
  754. self.assertEqual(output.status_code, 401)
  755. data = json.loads(output.data)
  756. self.assertDictEqual(
  757. data,
  758. {
  759. "error": "Invalid or expired token. Please visit " \
  760. "https://pagure.org/ to get or renew your API token.",
  761. "error_code": "EINVALIDTOK",
  762. }
  763. )
  764. # No input
  765. output = self.app.post('/api/0/test/issue/1/comment', headers=headers)
  766. self.assertEqual(output.status_code, 404)
  767. data = json.loads(output.data)
  768. self.assertDictEqual(
  769. data,
  770. {
  771. "error": "Issue not found",
  772. "error_code": "ENOISSUE",
  773. }
  774. )
  775. # Create normal issue
  776. repo = pagure.lib.get_project(self.session, 'test')
  777. msg = pagure.lib.new_issue(
  778. session=self.session,
  779. repo=repo,
  780. title='Test issue #1',
  781. content='We should work on this',
  782. user='pingou',
  783. ticketfolder=None,
  784. private=False,
  785. issue_uid='aaabbbccc#1',
  786. )
  787. self.session.commit()
  788. self.assertEqual(msg.title, 'Test issue #1')
  789. # Check comments before
  790. repo = pagure.lib.get_project(self.session, 'test')
  791. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  792. self.assertEqual(len(issue.comments), 0)
  793. data = {
  794. 'title': 'test issue',
  795. }
  796. # Incomplete request
  797. output = self.app.post(
  798. '/api/0/test/issue/1/comment', data=data, headers=headers)
  799. self.assertEqual(output.status_code, 400)
  800. data = json.loads(output.data)
  801. self.assertDictEqual(
  802. data,
  803. {
  804. "error": "Invalid or incomplete input submited",
  805. "error_code": "EINVALIDREQ",
  806. }
  807. )
  808. # No change
  809. repo = pagure.lib.get_project(self.session, 'test')
  810. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  811. self.assertEqual(issue.status, 'Open')
  812. data = {
  813. 'comment': 'This is a very interesting question',
  814. }
  815. # Valid request
  816. output = self.app.post(
  817. '/api/0/test/issue/1/comment', data=data, headers=headers)
  818. self.assertEqual(output.status_code, 200)
  819. data = json.loads(output.data)
  820. self.assertDictEqual(
  821. data,
  822. {'message': 'Comment added'}
  823. )
  824. # One comment added
  825. repo = pagure.lib.get_project(self.session, 'test')
  826. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  827. self.assertEqual(len(issue.comments), 1)
  828. # Create another project
  829. item = pagure.lib.model.Project(
  830. user_id=2, # foo
  831. name='foo',
  832. description='test project #3',
  833. hook_token='aaabbbdddeee',
  834. )
  835. self.session.add(item)
  836. self.session.commit()
  837. # Create a token for pingou for this project
  838. item = pagure.lib.model.Token(
  839. id='pingou_foo',
  840. user_id=1,
  841. project_id=3,
  842. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  843. days=30)
  844. )
  845. self.session.add(item)
  846. self.session.commit()
  847. # Give `issue_change_status` to this token when `issue_comment`
  848. # is required
  849. item = pagure.lib.model.TokenAcl(
  850. token_id='pingou_foo',
  851. acl_id=2,
  852. )
  853. self.session.add(item)
  854. self.session.commit()
  855. repo = pagure.lib.get_project(self.session, 'foo')
  856. # Create private issue
  857. msg = pagure.lib.new_issue(
  858. session=self.session,
  859. repo=repo,
  860. title='Test issue',
  861. content='We should work on this',
  862. user='foo',
  863. ticketfolder=None,
  864. private=True,
  865. issue_uid='aaabbbccc#2',
  866. )
  867. self.session.commit()
  868. self.assertEqual(msg.title, 'Test issue')
  869. # Check before
  870. repo = pagure.lib.get_project(self.session, 'foo')
  871. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  872. self.assertEqual(len(issue.comments), 0)
  873. data = {
  874. 'comment': 'This is a very interesting question',
  875. }
  876. headers = {'Authorization': 'token pingou_foo'}
  877. # Valid request but un-authorized
  878. output = self.app.post(
  879. '/api/0/foo/issue/1/comment', data=data, headers=headers)
  880. self.assertEqual(output.status_code, 401)
  881. data = json.loads(output.data)
  882. self.assertDictEqual(
  883. data,
  884. {
  885. "error": "Invalid or expired token. Please "
  886. "visit https://pagure.org/ to get or renew your API token.",
  887. "error_code": "EINVALIDTOK"
  888. }
  889. )
  890. # No comment added
  891. repo = pagure.lib.get_project(self.session, 'foo')
  892. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  893. self.assertEqual(len(issue.comments), 0)
  894. # Create token for user foo
  895. item = pagure.lib.model.Token(
  896. id='foo_token2',
  897. user_id=2,
  898. project_id=3,
  899. expiration=datetime.datetime.utcnow() + datetime.timedelta(days=30)
  900. )
  901. self.session.add(item)
  902. self.session.commit()
  903. tests.create_tokens_acl(self.session, token_id='foo_token2')
  904. data = {
  905. 'comment': 'This is a very interesting question',
  906. }
  907. headers = {'Authorization': 'token foo_token2'}
  908. # Valid request and authorized
  909. output = self.app.post(
  910. '/api/0/foo/issue/1/comment', data=data, headers=headers)
  911. self.assertEqual(output.status_code, 200)
  912. data = json.loads(output.data)
  913. self.assertDictEqual(
  914. data,
  915. {'message': 'Comment added'}
  916. )
  917. @patch('pagure.lib.git.update_git')
  918. @patch('pagure.lib.notify.send_email')
  919. def test_api_view_issue_comment(self, p_send_email, p_ugt):
  920. """ Test the api_view_issue_comment endpoint. """
  921. p_send_email.return_value = True
  922. p_ugt.return_value = True
  923. self.test_api_comment_issue()
  924. # View a comment that does not exist
  925. output = self.app.get('/api/0/foo/issue/100/comment/2')
  926. self.assertEqual(output.status_code, 404)
  927. # Issue exists but not the comment
  928. output = self.app.get('/api/0/test/issue/1/comment/2')
  929. self.assertEqual(output.status_code, 404)
  930. # Issue and comment exists
  931. output = self.app.get('/api/0/test/issue/1/comment/1')
  932. self.assertEqual(output.status_code, 200)
  933. data = json.loads(output.data)
  934. data['date_created'] = '1435821770'
  935. data["comment_date"] = "2015-07-02 09:22"
  936. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  937. self.assertDictEqual(
  938. data,
  939. {
  940. "avatar_url": "https://seccdn.libravatar.org/avatar/...",
  941. "comment": "This is a very interesting question",
  942. "comment_date": "2015-07-02 09:22",
  943. "date_created": "1435821770",
  944. "edited_on": None,
  945. "editor": None,
  946. "notification": False,
  947. "id": 1,
  948. "parent": None,
  949. "user": {
  950. "fullname": "PY C",
  951. "name": "pingou"
  952. }
  953. }
  954. )
  955. # Issue and comment exists, using UID
  956. output = self.app.get('/api/0/test/issue/aaabbbccc#1/comment/1')
  957. self.assertEqual(output.status_code, 200)
  958. data = json.loads(output.data)
  959. data['date_created'] = '1435821770'
  960. data["comment_date"] = "2015-07-02 09:22"
  961. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  962. self.assertDictEqual(
  963. data,
  964. {
  965. "avatar_url": "https://seccdn.libravatar.org/avatar/...",
  966. "comment": "This is a very interesting question",
  967. "comment_date": "2015-07-02 09:22",
  968. "date_created": "1435821770",
  969. "edited_on": None,
  970. "editor": None,
  971. "notification": False,
  972. "id": 1,
  973. "parent": None,
  974. "user": {
  975. "fullname": "PY C",
  976. "name": "pingou"
  977. }
  978. }
  979. )
  980. # Private issue
  981. output = self.app.get('/api/0/foo/issue/1/comment/2')
  982. self.assertEqual(output.status_code, 403)
  983. # Private issue - Auth - wrong token
  984. headers = {'Authorization': 'token pingou_foo'}
  985. output = self.app.get('/api/0/foo/issue/1/comment/2', headers=headers)
  986. self.assertEqual(output.status_code, 403)
  987. # Private issue - Auth - Invalid token
  988. headers = {'Authorization': 'token aaabbbcccddd'}
  989. output = self.app.get('/api/0/foo/issue/1/comment/2', headers=headers)
  990. self.assertEqual(output.status_code, 401)
  991. # Private issue - Auth - valid token - unknown comment
  992. headers = {'Authorization': 'token foo_token2'}
  993. output = self.app.get('/api/0/foo/issue/1/comment/3', headers=headers)
  994. self.assertEqual(output.status_code, 404)
  995. # Private issue - Auth - valid token - known comment
  996. headers = {'Authorization': 'token foo_token2'}
  997. output = self.app.get('/api/0/foo/issue/1/comment/2', headers=headers)
  998. self.assertEqual(output.status_code, 200)
  999. data = json.loads(output.data)
  1000. data['date_created'] = '1435821770'
  1001. data["comment_date"] = "2015-07-02 09:22"
  1002. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  1003. self.assertDictEqual(
  1004. data,
  1005. {
  1006. "avatar_url": "https://seccdn.libravatar.org/avatar/...",
  1007. "comment": "This is a very interesting question",
  1008. "comment_date": "2015-07-02 09:22",
  1009. "date_created": "1435821770",
  1010. "edited_on": None,
  1011. "editor": None,
  1012. "notification": False,
  1013. "id": 2,
  1014. "parent": None,
  1015. "user": {
  1016. "fullname": "foo bar",
  1017. "name": "foo"
  1018. }
  1019. }
  1020. )
  1021. @patch('pagure.lib.git.update_git')
  1022. @patch('pagure.lib.notify.send_email')
  1023. def test_api_assign_issue(self, p_send_email, p_ugt):
  1024. """ Test the api_assign_issue method of the flask api. """
  1025. p_send_email.return_value = True
  1026. p_ugt.return_value = True
  1027. tests.create_projects(self.session)
  1028. tests.create_tokens(self.session)
  1029. tests.create_tokens_acl(self.session)
  1030. headers = {'Authorization': 'token aaabbbcccddd'}
  1031. # Invalid project
  1032. output = self.app.post('/api/0/foo/issue/1/assign', headers=headers)
  1033. self.assertEqual(output.status_code, 404)
  1034. data = json.loads(output.data)
  1035. self.assertDictEqual(
  1036. data,
  1037. {
  1038. "error": "Project not found",
  1039. "error_code": "ENOPROJECT",
  1040. }
  1041. )
  1042. # Valid token, wrong project
  1043. output = self.app.post('/api/0/test2/issue/1/assign', headers=headers)
  1044. self.assertEqual(output.status_code, 401)
  1045. data = json.loads(output.data)
  1046. self.assertDictEqual(
  1047. data,
  1048. {
  1049. "error": "Invalid or expired token. Please visit " \
  1050. "https://pagure.org/ to get or renew your API token.",
  1051. "error_code": "EINVALIDTOK",
  1052. }
  1053. )
  1054. # No input
  1055. output = self.app.post('/api/0/test/issue/1/assign', headers=headers)
  1056. self.assertEqual(output.status_code, 404)
  1057. data = json.loads(output.data)
  1058. self.assertDictEqual(
  1059. data,
  1060. {
  1061. "error": "Issue not found",
  1062. "error_code": "ENOISSUE",
  1063. }
  1064. )
  1065. # Create normal issue
  1066. repo = pagure.lib.get_project(self.session, 'test')
  1067. msg = pagure.lib.new_issue(
  1068. session=self.session,
  1069. repo=repo,
  1070. title='Test issue #1',
  1071. content='We should work on this',
  1072. user='pingou',
  1073. ticketfolder=None,
  1074. private=False,
  1075. issue_uid='aaabbbccc#1',
  1076. )
  1077. self.session.commit()
  1078. self.assertEqual(msg.title, 'Test issue #1')
  1079. # Check comments before
  1080. repo = pagure.lib.get_project(self.session, 'test')
  1081. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1082. self.assertEqual(len(issue.comments), 0)
  1083. data = {
  1084. 'title': 'test issue',
  1085. }
  1086. # Incomplete request
  1087. output = self.app.post(
  1088. '/api/0/test/issue/1/assign', data=data, headers=headers)
  1089. self.assertEqual(output.status_code, 400)
  1090. data = json.loads(output.data)
  1091. self.assertDictEqual(
  1092. data,
  1093. {
  1094. "error": "Invalid or incomplete input submited",
  1095. "error_code": "EINVALIDREQ",
  1096. }
  1097. )
  1098. # No change
  1099. repo = pagure.lib.get_project(self.session, 'test')
  1100. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1101. self.assertEqual(issue.status, 'Open')
  1102. data = {
  1103. 'assignee': 'pingou',
  1104. }
  1105. # Valid request
  1106. output = self.app.post(
  1107. '/api/0/test/issue/1/assign', data=data, headers=headers)
  1108. self.assertEqual(output.status_code, 200)
  1109. data = json.loads(output.data)
  1110. self.assertDictEqual(
  1111. data,
  1112. {'message': 'Issue assigned'}
  1113. )
  1114. # One comment added
  1115. repo = pagure.lib.get_project(self.session, 'test')
  1116. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1117. self.assertEqual(issue.assignee.user, 'pingou')
  1118. # Create another project
  1119. item = pagure.lib.model.Project(
  1120. user_id=2, # foo
  1121. name='foo',
  1122. description='test project #3',
  1123. hook_token='aaabbbdddeee',
  1124. )
  1125. self.session.add(item)
  1126. self.session.commit()
  1127. # Create a token for pingou for this project
  1128. item = pagure.lib.model.Token(
  1129. id='pingou_foo',
  1130. user_id=1,
  1131. project_id=3,
  1132. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  1133. days=30)
  1134. )
  1135. self.session.add(item)
  1136. self.session.commit()
  1137. # Give `issue_change_status` to this token when `issue_comment`
  1138. # is required
  1139. item = pagure.lib.model.TokenAcl(
  1140. token_id='pingou_foo',
  1141. acl_id=5,
  1142. )
  1143. self.session.add(item)
  1144. self.session.commit()
  1145. repo = pagure.lib.get_project(self.session, 'foo')
  1146. # Create private issue
  1147. msg = pagure.lib.new_issue(
  1148. session=self.session,
  1149. repo=repo,
  1150. title='Test issue',
  1151. content='We should work on this',
  1152. user='foo',
  1153. ticketfolder=None,
  1154. private=True,
  1155. issue_uid='aaabbbccc#2',
  1156. )
  1157. self.session.commit()
  1158. self.assertEqual(msg.title, 'Test issue')
  1159. # Check before
  1160. repo = pagure.lib.get_project(self.session, 'foo')
  1161. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1162. self.assertEqual(len(issue.comments), 0)
  1163. data = {
  1164. 'assignee': 'pingou',
  1165. }
  1166. headers = {'Authorization': 'token pingou_foo'}
  1167. # Valid request but un-authorized
  1168. output = self.app.post(
  1169. '/api/0/foo/issue/1/assign', data=data, headers=headers)
  1170. self.assertEqual(output.status_code, 401)
  1171. data = json.loads(output.data)
  1172. self.assertDictEqual(
  1173. data,
  1174. {
  1175. "error": "Invalid or expired token. Please "
  1176. "visit https://pagure.org/ to get or renew your API token.",
  1177. "error_code": "EINVALIDTOK"
  1178. }
  1179. )
  1180. # No comment added
  1181. repo = pagure.lib.get_project(self.session, 'foo')
  1182. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1183. self.assertEqual(len(issue.comments), 0)
  1184. # Create token for user foo
  1185. item = pagure.lib.model.Token(
  1186. id='foo_token2',
  1187. user_id=2,
  1188. project_id=3,
  1189. expiration=datetime.datetime.utcnow() + datetime.timedelta(days=30)
  1190. )
  1191. self.session.add(item)
  1192. self.session.commit()
  1193. tests.create_tokens_acl(self.session, token_id='foo_token2')
  1194. data = {
  1195. 'assignee': 'pingou',
  1196. }
  1197. headers = {'Authorization': 'token foo_token2'}
  1198. # Valid request and authorized
  1199. output = self.app.post(
  1200. '/api/0/foo/issue/1/assign', data=data, headers=headers)
  1201. self.assertEqual(output.status_code, 200)
  1202. data = json.loads(output.data)
  1203. self.assertDictEqual(
  1204. data,
  1205. {'message': 'Issue assigned'}
  1206. )
  1207. if __name__ == '__main__':
  1208. SUITE = unittest.TestLoader().loadTestsFromTestCase(
  1209. PagureFlaskApiIssuetests)
  1210. unittest.TextTestRunner(verbosity=2).run(SUITE)