test_pagure_flask_api_fork.py 65 KB

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