test_pagure_flask_api_fork.py 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. from __future__ import unicode_literals
  8. __requires__ = ['SQLAlchemy >= 0.8']
  9. import pkg_resources
  10. import datetime
  11. import unittest
  12. import shutil
  13. import sys
  14. import os
  15. import json
  16. from mock import patch, MagicMock
  17. sys.path.insert(0, os.path.join(os.path.dirname(
  18. os.path.abspath(__file__)), '..'))
  19. import pagure
  20. import pagure.lib
  21. import tests
  22. class PagureFlaskApiForktests(tests.Modeltests):
  23. """ Tests for the flask API of pagure for issue """
  24. maxDiff = None
  25. def setUp(self):
  26. """ Set up the environnment, ran before every tests. """
  27. super(PagureFlaskApiForktests, self).setUp()
  28. pagure.config.config['REQUESTS_FOLDER'] = None
  29. @patch('pagure.lib.notify.send_email')
  30. def test_api_pull_request_views(self, send_email):
  31. """ Test the api_pull_request_views method of the flask api. """
  32. send_email.return_value = True
  33. tests.create_projects(self.session)
  34. tests.create_tokens(self.session)
  35. tests.create_tokens_acl(self.session)
  36. # Create a pull-request
  37. repo = pagure.lib.get_authorized_project(self.session, 'test')
  38. forked_repo = pagure.lib.get_authorized_project(
  39. self.session, 'test')
  40. req = pagure.lib.new_pull_request(
  41. session=self.session,
  42. repo_from=forked_repo,
  43. branch_from='master',
  44. repo_to=repo,
  45. branch_to='master',
  46. title='test pull-request',
  47. user='pingou',
  48. requestfolder=None,
  49. )
  50. self.session.commit()
  51. self.assertEqual(req.id, 1)
  52. self.assertEqual(req.title, 'test pull-request')
  53. # Invalid repo
  54. output = self.app.get('/api/0/foo/pull-requests')
  55. self.assertEqual(output.status_code, 404)
  56. data = json.loads(output.get_data(as_text=True))
  57. self.assertDictEqual(
  58. data,
  59. {
  60. "error": "Project not found",
  61. "error_code": "ENOPROJECT",
  62. }
  63. )
  64. # List pull-requests
  65. output = self.app.get('/api/0/test/pull-requests')
  66. self.assertEqual(output.status_code, 200)
  67. data = json.loads(output.get_data(as_text=True))
  68. data['requests'][0]['date_created'] = '1431414800'
  69. data['requests'][0]['updated_on'] = '1431414800'
  70. data['requests'][0]['project']['date_created'] = '1431414800'
  71. data['requests'][0]['project']['date_modified'] = '1431414800'
  72. data['requests'][0]['repo_from']['date_created'] = '1431414800'
  73. data['requests'][0]['repo_from']['date_modified'] = '1431414800'
  74. data['requests'][0]['uid'] = '1431414800'
  75. data['requests'][0]['last_updated'] = '1431414800'
  76. expected_data = {
  77. "args": {
  78. "assignee": None,
  79. "author": None,
  80. "status": True
  81. },
  82. "requests": [{
  83. "assignee": None,
  84. "branch": "master",
  85. "branch_from": "master",
  86. "cached_merge_status": "unknown",
  87. "closed_at": None,
  88. "closed_by": None,
  89. "comments": [],
  90. "commit_start": None,
  91. "commit_stop": None,
  92. "date_created": "1431414800",
  93. "id": 1,
  94. "initial_comment": None,
  95. "last_updated": "1431414800",
  96. "project": {
  97. "access_groups": {
  98. "admin": [],
  99. "commit": [],
  100. "ticket": []
  101. },
  102. "access_users": {
  103. "admin": [],
  104. "commit": [],
  105. "owner": ["pingou"],
  106. "ticket": []
  107. },
  108. "close_status": [
  109. "Invalid",
  110. "Insufficient data",
  111. "Fixed",
  112. "Duplicate"
  113. ],
  114. "custom_keys": [],
  115. "date_created": "1431414800",
  116. "date_modified": "1431414800",
  117. "description": "test project #1",
  118. "fullname": "test",
  119. "url_path": "test",
  120. "id": 1,
  121. "milestones": {},
  122. "name": "test",
  123. "namespace": None,
  124. "parent": None,
  125. "priorities": {},
  126. "tags": [],
  127. "user": {
  128. "fullname": "PY C",
  129. "name": "pingou"
  130. }
  131. },
  132. "remote_git": None,
  133. "repo_from": {
  134. "access_groups": {
  135. "admin": [],
  136. "commit": [],
  137. "ticket": []},
  138. "access_users": {
  139. "admin": [],
  140. "commit": [],
  141. "owner": ["pingou"],
  142. "ticket": []
  143. },
  144. "close_status": [
  145. "Invalid",
  146. "Insufficient data",
  147. "Fixed",
  148. "Duplicate"
  149. ],
  150. "custom_keys": [],
  151. "date_created": "1431414800",
  152. "date_modified": "1431414800",
  153. "description": "test project #1",
  154. "fullname": "test",
  155. "url_path": "test",
  156. "id": 1,
  157. "milestones": {},
  158. "name": "test",
  159. "namespace": None,
  160. "parent": None,
  161. "priorities": {},
  162. "tags": [],
  163. "user": {
  164. "fullname": "PY C",
  165. "name": "pingou"
  166. }
  167. },
  168. "status": "Open",
  169. "title": "test pull-request",
  170. "uid": "1431414800",
  171. "updated_on": "1431414800",
  172. "user": {
  173. "fullname": "PY C",
  174. "name": "pingou"
  175. }
  176. }],
  177. "total_requests": 1
  178. }
  179. self.assertDictEqual(data, expected_data)
  180. headers = {'Authorization': 'token aaabbbcccddd'}
  181. # Access Pull-Request authenticated
  182. output = self.app.get('/api/0/test/pull-requests', headers=headers)
  183. self.assertEqual(output.status_code, 200)
  184. data2 = json.loads(output.get_data(as_text=True))
  185. data2['requests'][0]['date_created'] = '1431414800'
  186. data2['requests'][0]['updated_on'] = '1431414800'
  187. data2['requests'][0]['project']['date_created'] = '1431414800'
  188. data2['requests'][0]['project']['date_modified'] = '1431414800'
  189. data2['requests'][0]['repo_from']['date_created'] = '1431414800'
  190. data2['requests'][0]['repo_from']['date_modified'] = '1431414800'
  191. data2['requests'][0]['uid'] = '1431414800'
  192. data2['requests'][0]['last_updated'] = '1431414800'
  193. self.assertDictEqual(data, data2)
  194. @patch('pagure.lib.notify.send_email')
  195. def test_api_pull_request_view(self, send_email):
  196. """ Test the api_pull_request_view method of the flask api. """
  197. send_email.return_value = True
  198. tests.create_projects(self.session)
  199. tests.create_tokens(self.session)
  200. tests.create_tokens_acl(self.session)
  201. # Create a pull-request
  202. repo = pagure.lib.get_authorized_project(self.session, 'test')
  203. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  204. req = pagure.lib.new_pull_request(
  205. session=self.session,
  206. repo_from=forked_repo,
  207. branch_from='master',
  208. repo_to=repo,
  209. branch_to='master',
  210. title='test pull-request',
  211. user='pingou',
  212. requestfolder=None,
  213. )
  214. self.session.commit()
  215. self.assertEqual(req.id, 1)
  216. self.assertEqual(req.title, 'test pull-request')
  217. # Invalid repo
  218. output = self.app.get('/api/0/foo/pull-request/1')
  219. self.assertEqual(output.status_code, 404)
  220. data = json.loads(output.get_data(as_text=True))
  221. self.assertDictEqual(
  222. data,
  223. {
  224. "error": "Project not found",
  225. "error_code": "ENOPROJECT",
  226. }
  227. )
  228. # Invalid issue for this repo
  229. output = self.app.get('/api/0/test2/pull-request/1')
  230. self.assertEqual(output.status_code, 404)
  231. data = json.loads(output.get_data(as_text=True))
  232. self.assertDictEqual(
  233. data,
  234. {
  235. "error": "Pull-Request not found",
  236. "error_code": "ENOREQ",
  237. }
  238. )
  239. # Valid issue
  240. output = self.app.get('/api/0/test/pull-request/1')
  241. self.assertEqual(output.status_code, 200)
  242. data = json.loads(output.get_data(as_text=True))
  243. data['date_created'] = '1431414800'
  244. data['updated_on'] = '1431414800'
  245. data['project']['date_created'] = '1431414800'
  246. data['project']['date_modified'] = '1431414800'
  247. data['repo_from']['date_created'] = '1431414800'
  248. data['repo_from']['date_modified'] = '1431414800'
  249. data['uid'] = '1431414800'
  250. data['last_updated'] = '1431414800'
  251. expected_data = {
  252. "assignee": None,
  253. "branch": "master",
  254. "branch_from": "master",
  255. "cached_merge_status": "unknown",
  256. "closed_at": None,
  257. "closed_by": None,
  258. "comments": [],
  259. "commit_start": None,
  260. "commit_stop": None,
  261. "date_created": "1431414800",
  262. "id": 1,
  263. "initial_comment": None,
  264. "last_updated": "1431414800",
  265. "project": {
  266. "access_groups": {
  267. "admin": [],
  268. "commit": [],
  269. "ticket": []
  270. },
  271. "access_users": {
  272. "admin": [],
  273. "commit": [],
  274. "owner": ["pingou"],
  275. "ticket": []
  276. },
  277. "close_status": [
  278. "Invalid",
  279. "Insufficient data",
  280. "Fixed",
  281. "Duplicate"
  282. ],
  283. "custom_keys": [],
  284. "date_created": "1431414800",
  285. "date_modified": "1431414800",
  286. "description": "test project #1",
  287. "fullname": "test",
  288. "url_path": "test",
  289. "id": 1,
  290. "milestones": {},
  291. "name": "test",
  292. "namespace": None,
  293. "parent": None,
  294. "priorities": {},
  295. "tags": [],
  296. "user": {
  297. "fullname": "PY C",
  298. "name": "pingou"
  299. }
  300. },
  301. "remote_git": None,
  302. "repo_from": {
  303. "access_groups": {
  304. "admin": [],
  305. "commit": [],
  306. "ticket": []},
  307. "access_users": {
  308. "admin": [],
  309. "commit": [],
  310. "owner": ["pingou"],
  311. "ticket": []},
  312. "close_status": [
  313. "Invalid",
  314. "Insufficient data",
  315. "Fixed",
  316. "Duplicate"],
  317. "custom_keys": [],
  318. "date_created": "1431414800",
  319. "date_modified": "1431414800",
  320. "description": "test project #1",
  321. "fullname": "test",
  322. "url_path": "test",
  323. "id": 1,
  324. "milestones": {},
  325. "name": "test",
  326. "namespace": None,
  327. "parent": None,
  328. "priorities": {},
  329. "tags": [],
  330. "user": {
  331. "fullname": "PY C",
  332. "name": "pingou"
  333. }
  334. },
  335. "status": "Open",
  336. "title": "test pull-request",
  337. "uid": "1431414800",
  338. "updated_on": "1431414800",
  339. "user": {
  340. "fullname": "PY C",
  341. "name": "pingou"
  342. }
  343. }
  344. self.assertDictEqual(data, expected_data)
  345. headers = {'Authorization': 'token aaabbbcccddd'}
  346. # Access Pull-Request authenticated
  347. output = self.app.get('/api/0/test/pull-request/1', headers=headers)
  348. self.assertEqual(output.status_code, 200)
  349. data2 = json.loads(output.get_data(as_text=True))
  350. data2['date_created'] = '1431414800'
  351. data2['project']['date_created'] = '1431414800'
  352. data2['project']['date_modified'] = '1431414800'
  353. data2['repo_from']['date_created'] = '1431414800'
  354. data2['repo_from']['date_modified'] = '1431414800'
  355. data2['uid'] = '1431414800'
  356. data2['date_created'] = '1431414800'
  357. data2['updated_on'] = '1431414800'
  358. data2['last_updated'] = '1431414800'
  359. self.assertDictEqual(data, data2)
  360. @patch('pagure.lib.notify.send_email')
  361. def test_api_pull_request_close(self, send_email):
  362. """ Test the api_pull_request_close method of the flask api. """
  363. send_email.return_value = True
  364. tests.create_projects(self.session)
  365. tests.create_tokens(self.session)
  366. tests.create_tokens_acl(self.session)
  367. # Create the pull-request to close
  368. repo = pagure.lib.get_authorized_project(self.session, 'test')
  369. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  370. req = pagure.lib.new_pull_request(
  371. session=self.session,
  372. repo_from=forked_repo,
  373. branch_from='master',
  374. repo_to=repo,
  375. branch_to='master',
  376. title='test pull-request',
  377. user='pingou',
  378. requestfolder=None,
  379. )
  380. self.session.commit()
  381. self.assertEqual(req.id, 1)
  382. self.assertEqual(req.title, 'test pull-request')
  383. headers = {'Authorization': 'token aaabbbcccddd'}
  384. # Invalid project
  385. output = self.app.post(
  386. '/api/0/foo/pull-request/1/close', headers=headers)
  387. self.assertEqual(output.status_code, 404)
  388. data = json.loads(output.get_data(as_text=True))
  389. self.assertDictEqual(
  390. data,
  391. {
  392. "error": "Project not found",
  393. "error_code": "ENOPROJECT",
  394. }
  395. )
  396. # Valid token, wrong project
  397. output = self.app.post(
  398. '/api/0/test2/pull-request/1/close', headers=headers)
  399. self.assertEqual(output.status_code, 401)
  400. data = json.loads(output.get_data(as_text=True))
  401. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  402. data['error_code'])
  403. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  404. # Invalid PR
  405. output = self.app.post(
  406. '/api/0/test/pull-request/2/close', headers=headers)
  407. self.assertEqual(output.status_code, 404)
  408. data = json.loads(output.get_data(as_text=True))
  409. self.assertDictEqual(
  410. data,
  411. {'error': 'Pull-Request not found', 'error_code': "ENOREQ"}
  412. )
  413. # Create a token for foo for this project
  414. item = pagure.lib.model.Token(
  415. id='foobar_token',
  416. user_id=2,
  417. project_id=1,
  418. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  419. days=30)
  420. )
  421. self.session.add(item)
  422. self.session.commit()
  423. # Allow the token to close PR
  424. acls = pagure.lib.get_acls(self.session)
  425. for acl in acls:
  426. if acl.name == 'pull_request_close':
  427. break
  428. item = pagure.lib.model.TokenAcl(
  429. token_id='foobar_token',
  430. acl_id=acl.id,
  431. )
  432. self.session.add(item)
  433. self.session.commit()
  434. headers = {'Authorization': 'token foobar_token'}
  435. # User not admin
  436. output = self.app.post(
  437. '/api/0/test/pull-request/1/close', headers=headers)
  438. self.assertEqual(output.status_code, 403)
  439. data = json.loads(output.get_data(as_text=True))
  440. self.assertDictEqual(
  441. data,
  442. {
  443. 'error': 'You are not allowed to merge/close pull-request '
  444. 'for this project',
  445. 'error_code': "ENOPRCLOSE",
  446. }
  447. )
  448. headers = {'Authorization': 'token aaabbbcccddd'}
  449. # Close PR
  450. output = self.app.post(
  451. '/api/0/test/pull-request/1/close', headers=headers)
  452. self.assertEqual(output.status_code, 200)
  453. data = json.loads(output.get_data(as_text=True))
  454. self.assertDictEqual(
  455. data,
  456. {"message": "Pull-request closed!"}
  457. )
  458. @patch('pagure.lib.notify.send_email')
  459. def test_api_pull_request_merge(self, send_email):
  460. """ Test the api_pull_request_merge method of the flask api. """
  461. send_email.return_value = True
  462. tests.create_projects(self.session)
  463. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  464. tests.create_projects_git(os.path.join(self.path, 'requests'),
  465. bare=True)
  466. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  467. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  468. branch='test')
  469. tests.create_tokens(self.session)
  470. tests.create_tokens_acl(self.session)
  471. # Create the pull-request to close
  472. repo = pagure.lib.get_authorized_project(self.session, 'test')
  473. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  474. req = pagure.lib.new_pull_request(
  475. session=self.session,
  476. repo_from=forked_repo,
  477. branch_from='test',
  478. repo_to=repo,
  479. branch_to='master',
  480. title='test pull-request',
  481. user='pingou',
  482. requestfolder=None,
  483. )
  484. self.session.commit()
  485. self.assertEqual(req.id, 1)
  486. self.assertEqual(req.title, 'test pull-request')
  487. headers = {'Authorization': 'token aaabbbcccddd'}
  488. # Invalid project
  489. output = self.app.post(
  490. '/api/0/foo/pull-request/1/merge', headers=headers)
  491. self.assertEqual(output.status_code, 404)
  492. data = json.loads(output.get_data(as_text=True))
  493. self.assertDictEqual(
  494. data,
  495. {
  496. "error": "Project not found",
  497. "error_code": "ENOPROJECT",
  498. }
  499. )
  500. # Valid token, wrong project
  501. output = self.app.post(
  502. '/api/0/test2/pull-request/1/merge', headers=headers)
  503. self.assertEqual(output.status_code, 401)
  504. data = json.loads(output.get_data(as_text=True))
  505. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  506. data['error_code'])
  507. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  508. # Invalid PR
  509. output = self.app.post(
  510. '/api/0/test/pull-request/2/merge', headers=headers)
  511. self.assertEqual(output.status_code, 404)
  512. data = json.loads(output.get_data(as_text=True))
  513. self.assertDictEqual(
  514. data,
  515. {'error': 'Pull-Request not found', 'error_code': "ENOREQ"}
  516. )
  517. # Create a token for foo for this project
  518. item = pagure.lib.model.Token(
  519. id='foobar_token',
  520. user_id=2,
  521. project_id=1,
  522. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  523. days=30)
  524. )
  525. self.session.add(item)
  526. self.session.commit()
  527. # Allow the token to merge PR
  528. acls = pagure.lib.get_acls(self.session)
  529. for acl in acls:
  530. if acl.name == 'pull_request_merge':
  531. break
  532. item = pagure.lib.model.TokenAcl(
  533. token_id='foobar_token',
  534. acl_id=acl.id,
  535. )
  536. self.session.add(item)
  537. self.session.commit()
  538. headers = {'Authorization': 'token foobar_token'}
  539. # User not admin
  540. output = self.app.post(
  541. '/api/0/test/pull-request/1/merge', headers=headers)
  542. self.assertEqual(output.status_code, 403)
  543. data = json.loads(output.get_data(as_text=True))
  544. self.assertDictEqual(
  545. data,
  546. {
  547. 'error': 'You are not allowed to merge/close pull-request '
  548. 'for this project',
  549. 'error_code': "ENOPRCLOSE",
  550. }
  551. )
  552. headers = {'Authorization': 'token aaabbbcccddd'}
  553. # Merge PR
  554. output = self.app.post(
  555. '/api/0/test/pull-request/1/merge', headers=headers)
  556. self.assertEqual(output.status_code, 200)
  557. data = json.loads(output.get_data(as_text=True))
  558. self.assertDictEqual(
  559. data,
  560. {"message": "Changes merged!"}
  561. )
  562. @patch('pagure.lib.notify.send_email')
  563. def test_api_pull_request_merge_user_token(self, send_email):
  564. """ Test the api_pull_request_merge method of the flask api. """
  565. send_email.return_value = True
  566. tests.create_projects(self.session)
  567. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  568. tests.create_projects_git(os.path.join(self.path, 'requests'),
  569. bare=True)
  570. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  571. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  572. branch='test')
  573. tests.create_tokens(self.session, project_id=None)
  574. tests.create_tokens_acl(self.session)
  575. # Create the pull-request to close
  576. repo = pagure.lib.get_authorized_project(self.session, 'test')
  577. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  578. req = pagure.lib.new_pull_request(
  579. session=self.session,
  580. repo_from=forked_repo,
  581. branch_from='test',
  582. repo_to=repo,
  583. branch_to='master',
  584. title='test pull-request',
  585. user='pingou',
  586. requestfolder=None,
  587. )
  588. self.session.commit()
  589. self.assertEqual(req.id, 1)
  590. self.assertEqual(req.title, 'test pull-request')
  591. headers = {'Authorization': 'token aaabbbcccddd'}
  592. # Invalid project
  593. output = self.app.post(
  594. '/api/0/foo/pull-request/1/merge', headers=headers)
  595. self.assertEqual(output.status_code, 404)
  596. data = json.loads(output.get_data(as_text=True))
  597. self.assertDictEqual(
  598. data,
  599. {
  600. "error": "Project not found",
  601. "error_code": "ENOPROJECT",
  602. }
  603. )
  604. # Valid token, invalid PR
  605. output = self.app.post(
  606. '/api/0/test2/pull-request/1/merge', headers=headers)
  607. self.assertEqual(output.status_code, 404)
  608. data = json.loads(output.get_data(as_text=True))
  609. self.assertDictEqual(
  610. data,
  611. {'error': 'Pull-Request not found', 'error_code': "ENOREQ"}
  612. )
  613. # Valid token, invalid PR - other project
  614. output = self.app.post(
  615. '/api/0/test/pull-request/2/merge', headers=headers)
  616. self.assertEqual(output.status_code, 404)
  617. data = json.loads(output.get_data(as_text=True))
  618. self.assertDictEqual(
  619. data,
  620. {'error': 'Pull-Request not found', 'error_code': "ENOREQ"}
  621. )
  622. # Create a token for foo for this project
  623. item = pagure.lib.model.Token(
  624. id='foobar_token',
  625. user_id=2,
  626. project_id=1,
  627. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  628. days=30)
  629. )
  630. self.session.add(item)
  631. self.session.commit()
  632. # Allow the token to merge PR
  633. acls = pagure.lib.get_acls(self.session)
  634. acl = None
  635. for acl in acls:
  636. if acl.name == 'pull_request_merge':
  637. break
  638. item = pagure.lib.model.TokenAcl(
  639. token_id='foobar_token',
  640. acl_id=acl.id,
  641. )
  642. self.session.add(item)
  643. self.session.commit()
  644. headers = {'Authorization': 'token foobar_token'}
  645. # User not admin
  646. output = self.app.post(
  647. '/api/0/test/pull-request/1/merge', headers=headers)
  648. self.assertEqual(output.status_code, 403)
  649. data = json.loads(output.get_data(as_text=True))
  650. self.assertDictEqual(
  651. data,
  652. {
  653. 'error': 'You are not allowed to merge/close pull-request '
  654. 'for this project',
  655. 'error_code': "ENOPRCLOSE",
  656. }
  657. )
  658. headers = {'Authorization': 'token aaabbbcccddd'}
  659. # Merge PR
  660. output = self.app.post(
  661. '/api/0/test/pull-request/1/merge', headers=headers)
  662. self.assertEqual(output.status_code, 200)
  663. data = json.loads(output.get_data(as_text=True))
  664. self.assertDictEqual(
  665. data,
  666. {"message": "Changes merged!"}
  667. )
  668. @patch('pagure.lib.notify.send_email')
  669. def test_api_pull_request_add_comment(self, mockemail):
  670. """ Test the api_pull_request_add_comment method of the flask api. """
  671. mockemail.return_value = True
  672. tests.create_projects(self.session)
  673. tests.create_tokens(self.session)
  674. tests.create_tokens_acl(self.session)
  675. headers = {'Authorization': 'token aaabbbcccddd'}
  676. # Invalid project
  677. output = self.app.post(
  678. '/api/0/foo/pull-request/1/comment', headers=headers)
  679. self.assertEqual(output.status_code, 404)
  680. data = json.loads(output.get_data(as_text=True))
  681. self.assertDictEqual(
  682. data,
  683. {
  684. "error": "Project not found",
  685. "error_code": "ENOPROJECT",
  686. }
  687. )
  688. # Valid token, wrong project
  689. output = self.app.post(
  690. '/api/0/test2/pull-request/1/comment', headers=headers)
  691. self.assertEqual(output.status_code, 401)
  692. data = json.loads(output.get_data(as_text=True))
  693. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  694. data['error_code'])
  695. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  696. # No input
  697. output = self.app.post(
  698. '/api/0/test/pull-request/1/comment', headers=headers)
  699. self.assertEqual(output.status_code, 404)
  700. data = json.loads(output.get_data(as_text=True))
  701. self.assertDictEqual(
  702. data,
  703. {
  704. "error": "Pull-Request not found",
  705. "error_code": "ENOREQ",
  706. }
  707. )
  708. # Create a pull-request
  709. repo = pagure.lib.get_authorized_project(self.session, 'test')
  710. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  711. req = pagure.lib.new_pull_request(
  712. session=self.session,
  713. repo_from=forked_repo,
  714. branch_from='master',
  715. repo_to=repo,
  716. branch_to='master',
  717. title='test pull-request',
  718. user='pingou',
  719. requestfolder=None,
  720. )
  721. self.session.commit()
  722. self.assertEqual(req.id, 1)
  723. self.assertEqual(req.title, 'test pull-request')
  724. # Check comments before
  725. self.session.commit()
  726. request = pagure.lib.search_pull_requests(
  727. self.session, project_id=1, requestid=1)
  728. self.assertEqual(len(request.comments), 0)
  729. data = {
  730. 'title': 'test issue',
  731. }
  732. # Incomplete request
  733. output = self.app.post(
  734. '/api/0/test/pull-request/1/comment', data=data, headers=headers)
  735. self.assertEqual(output.status_code, 400)
  736. data = json.loads(output.get_data(as_text=True))
  737. self.assertDictEqual(
  738. data,
  739. {
  740. "error": "Invalid or incomplete input submitted",
  741. "error_code": "EINVALIDREQ",
  742. "errors": {"comment": ["This field is required."]}
  743. }
  744. )
  745. # No change
  746. self.session.commit()
  747. request = pagure.lib.search_pull_requests(
  748. self.session, project_id=1, requestid=1)
  749. self.assertEqual(len(request.comments), 0)
  750. data = {
  751. 'comment': 'This is a very interesting question',
  752. }
  753. # Valid request
  754. output = self.app.post(
  755. '/api/0/test/pull-request/1/comment', data=data, headers=headers)
  756. self.assertEqual(output.status_code, 200)
  757. data = json.loads(output.get_data(as_text=True))
  758. self.assertDictEqual(
  759. data,
  760. {'message': 'Comment added'}
  761. )
  762. # One comment added
  763. self.session.commit()
  764. request = pagure.lib.search_pull_requests(
  765. self.session, project_id=1, requestid=1)
  766. self.assertEqual(len(request.comments), 1)
  767. @patch('pagure.lib.notify.send_email')
  768. def test_api_pull_request_add_comment_user_token(self, mockemail):
  769. """ Test the api_pull_request_add_comment method of the flask api. """
  770. mockemail.return_value = True
  771. tests.create_projects(self.session)
  772. tests.create_tokens(self.session, project_id=None)
  773. tests.create_tokens_acl(self.session)
  774. headers = {'Authorization': 'token aaabbbcccddd'}
  775. # Invalid project
  776. output = self.app.post(
  777. '/api/0/foo/pull-request/1/comment', headers=headers)
  778. self.assertEqual(output.status_code, 404)
  779. data = json.loads(output.get_data(as_text=True))
  780. self.assertDictEqual(
  781. data,
  782. {
  783. "error": "Project not found",
  784. "error_code": "ENOPROJECT",
  785. }
  786. )
  787. # Valid token, invalid request
  788. output = self.app.post(
  789. '/api/0/test2/pull-request/1/comment', headers=headers)
  790. self.assertEqual(output.status_code, 404)
  791. data = json.loads(output.get_data(as_text=True))
  792. self.assertDictEqual(
  793. data,
  794. {
  795. "error": "Pull-Request not found",
  796. "error_code": "ENOREQ",
  797. }
  798. )
  799. # Valid token, invalid request in another project
  800. output = self.app.post(
  801. '/api/0/test/pull-request/1/comment', headers=headers)
  802. self.assertEqual(output.status_code, 404)
  803. data = json.loads(output.get_data(as_text=True))
  804. self.assertDictEqual(
  805. data,
  806. {
  807. "error": "Pull-Request not found",
  808. "error_code": "ENOREQ",
  809. }
  810. )
  811. # Create a pull-request
  812. repo = pagure.lib.get_authorized_project(self.session, 'test')
  813. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  814. req = pagure.lib.new_pull_request(
  815. session=self.session,
  816. repo_from=forked_repo,
  817. branch_from='master',
  818. repo_to=repo,
  819. branch_to='master',
  820. title='test pull-request',
  821. user='pingou',
  822. requestfolder=None,
  823. )
  824. self.session.commit()
  825. self.assertEqual(req.id, 1)
  826. self.assertEqual(req.title, 'test pull-request')
  827. # Check comments before
  828. self.session.commit()
  829. request = pagure.lib.search_pull_requests(
  830. self.session, project_id=1, requestid=1)
  831. self.assertEqual(len(request.comments), 0)
  832. data = {
  833. 'title': 'test issue',
  834. }
  835. # Incomplete request
  836. output = self.app.post(
  837. '/api/0/test/pull-request/1/comment', data=data, headers=headers)
  838. self.assertEqual(output.status_code, 400)
  839. data = json.loads(output.get_data(as_text=True))
  840. self.assertDictEqual(
  841. data,
  842. {
  843. "error": "Invalid or incomplete input submitted",
  844. "error_code": "EINVALIDREQ",
  845. "errors": {"comment": ["This field is required."]}
  846. }
  847. )
  848. # No change
  849. self.session.commit()
  850. request = pagure.lib.search_pull_requests(
  851. self.session, project_id=1, requestid=1)
  852. self.assertEqual(len(request.comments), 0)
  853. data = {
  854. 'comment': 'This is a very interesting question',
  855. }
  856. # Valid request
  857. output = self.app.post(
  858. '/api/0/test/pull-request/1/comment', data=data, headers=headers)
  859. self.assertEqual(output.status_code, 200)
  860. data = json.loads(output.get_data(as_text=True))
  861. self.assertDictEqual(
  862. data,
  863. {'message': 'Comment added'}
  864. )
  865. # One comment added
  866. self.session.commit()
  867. request = pagure.lib.search_pull_requests(
  868. self.session, project_id=1, requestid=1)
  869. self.assertEqual(len(request.comments), 1)
  870. @patch('pagure.lib.git.update_git')
  871. @patch('pagure.lib.notify.send_email')
  872. def test_api_subscribe_pull_request(self, p_send_email, p_ugt):
  873. """ Test the api_subscribe_pull_request method of the flask api. """
  874. p_send_email.return_value = True
  875. p_ugt.return_value = True
  876. item = pagure.lib.model.User(
  877. user='bar',
  878. fullname='bar foo',
  879. password='foo',
  880. default_email='bar@bar.com',
  881. )
  882. self.session.add(item)
  883. item = pagure.lib.model.UserEmail(
  884. user_id=3,
  885. email='bar@bar.com')
  886. self.session.add(item)
  887. self.session.commit()
  888. tests.create_projects(self.session)
  889. tests.create_tokens(self.session, user_id=3)
  890. tests.create_tokens_acl(self.session)
  891. headers = {'Authorization': 'token aaabbbcccddd'}
  892. # Invalid project
  893. output = self.app.post(
  894. '/api/0/foo/pull-request/1/subscribe', headers=headers)
  895. self.assertEqual(output.status_code, 404)
  896. data = json.loads(output.get_data(as_text=True))
  897. self.assertDictEqual(
  898. data,
  899. {
  900. "error": "Project not found",
  901. "error_code": "ENOPROJECT",
  902. }
  903. )
  904. # Valid token, wrong project
  905. output = self.app.post(
  906. '/api/0/test2/pull-request/1/subscribe', headers=headers)
  907. self.assertEqual(output.status_code, 401)
  908. data = json.loads(output.get_data(as_text=True))
  909. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  910. data['error_code'])
  911. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  912. # No input
  913. output = self.app.post(
  914. '/api/0/test/pull-request/1/subscribe', headers=headers)
  915. self.assertEqual(output.status_code, 404)
  916. data = json.loads(output.get_data(as_text=True))
  917. self.assertDictEqual(
  918. data,
  919. {
  920. 'error': 'Pull-Request not found',
  921. 'error_code': 'ENOREQ'
  922. }
  923. )
  924. # Create pull-request
  925. repo = pagure.lib.get_authorized_project(self.session, 'test')
  926. req = pagure.lib.new_pull_request(
  927. session=self.session,
  928. repo_from=repo,
  929. branch_from='feature',
  930. repo_to=repo,
  931. branch_to='master',
  932. title='test pull-request',
  933. user='pingou',
  934. requestfolder=None,
  935. )
  936. self.session.commit()
  937. self.assertEqual(req.id, 1)
  938. self.assertEqual(req.title, 'test pull-request')
  939. # Check subscribtion before
  940. repo = pagure.lib.get_authorized_project(self.session, 'test')
  941. request = pagure.lib.search_pull_requests(
  942. self.session, project_id=1, requestid=1)
  943. self.assertEqual(
  944. pagure.lib.get_watch_list(self.session, request),
  945. set(['pingou']))
  946. # Unsubscribe - no changes
  947. data = {}
  948. output = self.app.post(
  949. '/api/0/test/pull-request/1/subscribe',
  950. data=data, headers=headers)
  951. self.assertEqual(output.status_code, 200)
  952. data = json.loads(output.get_data(as_text=True))
  953. self.assertDictEqual(
  954. data,
  955. {'message': 'You are no longer watching this pull-request'}
  956. )
  957. data = {}
  958. output = self.app.post(
  959. '/api/0/test/pull-request/1/subscribe',
  960. data=data, headers=headers)
  961. self.assertEqual(output.status_code, 200)
  962. data = json.loads(output.get_data(as_text=True))
  963. self.assertDictEqual(
  964. data,
  965. {'message': 'You are no longer watching this pull-request'}
  966. )
  967. # No change
  968. repo = pagure.lib.get_authorized_project(self.session, 'test')
  969. request = pagure.lib.search_pull_requests(
  970. self.session, project_id=1, requestid=1)
  971. self.assertEqual(
  972. pagure.lib.get_watch_list(self.session, request),
  973. set(['pingou']))
  974. # Subscribe
  975. data = {'status': True}
  976. output = self.app.post(
  977. '/api/0/test/pull-request/1/subscribe',
  978. data=data, headers=headers)
  979. self.assertEqual(output.status_code, 200)
  980. data = json.loads(output.get_data(as_text=True))
  981. self.assertDictEqual(
  982. data,
  983. {'message': 'You are now watching this pull-request'}
  984. )
  985. # Subscribe - no changes
  986. data = {'status': True}
  987. output = self.app.post(
  988. '/api/0/test/pull-request/1/subscribe',
  989. data=data, headers=headers)
  990. self.assertEqual(output.status_code, 200)
  991. data = json.loads(output.get_data(as_text=True))
  992. self.assertDictEqual(
  993. data,
  994. {'message': 'You are now watching this pull-request'}
  995. )
  996. repo = pagure.lib.get_authorized_project(self.session, 'test')
  997. request = pagure.lib.search_pull_requests(
  998. self.session, project_id=1, requestid=1)
  999. self.assertEqual(
  1000. pagure.lib.get_watch_list(self.session, request),
  1001. set(['pingou', 'bar']))
  1002. # Unsubscribe
  1003. data = {}
  1004. output = self.app.post(
  1005. '/api/0/test/pull-request/1/subscribe',
  1006. data=data, headers=headers)
  1007. self.assertEqual(output.status_code, 200)
  1008. data = json.loads(output.get_data(as_text=True))
  1009. self.assertDictEqual(
  1010. data,
  1011. {'message': 'You are no longer watching this pull-request'}
  1012. )
  1013. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1014. request = pagure.lib.search_pull_requests(
  1015. self.session, project_id=1, requestid=1)
  1016. self.assertEqual(
  1017. pagure.lib.get_watch_list(self.session, request),
  1018. set(['pingou']))
  1019. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1020. def test_api_pull_request_open_invalid_project(self):
  1021. """ Test the api_pull_request_create method of the flask api when
  1022. not the project doesn't exist.
  1023. """
  1024. tests.create_projects(self.session)
  1025. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1026. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1027. bare=True)
  1028. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1029. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1030. branch='test')
  1031. tests.create_tokens(self.session)
  1032. tests.create_tokens_acl(self.session)
  1033. headers = {'Authorization': 'token aaabbbcccddd'}
  1034. data = {
  1035. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1036. 'branch_to': 'master',
  1037. 'branch_from': 'test',
  1038. }
  1039. output = self.app.post(
  1040. '/api/0/foobar/pull-request/new', headers=headers, data=data)
  1041. self.assertEqual(output.status_code, 404)
  1042. data = json.loads(output.get_data(as_text=True))
  1043. self.assertDictEqual(
  1044. data,
  1045. {'error': 'Project not found', 'error_code': 'ENOPROJECT'}
  1046. )
  1047. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1048. def test_api_pull_request_open_missing_title(self):
  1049. """ Test the api_pull_request_create method of the flask api when
  1050. not title is submitted.
  1051. """
  1052. tests.create_projects(self.session)
  1053. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1054. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1055. bare=True)
  1056. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1057. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1058. branch='test')
  1059. tests.create_tokens(self.session)
  1060. tests.create_tokens_acl(self.session)
  1061. headers = {'Authorization': 'token aaabbbcccddd'}
  1062. data = {
  1063. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1064. 'branch_to': 'master',
  1065. 'branch_from': 'test',
  1066. }
  1067. output = self.app.post(
  1068. '/api/0/test/pull-request/new', headers=headers, data=data)
  1069. self.assertEqual(output.status_code, 400)
  1070. data = json.loads(output.get_data(as_text=True))
  1071. self.assertDictEqual(
  1072. data,
  1073. {
  1074. 'error': 'Invalid or incomplete input submitted',
  1075. 'error_code': 'EINVALIDREQ',
  1076. 'errors': {'title': ['This field is required.']}
  1077. }
  1078. )
  1079. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1080. def test_api_pull_request_open_missing_branch_to(self):
  1081. """ Test the api_pull_request_create method of the flask api when
  1082. not branch to is submitted.
  1083. """
  1084. tests.create_projects(self.session)
  1085. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1086. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1087. bare=True)
  1088. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1089. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1090. branch='test')
  1091. tests.create_tokens(self.session)
  1092. tests.create_tokens_acl(self.session)
  1093. headers = {'Authorization': 'token aaabbbcccddd'}
  1094. data = {
  1095. 'title': 'Test PR',
  1096. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1097. 'branch_from': 'test',
  1098. }
  1099. output = self.app.post(
  1100. '/api/0/test/pull-request/new', headers=headers, data=data)
  1101. self.assertEqual(output.status_code, 400)
  1102. data = json.loads(output.get_data(as_text=True))
  1103. self.assertDictEqual(
  1104. data,
  1105. {
  1106. 'error': 'Invalid or incomplete input submitted',
  1107. 'error_code': 'EINVALIDREQ',
  1108. 'errors': {'branch_to': ['This field is required.']}
  1109. }
  1110. )
  1111. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1112. def test_api_pull_request_open_missing_branch_from(self):
  1113. """ Test the api_pull_request_create method of the flask api when
  1114. not branch from is submitted.
  1115. """
  1116. tests.create_projects(self.session)
  1117. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1118. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1119. bare=True)
  1120. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1121. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1122. branch='test')
  1123. tests.create_tokens(self.session)
  1124. tests.create_tokens_acl(self.session)
  1125. headers = {'Authorization': 'token aaabbbcccddd'}
  1126. data = {
  1127. 'title': 'Test PR',
  1128. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1129. 'branch_to': 'master',
  1130. }
  1131. output = self.app.post(
  1132. '/api/0/test/pull-request/new', headers=headers, data=data)
  1133. self.assertEqual(output.status_code, 400)
  1134. data = json.loads(output.get_data(as_text=True))
  1135. self.assertDictEqual(
  1136. data,
  1137. {
  1138. 'error': 'Invalid or incomplete input submitted',
  1139. 'error_code': 'EINVALIDREQ',
  1140. 'errors': {'branch_from': ['This field is required.']}
  1141. }
  1142. )
  1143. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1144. def test_api_pull_request_open_pr_disabled(self):
  1145. """ Test the api_pull_request_create method of the flask api when
  1146. the parent repo disabled pull-requests.
  1147. """
  1148. tests.create_projects(self.session)
  1149. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1150. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1151. bare=True)
  1152. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1153. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1154. branch='test')
  1155. tests.create_tokens(self.session)
  1156. tests.create_tokens_acl(self.session)
  1157. # Check the behavior if the project disabled the issue tracker
  1158. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1159. settings = repo.settings
  1160. settings['pull_requests'] = False
  1161. repo.settings = settings
  1162. self.session.add(repo)
  1163. self.session.commit()
  1164. headers = {'Authorization': 'token aaabbbcccddd'}
  1165. data = {
  1166. 'title': 'Test PR',
  1167. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1168. 'branch_to': 'master',
  1169. 'branch_from': 'test',
  1170. }
  1171. output = self.app.post(
  1172. '/api/0/test/pull-request/new', headers=headers, data=data)
  1173. self.assertEqual(output.status_code, 404)
  1174. data = json.loads(output.get_data(as_text=True))
  1175. self.assertDictEqual(
  1176. data,
  1177. {
  1178. 'error': 'Pull-Request have been deactivated for this project',
  1179. 'error_code': 'EPULLREQUESTSDISABLED'
  1180. }
  1181. )
  1182. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1183. def test_api_pull_request_open_signed_pr(self):
  1184. """ Test the api_pull_request_create method of the flask api when
  1185. the parent repo enforces signed-off pull-requests.
  1186. """
  1187. tests.create_projects(self.session)
  1188. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1189. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1190. bare=True)
  1191. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1192. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1193. branch='test')
  1194. tests.create_tokens(self.session)
  1195. tests.create_tokens_acl(self.session)
  1196. # Check the behavior if the project disabled the issue tracker
  1197. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1198. settings = repo.settings
  1199. settings['Enforce_signed-off_commits_in_pull-request'] = True
  1200. repo.settings = settings
  1201. self.session.add(repo)
  1202. self.session.commit()
  1203. headers = {'Authorization': 'token aaabbbcccddd'}
  1204. data = {
  1205. 'title': 'Test PR',
  1206. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1207. 'branch_to': 'master',
  1208. 'branch_from': 'test',
  1209. }
  1210. output = self.app.post(
  1211. '/api/0/test/pull-request/new', headers=headers, data=data)
  1212. self.assertEqual(output.status_code, 400)
  1213. data = json.loads(output.get_data(as_text=True))
  1214. self.assertDictEqual(
  1215. data,
  1216. {
  1217. 'error': 'This repo enforces that all commits are signed '
  1218. 'off by their author.',
  1219. 'error_code': 'ENOSIGNEDOFF'
  1220. }
  1221. )
  1222. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1223. def test_api_pull_request_open_invalid_branch_from(self):
  1224. """ Test the api_pull_request_create method of the flask api when
  1225. the branch from does not exist.
  1226. """
  1227. tests.create_projects(self.session)
  1228. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1229. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1230. bare=True)
  1231. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1232. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1233. branch='test')
  1234. tests.create_tokens(self.session)
  1235. tests.create_tokens_acl(self.session)
  1236. # Check the behavior if the project disabled the issue tracker
  1237. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1238. settings = repo.settings
  1239. settings['Enforce_signed-off_commits_in_pull-request'] = True
  1240. repo.settings = settings
  1241. self.session.add(repo)
  1242. self.session.commit()
  1243. headers = {'Authorization': 'token aaabbbcccddd'}
  1244. data = {
  1245. 'title': 'Test PR',
  1246. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1247. 'branch_to': 'master',
  1248. 'branch_from': 'foobarbaz',
  1249. }
  1250. output = self.app.post(
  1251. '/api/0/test/pull-request/new', headers=headers, data=data)
  1252. self.assertEqual(output.status_code, 400)
  1253. data = json.loads(output.get_data(as_text=True))
  1254. self.assertDictEqual(
  1255. data,
  1256. {
  1257. 'error': 'Invalid or incomplete input submitted',
  1258. 'error_code': 'EINVALIDREQ',
  1259. 'errors': 'Branch foobarbaz does not exist'
  1260. }
  1261. )
  1262. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1263. def test_api_pull_request_open_invalid_branch_to(self):
  1264. """ Test the api_pull_request_create method of the flask api when
  1265. the branch to does not exist.
  1266. """
  1267. tests.create_projects(self.session)
  1268. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1269. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1270. bare=True)
  1271. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1272. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1273. branch='test')
  1274. tests.create_tokens(self.session)
  1275. tests.create_tokens_acl(self.session)
  1276. # Check the behavior if the project disabled the issue tracker
  1277. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1278. settings = repo.settings
  1279. settings['Enforce_signed-off_commits_in_pull-request'] = True
  1280. repo.settings = settings
  1281. self.session.add(repo)
  1282. self.session.commit()
  1283. headers = {'Authorization': 'token aaabbbcccddd'}
  1284. data = {
  1285. 'title': 'Test PR',
  1286. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1287. 'branch_to': 'foobarbaz',
  1288. 'branch_from': 'test',
  1289. }
  1290. output = self.app.post(
  1291. '/api/0/test/pull-request/new', headers=headers, data=data)
  1292. self.assertEqual(output.status_code, 400)
  1293. data = json.loads(output.get_data(as_text=True))
  1294. self.assertDictEqual(
  1295. data,
  1296. {
  1297. 'error': 'Invalid or incomplete input submitted',
  1298. 'error_code': 'EINVALIDREQ',
  1299. 'errors': 'Branch foobarbaz could not be found in the '
  1300. 'target repo'
  1301. }
  1302. )
  1303. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1304. def test_api_pull_request_open(self):
  1305. """ Test the api_pull_request_create method of the flask api. """
  1306. tests.create_projects(self.session)
  1307. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1308. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1309. bare=True)
  1310. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1311. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1312. branch='test')
  1313. tests.create_tokens(self.session)
  1314. tests.create_tokens_acl(self.session)
  1315. headers = {'Authorization': 'token aaabbbcccddd'}
  1316. data = {
  1317. 'title': 'Test PR',
  1318. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1319. 'branch_to': 'master',
  1320. 'branch_from': 'test',
  1321. }
  1322. output = self.app.post(
  1323. '/api/0/test/pull-request/new', headers=headers, data=data)
  1324. self.assertEqual(output.status_code, 200)
  1325. data = json.loads(output.get_data(as_text=True))
  1326. data['project']['date_created'] = '1516348115'
  1327. data['project']['date_modified'] = '1516348115'
  1328. data['repo_from']['date_created'] = '1516348115'
  1329. data['repo_from']['date_modified'] = '1516348115'
  1330. data['uid'] = 'e8b68df8711648deac67c3afed15a798'
  1331. data['commit_start'] = '114f1b468a5f05e635fcb6394273f3f907386eab'
  1332. data['commit_stop'] = '114f1b468a5f05e635fcb6394273f3f907386eab'
  1333. data['date_created'] = '1516348115'
  1334. data['last_updated'] = '1516348115'
  1335. data['updated_on'] = '1516348115'
  1336. self.assertDictEqual(
  1337. data,
  1338. {
  1339. 'assignee': None,
  1340. 'branch': 'master',
  1341. 'branch_from': 'test',
  1342. 'cached_merge_status': 'unknown',
  1343. 'closed_at': None,
  1344. 'closed_by': None,
  1345. 'comments': [],
  1346. 'commit_start': '114f1b468a5f05e635fcb6394273f3f907386eab',
  1347. 'commit_stop': '114f1b468a5f05e635fcb6394273f3f907386eab',
  1348. 'date_created': '1516348115',
  1349. 'id': 1,
  1350. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1351. 'last_updated': '1516348115',
  1352. 'project': {'access_groups': {'admin': [],
  1353. 'commit': [],
  1354. 'ticket':[]},
  1355. 'access_users': {'admin': [],
  1356. 'commit': [],
  1357. 'owner': ['pingou'],
  1358. 'ticket': []},
  1359. 'close_status': ['Invalid',
  1360. 'Insufficient data',
  1361. 'Fixed',
  1362. 'Duplicate'],
  1363. 'custom_keys': [],
  1364. 'date_created': '1516348115',
  1365. 'date_modified': '1516348115',
  1366. 'description': 'test project #1',
  1367. 'fullname': 'test',
  1368. 'id': 1,
  1369. 'milestones': {},
  1370. 'name': 'test',
  1371. 'namespace': None,
  1372. 'parent': None,
  1373. 'priorities': {},
  1374. 'tags': [],
  1375. 'url_path': 'test',
  1376. 'user': {'fullname': 'PY C', 'name': 'pingou'}},
  1377. 'remote_git': None,
  1378. 'repo_from': {'access_groups': {'admin': [],
  1379. 'commit': [],
  1380. 'ticket': []},
  1381. 'access_users': {'admin': [],
  1382. 'commit': [],
  1383. 'owner': ['pingou'],
  1384. 'ticket': []},
  1385. 'close_status': ['Invalid',
  1386. 'Insufficient data',
  1387. 'Fixed',
  1388. 'Duplicate'],
  1389. 'custom_keys': [],
  1390. 'date_created': '1516348115',
  1391. 'date_modified': '1516348115',
  1392. 'description': 'test project #1',
  1393. 'fullname': 'test',
  1394. 'id': 1,
  1395. 'milestones': {},
  1396. 'name': 'test',
  1397. 'namespace': None,
  1398. 'parent': None,
  1399. 'priorities': {},
  1400. 'tags': [],
  1401. 'url_path': 'test',
  1402. 'user': {'fullname': 'PY C', 'name': 'pingou'}},
  1403. 'status': 'Open',
  1404. 'title': 'Test PR',
  1405. 'uid': 'e8b68df8711648deac67c3afed15a798',
  1406. 'updated_on': '1516348115',
  1407. 'user': {'fullname': 'PY C', 'name': 'pingou'}
  1408. }
  1409. )
  1410. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1411. def test_api_pull_request_open_missing_initial_comment(self):
  1412. """ Test the api_pull_request_create method of the flask api when
  1413. not initial comment is submitted.
  1414. """
  1415. tests.create_projects(self.session)
  1416. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1417. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1418. bare=True)
  1419. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1420. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1421. branch='test')
  1422. tests.create_tokens(self.session)
  1423. tests.create_tokens_acl(self.session)
  1424. headers = {'Authorization': 'token aaabbbcccddd'}
  1425. data = {
  1426. 'title': 'Test PR',
  1427. 'branch_to': 'master',
  1428. 'branch_from': 'test',
  1429. }
  1430. output = self.app.post(
  1431. '/api/0/test/pull-request/new', headers=headers, data=data)
  1432. self.assertEqual(output.status_code, 200)
  1433. data = json.loads(output.get_data(as_text=True))
  1434. data['project']['date_created'] = '1516348115'
  1435. data['project']['date_modified'] = '1516348115'
  1436. data['repo_from']['date_created'] = '1516348115'
  1437. data['repo_from']['date_modified'] = '1516348115'
  1438. data['uid'] = 'e8b68df8711648deac67c3afed15a798'
  1439. data['commit_start'] = '114f1b468a5f05e635fcb6394273f3f907386eab'
  1440. data['commit_stop'] = '114f1b468a5f05e635fcb6394273f3f907386eab'
  1441. data['date_created'] = '1516348115'
  1442. data['last_updated'] = '1516348115'
  1443. data['updated_on'] = '1516348115'
  1444. self.assertDictEqual(
  1445. data,
  1446. {
  1447. 'assignee': None,
  1448. 'branch': 'master',
  1449. 'branch_from': 'test',
  1450. 'cached_merge_status': 'unknown',
  1451. 'closed_at': None,
  1452. 'closed_by': None,
  1453. 'comments': [],
  1454. 'commit_start': '114f1b468a5f05e635fcb6394273f3f907386eab',
  1455. 'commit_stop': '114f1b468a5f05e635fcb6394273f3f907386eab',
  1456. 'date_created': '1516348115',
  1457. 'id': 1,
  1458. 'initial_comment': None,
  1459. 'last_updated': '1516348115',
  1460. 'project': {'access_groups': {'admin': [],
  1461. 'commit': [],
  1462. 'ticket':[]},
  1463. 'access_users': {'admin': [],
  1464. 'commit': [],
  1465. 'owner': ['pingou'],
  1466. 'ticket': []},
  1467. 'close_status': ['Invalid',
  1468. 'Insufficient data',
  1469. 'Fixed',
  1470. 'Duplicate'],
  1471. 'custom_keys': [],
  1472. 'date_created': '1516348115',
  1473. 'date_modified': '1516348115',
  1474. 'description': 'test project #1',
  1475. 'fullname': 'test',
  1476. 'id': 1,
  1477. 'milestones': {},
  1478. 'name': 'test',
  1479. 'namespace': None,
  1480. 'parent': None,
  1481. 'priorities': {},
  1482. 'tags': [],
  1483. 'url_path': 'test',
  1484. 'user': {'fullname': 'PY C', 'name': 'pingou'}},
  1485. 'remote_git': None,
  1486. 'repo_from': {'access_groups': {'admin': [],
  1487. 'commit': [],
  1488. 'ticket': []},
  1489. 'access_users': {'admin': [],
  1490. 'commit': [],
  1491. 'owner': ['pingou'],
  1492. 'ticket': []},
  1493. 'close_status': ['Invalid',
  1494. 'Insufficient data',
  1495. 'Fixed',
  1496. 'Duplicate'],
  1497. 'custom_keys': [],
  1498. 'date_created': '1516348115',
  1499. 'date_modified': '1516348115',
  1500. 'description': 'test project #1',
  1501. 'fullname': 'test',
  1502. 'id': 1,
  1503. 'milestones': {},
  1504. 'name': 'test',
  1505. 'namespace': None,
  1506. 'parent': None,
  1507. 'priorities': {},
  1508. 'tags': [],
  1509. 'url_path': 'test',
  1510. 'user': {'fullname': 'PY C', 'name': 'pingou'}},
  1511. 'status': 'Open',
  1512. 'title': 'Test PR',
  1513. 'uid': 'e8b68df8711648deac67c3afed15a798',
  1514. 'updated_on': '1516348115',
  1515. 'user': {'fullname': 'PY C', 'name': 'pingou'}
  1516. }
  1517. )
  1518. if __name__ == '__main__':
  1519. unittest.main(verbosity=2)