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