test_pagure_flask_api_issue.py 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344
  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)