test_pagure_flask_api_fork.py 107 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878
  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', MagicMock(return_value=True))
  30. def test_api_pull_request_views_pr_disabled(self):
  31. """ Test the api_pull_request_views method of the flask api when PR
  32. are disabled. """
  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. )
  49. self.session.commit()
  50. self.assertEqual(req.id, 1)
  51. self.assertEqual(req.title, 'test pull-request')
  52. repo = pagure.lib.get_authorized_project(self.session, 'test')
  53. settings = repo.settings
  54. settings['pull_requests'] = False
  55. repo.settings = settings
  56. self.session.add(repo)
  57. self.session.commit()
  58. output = self.app.get('/api/0/test/pull-requests')
  59. self.assertEqual(output.status_code, 404)
  60. data = json.loads(output.get_data(as_text=True))
  61. self.assertDictEqual(
  62. data,
  63. {
  64. u'error': u'Pull-Request have been deactivated for this project',
  65. u'error_code': u'EPULLREQUESTSDISABLED'
  66. }
  67. )
  68. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  69. def test_api_pull_request_views_pr_closed(self):
  70. """ Test the api_pull_request_views method of the flask api to list
  71. the closed PRs. """
  72. tests.create_projects(self.session)
  73. tests.create_tokens(self.session)
  74. tests.create_tokens_acl(self.session)
  75. # Create a pull-request
  76. repo = pagure.lib.get_authorized_project(self.session, 'test')
  77. forked_repo = pagure.lib.get_authorized_project(
  78. self.session, 'test')
  79. req = pagure.lib.new_pull_request(
  80. session=self.session,
  81. repo_from=forked_repo,
  82. branch_from='master',
  83. repo_to=repo,
  84. branch_to='master',
  85. title='test pull-request',
  86. user='pingou',
  87. )
  88. self.session.commit()
  89. self.assertEqual(req.id, 1)
  90. self.assertEqual(req.title, 'test pull-request')
  91. output = self.app.get('/api/0/test/pull-requests?status=closed')
  92. self.assertEqual(output.status_code, 200)
  93. data = json.loads(output.get_data(as_text=True))
  94. for k in ['first', 'last']:
  95. self.assertIsNotNone(data['pagination'][k])
  96. data['pagination'][k] = 'http://localhost...'
  97. self.assertDictEqual(
  98. data,
  99. {
  100. u'args': {
  101. u'assignee': None,
  102. u'author': None,
  103. u'page': 1,
  104. u'per_page': 20,
  105. u'status': u'closed'
  106. },
  107. u'pagination': {
  108. u'first': u'http://localhost...',
  109. u'last': u'http://localhost...',
  110. u'next': None,
  111. u'page': 1,
  112. u'pages': 0,
  113. u'per_page': 20,
  114. u'prev': None
  115. },
  116. u'requests': [],
  117. u'total_requests': 0
  118. }
  119. )
  120. # Close the PR and try again
  121. pagure.lib.close_pull_request(
  122. self.session, request=req, user='pingou',
  123. merged=False)
  124. output = self.app.get('/api/0/test/pull-requests?status=closed')
  125. self.assertEqual(output.status_code, 200)
  126. data = json.loads(output.get_data(as_text=True))
  127. self.assertEqual(
  128. sorted(data.keys()),
  129. ['args', 'pagination', 'requests', 'total_requests'])
  130. self.assertDictEqual(
  131. data['args'],
  132. {
  133. u'assignee': None,
  134. u'author': None,
  135. u'page': 1,
  136. u'per_page': 20,
  137. u'status': u'closed'
  138. }
  139. )
  140. self.assertEqual(data['total_requests'], 1)
  141. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  142. def test_api_pull_request_views_all_pr(self):
  143. """ Test the api_pull_request_views method of the flask api to list
  144. all PRs. """
  145. tests.create_projects(self.session)
  146. tests.create_tokens(self.session)
  147. tests.create_tokens_acl(self.session)
  148. # Create a pull-request
  149. repo = pagure.lib.get_authorized_project(self.session, 'test')
  150. forked_repo = pagure.lib.get_authorized_project(
  151. self.session, 'test')
  152. req = pagure.lib.new_pull_request(
  153. session=self.session,
  154. repo_from=forked_repo,
  155. branch_from='master',
  156. repo_to=repo,
  157. branch_to='master',
  158. title='test pull-request',
  159. user='pingou',
  160. )
  161. self.session.commit()
  162. self.assertEqual(req.id, 1)
  163. self.assertEqual(req.title, 'test pull-request')
  164. output = self.app.get('/api/0/test/pull-requests?status=all')
  165. self.assertEqual(output.status_code, 200)
  166. data = json.loads(output.get_data(as_text=True))
  167. self.assertEqual(
  168. sorted(data.keys()),
  169. ['args', 'pagination', 'requests', 'total_requests'])
  170. self.assertDictEqual(
  171. data['args'],
  172. {
  173. u'assignee': None,
  174. u'author': None,
  175. u'page': 1,
  176. u'per_page': 20,
  177. u'status': u'all'
  178. }
  179. )
  180. self.assertEqual(data['total_requests'], 1)
  181. # Close the PR and try again
  182. pagure.lib.close_pull_request(
  183. self.session, request=req, user='pingou',
  184. merged=False)
  185. output = self.app.get('/api/0/test/pull-requests?status=all')
  186. self.assertEqual(output.status_code, 200)
  187. data = json.loads(output.get_data(as_text=True))
  188. self.assertEqual(
  189. sorted(data.keys()),
  190. ['args', 'pagination', 'requests', 'total_requests'])
  191. self.assertDictEqual(
  192. data['args'],
  193. {
  194. u'assignee': None,
  195. u'author': None,
  196. u'page': 1,
  197. u'per_page': 20,
  198. u'status': u'all'
  199. }
  200. )
  201. self.assertEqual(data['total_requests'], 1)
  202. @patch('pagure.lib.notify.send_email')
  203. def test_api_pull_request_views(self, send_email):
  204. """ Test the api_pull_request_views method of the flask api. """
  205. send_email.return_value = True
  206. tests.create_projects(self.session)
  207. tests.create_tokens(self.session)
  208. tests.create_tokens_acl(self.session)
  209. # Create a pull-request
  210. repo = pagure.lib.get_authorized_project(self.session, 'test')
  211. forked_repo = pagure.lib.get_authorized_project(
  212. self.session, 'test')
  213. req = pagure.lib.new_pull_request(
  214. session=self.session,
  215. repo_from=forked_repo,
  216. branch_from='master',
  217. repo_to=repo,
  218. branch_to='master',
  219. title='test pull-request',
  220. user='pingou',
  221. )
  222. self.session.commit()
  223. self.assertEqual(req.id, 1)
  224. self.assertEqual(req.title, 'test pull-request')
  225. # Invalid repo
  226. output = self.app.get('/api/0/foo/pull-requests')
  227. self.assertEqual(output.status_code, 404)
  228. data = json.loads(output.get_data(as_text=True))
  229. self.assertDictEqual(
  230. data,
  231. {
  232. "error": "Project not found",
  233. "error_code": "ENOPROJECT",
  234. }
  235. )
  236. # List pull-requests
  237. output = self.app.get('/api/0/test/pull-requests')
  238. self.assertEqual(output.status_code, 200)
  239. data = json.loads(output.get_data(as_text=True))
  240. data['requests'][0]['date_created'] = '1431414800'
  241. data['requests'][0]['updated_on'] = '1431414800'
  242. data['requests'][0]['project']['date_created'] = '1431414800'
  243. data['requests'][0]['project']['date_modified'] = '1431414800'
  244. data['requests'][0]['repo_from']['date_created'] = '1431414800'
  245. data['requests'][0]['repo_from']['date_modified'] = '1431414800'
  246. data['requests'][0]['uid'] = '1431414800'
  247. data['requests'][0]['last_updated'] = '1431414800'
  248. for k in ['first', 'last']:
  249. self.assertIsNotNone(data['pagination'][k])
  250. data['pagination'][k] = 'http://localhost...'
  251. expected_data = {
  252. "args": {
  253. "assignee": None,
  254. "author": None,
  255. "page": 1,
  256. "per_page": 20,
  257. "status": True
  258. },
  259. 'pagination': {
  260. "first": 'http://localhost...',
  261. "last": 'http://localhost...',
  262. "next": None,
  263. "page": 1,
  264. "pages": 1,
  265. "per_page": 20,
  266. "prev": None
  267. },
  268. "requests": [{
  269. "assignee": None,
  270. "branch": "master",
  271. "branch_from": "master",
  272. "cached_merge_status": "unknown",
  273. "closed_at": None,
  274. "closed_by": None,
  275. "comments": [],
  276. "commit_start": None,
  277. "commit_stop": None,
  278. "date_created": "1431414800",
  279. "id": 1,
  280. "initial_comment": None,
  281. "last_updated": "1431414800",
  282. "project": {
  283. "access_groups": {
  284. "admin": [],
  285. "commit": [],
  286. "ticket": []
  287. },
  288. "access_users": {
  289. "admin": [],
  290. "commit": [],
  291. "owner": ["pingou"],
  292. "ticket": []
  293. },
  294. "close_status": [
  295. "Invalid",
  296. "Insufficient data",
  297. "Fixed",
  298. "Duplicate"
  299. ],
  300. "custom_keys": [],
  301. "date_created": "1431414800",
  302. "date_modified": "1431414800",
  303. "description": "test project #1",
  304. "fullname": "test",
  305. "url_path": "test",
  306. "id": 1,
  307. "milestones": {},
  308. "name": "test",
  309. "namespace": None,
  310. "parent": None,
  311. "priorities": {},
  312. "tags": [],
  313. "user": {
  314. "fullname": "PY C",
  315. "name": "pingou"
  316. }
  317. },
  318. "remote_git": None,
  319. "repo_from": {
  320. "access_groups": {
  321. "admin": [],
  322. "commit": [],
  323. "ticket": []},
  324. "access_users": {
  325. "admin": [],
  326. "commit": [],
  327. "owner": ["pingou"],
  328. "ticket": []
  329. },
  330. "close_status": [
  331. "Invalid",
  332. "Insufficient data",
  333. "Fixed",
  334. "Duplicate"
  335. ],
  336. "custom_keys": [],
  337. "date_created": "1431414800",
  338. "date_modified": "1431414800",
  339. "description": "test project #1",
  340. "fullname": "test",
  341. "url_path": "test",
  342. "id": 1,
  343. "milestones": {},
  344. "name": "test",
  345. "namespace": None,
  346. "parent": None,
  347. "priorities": {},
  348. "tags": [],
  349. "user": {
  350. "fullname": "PY C",
  351. "name": "pingou"
  352. }
  353. },
  354. "status": "Open",
  355. "title": "test pull-request",
  356. "uid": "1431414800",
  357. "updated_on": "1431414800",
  358. "user": {
  359. "fullname": "PY C",
  360. "name": "pingou"
  361. }
  362. }],
  363. "total_requests": 1
  364. }
  365. self.assertDictEqual(data, expected_data)
  366. headers = {'Authorization': 'token aaabbbcccddd'}
  367. # Access Pull-Request authenticated
  368. output = self.app.get('/api/0/test/pull-requests', headers=headers)
  369. self.assertEqual(output.status_code, 200)
  370. data2 = json.loads(output.get_data(as_text=True))
  371. data2['requests'][0]['date_created'] = '1431414800'
  372. data2['requests'][0]['updated_on'] = '1431414800'
  373. data2['requests'][0]['project']['date_created'] = '1431414800'
  374. data2['requests'][0]['project']['date_modified'] = '1431414800'
  375. data2['requests'][0]['repo_from']['date_created'] = '1431414800'
  376. data2['requests'][0]['repo_from']['date_modified'] = '1431414800'
  377. data2['requests'][0]['uid'] = '1431414800'
  378. data2['requests'][0]['last_updated'] = '1431414800'
  379. for k in ['first', 'last']:
  380. self.assertIsNotNone(data['pagination'][k])
  381. data2['pagination'][k] = 'http://localhost...'
  382. self.assertDictEqual(data, data2)
  383. @patch('pagure.lib.notify.send_email')
  384. def test_api_pull_request_view_pr_disabled(self, send_email):
  385. """ Test the api_pull_request_view method of the flask api. """
  386. send_email.return_value = True
  387. tests.create_projects(self.session)
  388. tests.create_tokens(self.session)
  389. tests.create_tokens_acl(self.session)
  390. # Create a pull-request
  391. repo = pagure.lib.get_authorized_project(self.session, 'test')
  392. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  393. req = pagure.lib.new_pull_request(
  394. session=self.session,
  395. repo_from=forked_repo,
  396. branch_from='master',
  397. repo_to=repo,
  398. branch_to='master',
  399. title='test pull-request',
  400. user='pingou',
  401. )
  402. self.session.commit()
  403. self.assertEqual(req.id, 1)
  404. self.assertEqual(req.title, 'test pull-request')
  405. repo = pagure.lib.get_authorized_project(self.session, 'test')
  406. settings = repo.settings
  407. settings['pull_requests'] = False
  408. repo.settings = settings
  409. self.session.add(repo)
  410. self.session.commit()
  411. output = self.app.get('/api/0/test/pull-request/1')
  412. self.assertEqual(output.status_code, 404)
  413. data = json.loads(output.get_data(as_text=True))
  414. self.assertDictEqual(
  415. data,
  416. {
  417. u'error': u'Pull-Request have been deactivated for this project',
  418. u'error_code': u'EPULLREQUESTSDISABLED'
  419. }
  420. )
  421. @patch('pagure.lib.notify.send_email')
  422. def test_api_pull_request_view(self, send_email):
  423. """ Test the api_pull_request_view method of the flask api. """
  424. send_email.return_value = True
  425. tests.create_projects(self.session)
  426. tests.create_tokens(self.session)
  427. tests.create_tokens_acl(self.session)
  428. # Create a pull-request
  429. repo = pagure.lib.get_authorized_project(self.session, 'test')
  430. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  431. req = pagure.lib.new_pull_request(
  432. session=self.session,
  433. repo_from=forked_repo,
  434. branch_from='master',
  435. repo_to=repo,
  436. branch_to='master',
  437. title='test pull-request',
  438. user='pingou',
  439. )
  440. self.session.commit()
  441. self.assertEqual(req.id, 1)
  442. self.assertEqual(req.title, 'test pull-request')
  443. # Invalid repo
  444. output = self.app.get('/api/0/foo/pull-request/1')
  445. self.assertEqual(output.status_code, 404)
  446. data = json.loads(output.get_data(as_text=True))
  447. self.assertDictEqual(
  448. data,
  449. {
  450. "error": "Project not found",
  451. "error_code": "ENOPROJECT",
  452. }
  453. )
  454. # Invalid issue for this repo
  455. output = self.app.get('/api/0/test2/pull-request/1')
  456. self.assertEqual(output.status_code, 404)
  457. data = json.loads(output.get_data(as_text=True))
  458. self.assertDictEqual(
  459. data,
  460. {
  461. "error": "Pull-Request not found",
  462. "error_code": "ENOREQ",
  463. }
  464. )
  465. # Valid issue
  466. output = self.app.get('/api/0/test/pull-request/1')
  467. self.assertEqual(output.status_code, 200)
  468. data = json.loads(output.get_data(as_text=True))
  469. data['date_created'] = '1431414800'
  470. data['updated_on'] = '1431414800'
  471. data['project']['date_created'] = '1431414800'
  472. data['project']['date_modified'] = '1431414800'
  473. data['repo_from']['date_created'] = '1431414800'
  474. data['repo_from']['date_modified'] = '1431414800'
  475. data['uid'] = '1431414800'
  476. data['last_updated'] = '1431414800'
  477. expected_data = {
  478. "assignee": None,
  479. "branch": "master",
  480. "branch_from": "master",
  481. "cached_merge_status": "unknown",
  482. "closed_at": None,
  483. "closed_by": None,
  484. "comments": [],
  485. "commit_start": None,
  486. "commit_stop": None,
  487. "date_created": "1431414800",
  488. "id": 1,
  489. "initial_comment": None,
  490. "last_updated": "1431414800",
  491. "project": {
  492. "access_groups": {
  493. "admin": [],
  494. "commit": [],
  495. "ticket": []
  496. },
  497. "access_users": {
  498. "admin": [],
  499. "commit": [],
  500. "owner": ["pingou"],
  501. "ticket": []
  502. },
  503. "close_status": [
  504. "Invalid",
  505. "Insufficient data",
  506. "Fixed",
  507. "Duplicate"
  508. ],
  509. "custom_keys": [],
  510. "date_created": "1431414800",
  511. "date_modified": "1431414800",
  512. "description": "test project #1",
  513. "fullname": "test",
  514. "url_path": "test",
  515. "id": 1,
  516. "milestones": {},
  517. "name": "test",
  518. "namespace": None,
  519. "parent": None,
  520. "priorities": {},
  521. "tags": [],
  522. "user": {
  523. "fullname": "PY C",
  524. "name": "pingou"
  525. }
  526. },
  527. "remote_git": None,
  528. "repo_from": {
  529. "access_groups": {
  530. "admin": [],
  531. "commit": [],
  532. "ticket": []},
  533. "access_users": {
  534. "admin": [],
  535. "commit": [],
  536. "owner": ["pingou"],
  537. "ticket": []},
  538. "close_status": [
  539. "Invalid",
  540. "Insufficient data",
  541. "Fixed",
  542. "Duplicate"],
  543. "custom_keys": [],
  544. "date_created": "1431414800",
  545. "date_modified": "1431414800",
  546. "description": "test project #1",
  547. "fullname": "test",
  548. "url_path": "test",
  549. "id": 1,
  550. "milestones": {},
  551. "name": "test",
  552. "namespace": None,
  553. "parent": None,
  554. "priorities": {},
  555. "tags": [],
  556. "user": {
  557. "fullname": "PY C",
  558. "name": "pingou"
  559. }
  560. },
  561. "status": "Open",
  562. "title": "test pull-request",
  563. "uid": "1431414800",
  564. "updated_on": "1431414800",
  565. "user": {
  566. "fullname": "PY C",
  567. "name": "pingou"
  568. }
  569. }
  570. self.assertDictEqual(data, expected_data)
  571. headers = {'Authorization': 'token aaabbbcccddd'}
  572. # Access Pull-Request authenticated
  573. output = self.app.get('/api/0/test/pull-request/1', headers=headers)
  574. self.assertEqual(output.status_code, 200)
  575. data2 = json.loads(output.get_data(as_text=True))
  576. data2['date_created'] = '1431414800'
  577. data2['project']['date_created'] = '1431414800'
  578. data2['project']['date_modified'] = '1431414800'
  579. data2['repo_from']['date_created'] = '1431414800'
  580. data2['repo_from']['date_modified'] = '1431414800'
  581. data2['uid'] = '1431414800'
  582. data2['date_created'] = '1431414800'
  583. data2['updated_on'] = '1431414800'
  584. data2['last_updated'] = '1431414800'
  585. self.assertDictEqual(data, data2)
  586. @patch('pagure.lib.notify.send_email')
  587. def test_api_pull_request_by_uid_view(self, send_email):
  588. """ Test the api_pull_request_by_uid_view method of the flask api. """
  589. send_email.return_value = True
  590. tests.create_projects(self.session)
  591. tests.create_tokens(self.session)
  592. tests.create_tokens_acl(self.session)
  593. # Create a pull-request
  594. repo = pagure.lib.get_authorized_project(self.session, 'test')
  595. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  596. req = pagure.lib.new_pull_request(
  597. session=self.session,
  598. repo_from=forked_repo,
  599. branch_from='master',
  600. repo_to=repo,
  601. branch_to='master',
  602. title='test pull-request',
  603. user='pingou',
  604. )
  605. self.session.commit()
  606. self.assertEqual(req.id, 1)
  607. self.assertEqual(req.title, 'test pull-request')
  608. uid = req.uid
  609. # Invalid request
  610. output = self.app.get('/api/0/pull-requests/{}'.format(uid + 'aaa'))
  611. self.assertEqual(output.status_code, 404)
  612. data = json.loads(output.get_data(as_text=True))
  613. self.assertDictEqual(
  614. data,
  615. {
  616. "error": "Pull-Request not found",
  617. "error_code": "ENOREQ",
  618. }
  619. )
  620. # Valid issue
  621. output = self.app.get('/api/0/pull-requests/{}'.format(uid))
  622. self.assertEqual(output.status_code, 200)
  623. data = json.loads(output.get_data(as_text=True))
  624. data['date_created'] = '1431414800'
  625. data['updated_on'] = '1431414800'
  626. data['project']['date_created'] = '1431414800'
  627. data['project']['date_modified'] = '1431414800'
  628. data['repo_from']['date_created'] = '1431414800'
  629. data['repo_from']['date_modified'] = '1431414800'
  630. data['last_updated'] = '1431414800'
  631. expected_data = {
  632. "assignee": None,
  633. "branch": "master",
  634. "branch_from": "master",
  635. "cached_merge_status": "unknown",
  636. "closed_at": None,
  637. "closed_by": None,
  638. "comments": [],
  639. "commit_start": None,
  640. "commit_stop": None,
  641. "date_created": "1431414800",
  642. "id": 1,
  643. "initial_comment": None,
  644. "last_updated": "1431414800",
  645. "project": {
  646. "access_groups": {
  647. "admin": [],
  648. "commit": [],
  649. "ticket": []
  650. },
  651. "access_users": {
  652. "admin": [],
  653. "commit": [],
  654. "owner": ["pingou"],
  655. "ticket": []
  656. },
  657. "close_status": [
  658. "Invalid",
  659. "Insufficient data",
  660. "Fixed",
  661. "Duplicate"
  662. ],
  663. "custom_keys": [],
  664. "date_created": "1431414800",
  665. "date_modified": "1431414800",
  666. "description": "test project #1",
  667. "fullname": "test",
  668. "url_path": "test",
  669. "id": 1,
  670. "milestones": {},
  671. "name": "test",
  672. "namespace": None,
  673. "parent": None,
  674. "priorities": {},
  675. "tags": [],
  676. "user": {
  677. "fullname": "PY C",
  678. "name": "pingou"
  679. }
  680. },
  681. "remote_git": None,
  682. "repo_from": {
  683. "access_groups": {
  684. "admin": [],
  685. "commit": [],
  686. "ticket": []},
  687. "access_users": {
  688. "admin": [],
  689. "commit": [],
  690. "owner": ["pingou"],
  691. "ticket": []},
  692. "close_status": [
  693. "Invalid",
  694. "Insufficient data",
  695. "Fixed",
  696. "Duplicate"],
  697. "custom_keys": [],
  698. "date_created": "1431414800",
  699. "date_modified": "1431414800",
  700. "description": "test project #1",
  701. "fullname": "test",
  702. "url_path": "test",
  703. "id": 1,
  704. "milestones": {},
  705. "name": "test",
  706. "namespace": None,
  707. "parent": None,
  708. "priorities": {},
  709. "tags": [],
  710. "user": {
  711. "fullname": "PY C",
  712. "name": "pingou"
  713. }
  714. },
  715. "status": "Open",
  716. "title": "test pull-request",
  717. "uid": uid,
  718. "updated_on": "1431414800",
  719. "user": {
  720. "fullname": "PY C",
  721. "name": "pingou"
  722. }
  723. }
  724. self.assertDictEqual(data, expected_data)
  725. headers = {'Authorization': 'token aaabbbcccddd'}
  726. # Access Pull-Request authenticated
  727. output = self.app.get('/api/0/pull-requests/{}'.format(uid), headers=headers)
  728. self.assertEqual(output.status_code, 200)
  729. data2 = json.loads(output.get_data(as_text=True))
  730. data2['date_created'] = '1431414800'
  731. data2['project']['date_created'] = '1431414800'
  732. data2['project']['date_modified'] = '1431414800'
  733. data2['repo_from']['date_created'] = '1431414800'
  734. data2['repo_from']['date_modified'] = '1431414800'
  735. data2['date_created'] = '1431414800'
  736. data2['updated_on'] = '1431414800'
  737. data2['last_updated'] = '1431414800'
  738. self.assertDictEqual(data, data2)
  739. @patch('pagure.lib.notify.send_email')
  740. def test_api_pull_request_close_pr_disabled(self, send_email):
  741. """ Test the api_pull_request_close method of the flask api. """
  742. send_email.return_value = True
  743. tests.create_projects(self.session)
  744. tests.create_tokens(self.session)
  745. tests.create_tokens_acl(self.session)
  746. # Create the pull-request to close
  747. repo = pagure.lib.get_authorized_project(self.session, 'test')
  748. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  749. req = pagure.lib.new_pull_request(
  750. session=self.session,
  751. repo_from=forked_repo,
  752. branch_from='master',
  753. repo_to=repo,
  754. branch_to='master',
  755. title='test pull-request',
  756. user='pingou',
  757. )
  758. self.session.commit()
  759. self.assertEqual(req.id, 1)
  760. self.assertEqual(req.title, 'test pull-request')
  761. repo = pagure.lib.get_authorized_project(self.session, 'test')
  762. settings = repo.settings
  763. settings['pull_requests'] = False
  764. repo.settings = settings
  765. self.session.add(repo)
  766. self.session.commit()
  767. headers = {'Authorization': 'token aaabbbcccddd'}
  768. output = self.app.post(
  769. '/api/0/test/pull-request/1/close', headers=headers)
  770. self.assertEqual(output.status_code, 404)
  771. data = json.loads(output.get_data(as_text=True))
  772. self.assertDictEqual(
  773. data,
  774. {
  775. u'error': u'Pull-Request have been deactivated for this project',
  776. u'error_code': u'EPULLREQUESTSDISABLED'
  777. }
  778. )
  779. @patch('pagure.lib.notify.send_email')
  780. def test_api_pull_request_close(self, send_email):
  781. """ Test the api_pull_request_close method of the flask api. """
  782. send_email.return_value = True
  783. tests.create_projects(self.session)
  784. tests.create_tokens(self.session)
  785. tests.create_tokens_acl(self.session)
  786. # Create the pull-request to close
  787. repo = pagure.lib.get_authorized_project(self.session, 'test')
  788. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  789. req = pagure.lib.new_pull_request(
  790. session=self.session,
  791. repo_from=forked_repo,
  792. branch_from='master',
  793. repo_to=repo,
  794. branch_to='master',
  795. title='test pull-request',
  796. user='pingou',
  797. )
  798. self.session.commit()
  799. self.assertEqual(req.id, 1)
  800. self.assertEqual(req.title, 'test pull-request')
  801. headers = {'Authorization': 'token aaabbbcccddd'}
  802. # Invalid project
  803. output = self.app.post(
  804. '/api/0/foo/pull-request/1/close', headers=headers)
  805. self.assertEqual(output.status_code, 404)
  806. data = json.loads(output.get_data(as_text=True))
  807. self.assertDictEqual(
  808. data,
  809. {
  810. "error": "Project not found",
  811. "error_code": "ENOPROJECT",
  812. }
  813. )
  814. # Valid token, wrong project
  815. output = self.app.post(
  816. '/api/0/test2/pull-request/1/close', headers=headers)
  817. self.assertEqual(output.status_code, 401)
  818. data = json.loads(output.get_data(as_text=True))
  819. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  820. data['error_code'])
  821. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  822. # Invalid PR
  823. output = self.app.post(
  824. '/api/0/test/pull-request/2/close', headers=headers)
  825. self.assertEqual(output.status_code, 404)
  826. data = json.loads(output.get_data(as_text=True))
  827. self.assertDictEqual(
  828. data,
  829. {'error': 'Pull-Request not found', 'error_code': "ENOREQ"}
  830. )
  831. # Create a token for foo for this project
  832. item = pagure.lib.model.Token(
  833. id='foobar_token',
  834. user_id=2,
  835. project_id=1,
  836. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  837. days=30)
  838. )
  839. self.session.add(item)
  840. self.session.commit()
  841. # Allow the token to close PR
  842. acls = pagure.lib.get_acls(self.session)
  843. for acl in acls:
  844. if acl.name == 'pull_request_close':
  845. break
  846. item = pagure.lib.model.TokenAcl(
  847. token_id='foobar_token',
  848. acl_id=acl.id,
  849. )
  850. self.session.add(item)
  851. self.session.commit()
  852. headers = {'Authorization': 'token foobar_token'}
  853. # User not admin
  854. output = self.app.post(
  855. '/api/0/test/pull-request/1/close', headers=headers)
  856. self.assertEqual(output.status_code, 403)
  857. data = json.loads(output.get_data(as_text=True))
  858. self.assertDictEqual(
  859. data,
  860. {
  861. 'error': 'You are not allowed to merge/close pull-request '
  862. 'for this project',
  863. 'error_code': "ENOPRCLOSE",
  864. }
  865. )
  866. headers = {'Authorization': 'token aaabbbcccddd'}
  867. # Close PR
  868. output = self.app.post(
  869. '/api/0/test/pull-request/1/close', headers=headers)
  870. self.assertEqual(output.status_code, 200)
  871. data = json.loads(output.get_data(as_text=True))
  872. self.assertDictEqual(
  873. data,
  874. {"message": "Pull-request closed!"}
  875. )
  876. @patch('pagure.lib.notify.send_email')
  877. def test_api_pull_request_merge_pr_disabled(self, send_email):
  878. """ Test the api_pull_request_merge method of the flask api when PR
  879. are disabled. """
  880. send_email.return_value = True
  881. tests.create_projects(self.session)
  882. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  883. tests.create_projects_git(os.path.join(self.path, 'requests'),
  884. bare=True)
  885. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  886. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  887. branch='test')
  888. tests.create_tokens(self.session)
  889. tests.create_tokens_acl(self.session)
  890. # Create the pull-request to close
  891. repo = pagure.lib.get_authorized_project(self.session, 'test')
  892. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  893. req = pagure.lib.new_pull_request(
  894. session=self.session,
  895. repo_from=forked_repo,
  896. branch_from='test',
  897. repo_to=repo,
  898. branch_to='master',
  899. title='test pull-request',
  900. user='pingou',
  901. )
  902. self.session.commit()
  903. self.assertEqual(req.id, 1)
  904. self.assertEqual(req.title, 'test pull-request')
  905. repo = pagure.lib.get_authorized_project(self.session, 'test')
  906. settings = repo.settings
  907. settings['pull_requests'] = False
  908. repo.settings = settings
  909. self.session.add(repo)
  910. self.session.commit()
  911. headers = {'Authorization': 'token aaabbbcccddd'}
  912. output = self.app.post(
  913. '/api/0/test/pull-request/1/merge', headers=headers)
  914. self.assertEqual(output.status_code, 404)
  915. data = json.loads(output.get_data(as_text=True))
  916. self.assertDictEqual(
  917. data,
  918. {
  919. u'error': u'Pull-Request have been deactivated for this project',
  920. u'error_code': u'EPULLREQUESTSDISABLED'
  921. }
  922. )
  923. @patch('pagure.lib.notify.send_email')
  924. def test_api_pull_request_merge_only_assigned(self, send_email):
  925. """ Test the api_pull_request_merge method of the flask api when
  926. only assignee can merge the PR and the PR isn't assigned. """
  927. send_email.return_value = True
  928. tests.create_projects(self.session)
  929. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  930. tests.create_projects_git(os.path.join(self.path, 'requests'),
  931. bare=True)
  932. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  933. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  934. branch='test')
  935. tests.create_tokens(self.session)
  936. tests.create_tokens_acl(self.session)
  937. # Create the pull-request to close
  938. repo = pagure.lib.get_authorized_project(self.session, 'test')
  939. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  940. req = pagure.lib.new_pull_request(
  941. session=self.session,
  942. repo_from=forked_repo,
  943. branch_from='test',
  944. repo_to=repo,
  945. branch_to='master',
  946. title='test pull-request',
  947. user='pingou',
  948. )
  949. self.session.commit()
  950. self.assertEqual(req.id, 1)
  951. self.assertEqual(req.title, 'test pull-request')
  952. repo = pagure.lib.get_authorized_project(self.session, 'test')
  953. settings = repo.settings
  954. settings['Only_assignee_can_merge_pull-request'] = True
  955. repo.settings = settings
  956. self.session.add(repo)
  957. self.session.commit()
  958. headers = {'Authorization': 'token aaabbbcccddd'}
  959. output = self.app.post(
  960. '/api/0/test/pull-request/1/merge', headers=headers)
  961. self.assertEqual(output.status_code, 403)
  962. data = json.loads(output.get_data(as_text=True))
  963. self.assertDictEqual(
  964. data,
  965. {
  966. u'error': u'This request must be assigned to be merged',
  967. u'error_code': u'ENOTASSIGNED'
  968. }
  969. )
  970. @patch('pagure.lib.notify.send_email')
  971. def test_api_pull_request_merge_only_assigned_not_assignee(
  972. self, send_email):
  973. """ Test the api_pull_request_merge method of the flask api when
  974. only assignee can merge the PR and the PR isn't assigned to the
  975. user asking to merge. """
  976. send_email.return_value = True
  977. tests.create_projects(self.session)
  978. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  979. tests.create_projects_git(os.path.join(self.path, 'requests'),
  980. bare=True)
  981. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  982. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  983. branch='test')
  984. tests.create_tokens(self.session)
  985. tests.create_tokens_acl(self.session)
  986. # Create the pull-request to close
  987. repo = pagure.lib.get_authorized_project(self.session, 'test')
  988. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  989. req = pagure.lib.new_pull_request(
  990. session=self.session,
  991. repo_from=forked_repo,
  992. branch_from='test',
  993. repo_to=repo,
  994. branch_to='master',
  995. title='test pull-request',
  996. user='pingou',
  997. )
  998. self.session.commit()
  999. self.assertEqual(req.id, 1)
  1000. self.assertEqual(req.title, 'test pull-request')
  1001. req.assignee = pagure.lib.search_user(self.session, 'foo')
  1002. self.session.add(req)
  1003. self.session.commit()
  1004. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1005. settings = repo.settings
  1006. settings['Only_assignee_can_merge_pull-request'] = True
  1007. repo.settings = settings
  1008. self.session.add(repo)
  1009. self.session.commit()
  1010. headers = {'Authorization': 'token aaabbbcccddd'}
  1011. output = self.app.post(
  1012. '/api/0/test/pull-request/1/merge', headers=headers)
  1013. self.assertEqual(output.status_code, 403)
  1014. data = json.loads(output.get_data(as_text=True))
  1015. self.assertDictEqual(
  1016. data,
  1017. {
  1018. u'error': u'Only the assignee can merge this review',
  1019. u'error_code': u'ENOTASSIGNEE'
  1020. }
  1021. )
  1022. @patch('pagure.lib.notify.send_email')
  1023. def test_api_pull_request_merge_minimal_score(self, send_email):
  1024. """ Test the api_pull_request_merge method of the flask api when
  1025. a PR requires a certain minimal score to be merged. """
  1026. send_email.return_value = True
  1027. tests.create_projects(self.session)
  1028. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1029. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1030. bare=True)
  1031. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1032. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1033. branch='test')
  1034. tests.create_tokens(self.session)
  1035. tests.create_tokens_acl(self.session)
  1036. # Create the pull-request to close
  1037. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1038. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  1039. req = pagure.lib.new_pull_request(
  1040. session=self.session,
  1041. repo_from=forked_repo,
  1042. branch_from='test',
  1043. repo_to=repo,
  1044. branch_to='master',
  1045. title='test pull-request',
  1046. user='pingou',
  1047. )
  1048. self.session.commit()
  1049. self.assertEqual(req.id, 1)
  1050. self.assertEqual(req.title, 'test pull-request')
  1051. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1052. settings = repo.settings
  1053. settings['Minimum_score_to_merge_pull-request'] = 2
  1054. repo.settings = settings
  1055. self.session.add(repo)
  1056. self.session.commit()
  1057. headers = {'Authorization': 'token aaabbbcccddd'}
  1058. output = self.app.post(
  1059. '/api/0/test/pull-request/1/merge', headers=headers)
  1060. self.assertEqual(output.status_code, 403)
  1061. data = json.loads(output.get_data(as_text=True))
  1062. self.assertDictEqual(
  1063. data,
  1064. {
  1065. u'error': u'This request does not have the minimum review '
  1066. 'score necessary to be merged',
  1067. u'error_code': u'EPRSCORE'
  1068. }
  1069. )
  1070. @patch('pagure.lib.notify.send_email')
  1071. def test_api_pull_request_merge(self, send_email):
  1072. """ Test the api_pull_request_merge method of the flask api. """
  1073. send_email.return_value = True
  1074. tests.create_projects(self.session)
  1075. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1076. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1077. bare=True)
  1078. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1079. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1080. branch='test')
  1081. tests.create_tokens(self.session)
  1082. tests.create_tokens_acl(self.session)
  1083. # Create the pull-request to close
  1084. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1085. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  1086. req = pagure.lib.new_pull_request(
  1087. session=self.session,
  1088. repo_from=forked_repo,
  1089. branch_from='test',
  1090. repo_to=repo,
  1091. branch_to='master',
  1092. title='test pull-request',
  1093. user='pingou',
  1094. )
  1095. self.session.commit()
  1096. self.assertEqual(req.id, 1)
  1097. self.assertEqual(req.title, 'test pull-request')
  1098. headers = {'Authorization': 'token aaabbbcccddd'}
  1099. # Invalid project
  1100. output = self.app.post(
  1101. '/api/0/foo/pull-request/1/merge', headers=headers)
  1102. self.assertEqual(output.status_code, 404)
  1103. data = json.loads(output.get_data(as_text=True))
  1104. self.assertDictEqual(
  1105. data,
  1106. {
  1107. "error": "Project not found",
  1108. "error_code": "ENOPROJECT",
  1109. }
  1110. )
  1111. # Valid token, wrong project
  1112. output = self.app.post(
  1113. '/api/0/test2/pull-request/1/merge', headers=headers)
  1114. self.assertEqual(output.status_code, 401)
  1115. data = json.loads(output.get_data(as_text=True))
  1116. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  1117. data['error_code'])
  1118. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  1119. # Invalid PR
  1120. output = self.app.post(
  1121. '/api/0/test/pull-request/2/merge', headers=headers)
  1122. self.assertEqual(output.status_code, 404)
  1123. data = json.loads(output.get_data(as_text=True))
  1124. self.assertDictEqual(
  1125. data,
  1126. {'error': 'Pull-Request not found', 'error_code': "ENOREQ"}
  1127. )
  1128. # Create a token for foo for this project
  1129. item = pagure.lib.model.Token(
  1130. id='foobar_token',
  1131. user_id=2,
  1132. project_id=1,
  1133. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  1134. days=30)
  1135. )
  1136. self.session.add(item)
  1137. self.session.commit()
  1138. # Allow the token to merge PR
  1139. acls = pagure.lib.get_acls(self.session)
  1140. for acl in acls:
  1141. if acl.name == 'pull_request_merge':
  1142. break
  1143. item = pagure.lib.model.TokenAcl(
  1144. token_id='foobar_token',
  1145. acl_id=acl.id,
  1146. )
  1147. self.session.add(item)
  1148. self.session.commit()
  1149. headers = {'Authorization': 'token foobar_token'}
  1150. # User not admin
  1151. output = self.app.post(
  1152. '/api/0/test/pull-request/1/merge', headers=headers)
  1153. self.assertEqual(output.status_code, 403)
  1154. data = json.loads(output.get_data(as_text=True))
  1155. self.assertDictEqual(
  1156. data,
  1157. {
  1158. 'error': 'You are not allowed to merge/close pull-request '
  1159. 'for this project',
  1160. 'error_code': "ENOPRCLOSE",
  1161. }
  1162. )
  1163. headers = {'Authorization': 'token aaabbbcccddd'}
  1164. # Merge PR
  1165. output = self.app.post(
  1166. '/api/0/test/pull-request/1/merge', headers=headers)
  1167. self.assertEqual(output.status_code, 200)
  1168. data = json.loads(output.get_data(as_text=True))
  1169. self.assertDictEqual(
  1170. data,
  1171. {"message": "Changes merged!"}
  1172. )
  1173. @patch('pagure.lib.notify.send_email')
  1174. def test_api_pull_request_merge_user_token(self, send_email):
  1175. """ Test the api_pull_request_merge method of the flask api. """
  1176. send_email.return_value = True
  1177. tests.create_projects(self.session)
  1178. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1179. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1180. bare=True)
  1181. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1182. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1183. branch='test')
  1184. tests.create_tokens(self.session, project_id=None)
  1185. tests.create_tokens_acl(self.session)
  1186. # Create the pull-request to close
  1187. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1188. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  1189. req = pagure.lib.new_pull_request(
  1190. session=self.session,
  1191. repo_from=forked_repo,
  1192. branch_from='test',
  1193. repo_to=repo,
  1194. branch_to='master',
  1195. title='test pull-request',
  1196. user='pingou',
  1197. )
  1198. self.session.commit()
  1199. self.assertEqual(req.id, 1)
  1200. self.assertEqual(req.title, 'test pull-request')
  1201. headers = {'Authorization': 'token aaabbbcccddd'}
  1202. # Invalid project
  1203. output = self.app.post(
  1204. '/api/0/foo/pull-request/1/merge', headers=headers)
  1205. self.assertEqual(output.status_code, 404)
  1206. data = json.loads(output.get_data(as_text=True))
  1207. self.assertDictEqual(
  1208. data,
  1209. {
  1210. "error": "Project not found",
  1211. "error_code": "ENOPROJECT",
  1212. }
  1213. )
  1214. # Valid token, invalid PR
  1215. output = self.app.post(
  1216. '/api/0/test2/pull-request/1/merge', headers=headers)
  1217. self.assertEqual(output.status_code, 404)
  1218. data = json.loads(output.get_data(as_text=True))
  1219. self.assertDictEqual(
  1220. data,
  1221. {'error': 'Pull-Request not found', 'error_code': "ENOREQ"}
  1222. )
  1223. # Valid token, invalid PR - other project
  1224. output = self.app.post(
  1225. '/api/0/test/pull-request/2/merge', headers=headers)
  1226. self.assertEqual(output.status_code, 404)
  1227. data = json.loads(output.get_data(as_text=True))
  1228. self.assertDictEqual(
  1229. data,
  1230. {'error': 'Pull-Request not found', 'error_code': "ENOREQ"}
  1231. )
  1232. # Create a token for foo for this project
  1233. item = pagure.lib.model.Token(
  1234. id='foobar_token',
  1235. user_id=2,
  1236. project_id=1,
  1237. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  1238. days=30)
  1239. )
  1240. self.session.add(item)
  1241. self.session.commit()
  1242. # Allow the token to merge PR
  1243. acls = pagure.lib.get_acls(self.session)
  1244. acl = None
  1245. for acl in acls:
  1246. if acl.name == 'pull_request_merge':
  1247. break
  1248. item = pagure.lib.model.TokenAcl(
  1249. token_id='foobar_token',
  1250. acl_id=acl.id,
  1251. )
  1252. self.session.add(item)
  1253. self.session.commit()
  1254. headers = {'Authorization': 'token foobar_token'}
  1255. # User not admin
  1256. output = self.app.post(
  1257. '/api/0/test/pull-request/1/merge', headers=headers)
  1258. self.assertEqual(output.status_code, 403)
  1259. data = json.loads(output.get_data(as_text=True))
  1260. self.assertDictEqual(
  1261. data,
  1262. {
  1263. 'error': 'You are not allowed to merge/close pull-request '
  1264. 'for this project',
  1265. 'error_code': "ENOPRCLOSE",
  1266. }
  1267. )
  1268. headers = {'Authorization': 'token aaabbbcccddd'}
  1269. # Merge PR
  1270. output = self.app.post(
  1271. '/api/0/test/pull-request/1/merge', headers=headers)
  1272. self.assertEqual(output.status_code, 200)
  1273. data = json.loads(output.get_data(as_text=True))
  1274. self.assertDictEqual(
  1275. data,
  1276. {"message": "Changes merged!"}
  1277. )
  1278. @patch('pagure.lib.notify.send_email')
  1279. def test_api_pull_request_add_comment(self, mockemail):
  1280. """ Test the api_pull_request_add_comment method of the flask api. """
  1281. mockemail.return_value = True
  1282. tests.create_projects(self.session)
  1283. tests.create_tokens(self.session)
  1284. tests.create_tokens_acl(self.session)
  1285. headers = {'Authorization': 'token aaabbbcccddd'}
  1286. # Invalid project
  1287. output = self.app.post(
  1288. '/api/0/foo/pull-request/1/comment', headers=headers)
  1289. self.assertEqual(output.status_code, 404)
  1290. data = json.loads(output.get_data(as_text=True))
  1291. self.assertDictEqual(
  1292. data,
  1293. {
  1294. "error": "Project not found",
  1295. "error_code": "ENOPROJECT",
  1296. }
  1297. )
  1298. # Valid token, wrong project
  1299. output = self.app.post(
  1300. '/api/0/test2/pull-request/1/comment', headers=headers)
  1301. self.assertEqual(output.status_code, 401)
  1302. data = json.loads(output.get_data(as_text=True))
  1303. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  1304. data['error_code'])
  1305. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  1306. # No input
  1307. output = self.app.post(
  1308. '/api/0/test/pull-request/1/comment', headers=headers)
  1309. self.assertEqual(output.status_code, 404)
  1310. data = json.loads(output.get_data(as_text=True))
  1311. self.assertDictEqual(
  1312. data,
  1313. {
  1314. "error": "Pull-Request not found",
  1315. "error_code": "ENOREQ",
  1316. }
  1317. )
  1318. # Create a pull-request
  1319. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1320. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  1321. req = pagure.lib.new_pull_request(
  1322. session=self.session,
  1323. repo_from=forked_repo,
  1324. branch_from='master',
  1325. repo_to=repo,
  1326. branch_to='master',
  1327. title='test pull-request',
  1328. user='pingou',
  1329. )
  1330. self.session.commit()
  1331. self.assertEqual(req.id, 1)
  1332. self.assertEqual(req.title, 'test pull-request')
  1333. # Check comments before
  1334. self.session.commit()
  1335. request = pagure.lib.search_pull_requests(
  1336. self.session, project_id=1, requestid=1)
  1337. self.assertEqual(len(request.comments), 0)
  1338. data = {
  1339. 'title': 'test issue',
  1340. }
  1341. # Incomplete request
  1342. output = self.app.post(
  1343. '/api/0/test/pull-request/1/comment', data=data, headers=headers)
  1344. self.assertEqual(output.status_code, 400)
  1345. data = json.loads(output.get_data(as_text=True))
  1346. self.assertDictEqual(
  1347. data,
  1348. {
  1349. "error": "Invalid or incomplete input submitted",
  1350. "error_code": "EINVALIDREQ",
  1351. "errors": {"comment": ["This field is required."]}
  1352. }
  1353. )
  1354. # No change
  1355. self.session.commit()
  1356. request = pagure.lib.search_pull_requests(
  1357. self.session, project_id=1, requestid=1)
  1358. self.assertEqual(len(request.comments), 0)
  1359. data = {
  1360. 'comment': 'This is a very interesting question',
  1361. }
  1362. # Valid request
  1363. output = self.app.post(
  1364. '/api/0/test/pull-request/1/comment', data=data, headers=headers)
  1365. self.assertEqual(output.status_code, 200)
  1366. data = json.loads(output.get_data(as_text=True))
  1367. self.assertDictEqual(
  1368. data,
  1369. {'message': 'Comment added'}
  1370. )
  1371. # One comment added
  1372. self.session.commit()
  1373. request = pagure.lib.search_pull_requests(
  1374. self.session, project_id=1, requestid=1)
  1375. self.assertEqual(len(request.comments), 1)
  1376. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1377. def test_api_pull_request_add_comment_wrong_user(self):
  1378. """ Test the api_pull_request_add_comment method of the flask api
  1379. when the user is not found in the DB. """
  1380. tests.create_projects(self.session)
  1381. tests.create_tokens(self.session, project_id=None)
  1382. tests.create_tokens_acl(self.session)
  1383. headers = {'Authorization': 'token aaabbbcccddd'}
  1384. # Create a pull-request
  1385. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1386. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  1387. req = pagure.lib.new_pull_request(
  1388. session=self.session,
  1389. repo_from=forked_repo,
  1390. branch_from='master',
  1391. repo_to=repo,
  1392. branch_to='master',
  1393. title='test pull-request',
  1394. user='pingou',
  1395. )
  1396. self.session.commit()
  1397. self.assertEqual(req.id, 1)
  1398. self.assertEqual(req.title, 'test pull-request')
  1399. data = {
  1400. 'comment': 'This is a very interesting question',
  1401. }
  1402. # Valid request
  1403. with patch('pagure.lib.add_pull_request_comment',
  1404. side_effect=pagure.exceptions.PagureException('error')):
  1405. output = self.app.post(
  1406. '/api/0/test/pull-request/1/comment', data=data, headers=headers)
  1407. self.assertEqual(output.status_code, 400)
  1408. data = json.loads(output.get_data(as_text=True))
  1409. self.assertDictEqual(
  1410. data,
  1411. {u'error': u'error', u'error_code': u'ENOCODE'}
  1412. )
  1413. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1414. def test_api_pull_request_add_comment_pr_disabled(self):
  1415. """ Test the api_pull_request_add_comment method of the flask api
  1416. when PRs are disabled. """
  1417. tests.create_projects(self.session)
  1418. tests.create_tokens(self.session, project_id=None)
  1419. tests.create_tokens_acl(self.session)
  1420. headers = {'Authorization': 'token aaabbbcccddd'}
  1421. # Create a pull-request
  1422. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1423. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  1424. req = pagure.lib.new_pull_request(
  1425. session=self.session,
  1426. repo_from=forked_repo,
  1427. branch_from='master',
  1428. repo_to=repo,
  1429. branch_to='master',
  1430. title='test pull-request',
  1431. user='pingou',
  1432. )
  1433. self.session.commit()
  1434. self.assertEqual(req.id, 1)
  1435. self.assertEqual(req.title, 'test pull-request')
  1436. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1437. settings = repo.settings
  1438. settings['pull_requests'] = False
  1439. repo.settings = settings
  1440. self.session.add(repo)
  1441. self.session.commit()
  1442. data = {
  1443. 'comment': 'This is a very interesting question',
  1444. }
  1445. # Valid request
  1446. output = self.app.post(
  1447. '/api/0/test/pull-request/1/comment', data=data, headers=headers)
  1448. self.assertEqual(output.status_code, 404)
  1449. data = json.loads(output.get_data(as_text=True))
  1450. self.assertDictEqual(
  1451. data,
  1452. {
  1453. u'error': u'Pull-Request have been deactivated for this project',
  1454. u'error_code': u'EPULLREQUESTSDISABLED'
  1455. }
  1456. )
  1457. # no comment added
  1458. self.session.commit()
  1459. request = pagure.lib.search_pull_requests(
  1460. self.session, project_id=1, requestid=1)
  1461. self.assertEqual(len(request.comments), 0)
  1462. @patch('pagure.lib.notify.send_email')
  1463. def test_api_pull_request_add_comment_user_token(self, mockemail):
  1464. """ Test the api_pull_request_add_comment method of the flask api. """
  1465. mockemail.return_value = True
  1466. tests.create_projects(self.session)
  1467. tests.create_tokens(self.session, project_id=None)
  1468. tests.create_tokens_acl(self.session)
  1469. headers = {'Authorization': 'token aaabbbcccddd'}
  1470. # Invalid project
  1471. output = self.app.post(
  1472. '/api/0/foo/pull-request/1/comment', headers=headers)
  1473. self.assertEqual(output.status_code, 404)
  1474. data = json.loads(output.get_data(as_text=True))
  1475. self.assertDictEqual(
  1476. data,
  1477. {
  1478. "error": "Project not found",
  1479. "error_code": "ENOPROJECT",
  1480. }
  1481. )
  1482. # Valid token, invalid request
  1483. output = self.app.post(
  1484. '/api/0/test2/pull-request/1/comment', headers=headers)
  1485. self.assertEqual(output.status_code, 404)
  1486. data = json.loads(output.get_data(as_text=True))
  1487. self.assertDictEqual(
  1488. data,
  1489. {
  1490. "error": "Pull-Request not found",
  1491. "error_code": "ENOREQ",
  1492. }
  1493. )
  1494. # Valid token, invalid request in another project
  1495. output = self.app.post(
  1496. '/api/0/test/pull-request/1/comment', headers=headers)
  1497. self.assertEqual(output.status_code, 404)
  1498. data = json.loads(output.get_data(as_text=True))
  1499. self.assertDictEqual(
  1500. data,
  1501. {
  1502. "error": "Pull-Request not found",
  1503. "error_code": "ENOREQ",
  1504. }
  1505. )
  1506. # Create a pull-request
  1507. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1508. forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
  1509. req = pagure.lib.new_pull_request(
  1510. session=self.session,
  1511. repo_from=forked_repo,
  1512. branch_from='master',
  1513. repo_to=repo,
  1514. branch_to='master',
  1515. title='test pull-request',
  1516. user='pingou',
  1517. )
  1518. self.session.commit()
  1519. self.assertEqual(req.id, 1)
  1520. self.assertEqual(req.title, 'test pull-request')
  1521. # Check comments before
  1522. self.session.commit()
  1523. request = pagure.lib.search_pull_requests(
  1524. self.session, project_id=1, requestid=1)
  1525. self.assertEqual(len(request.comments), 0)
  1526. data = {
  1527. 'title': 'test issue',
  1528. }
  1529. # Incomplete request
  1530. output = self.app.post(
  1531. '/api/0/test/pull-request/1/comment', data=data, headers=headers)
  1532. self.assertEqual(output.status_code, 400)
  1533. data = json.loads(output.get_data(as_text=True))
  1534. self.assertDictEqual(
  1535. data,
  1536. {
  1537. "error": "Invalid or incomplete input submitted",
  1538. "error_code": "EINVALIDREQ",
  1539. "errors": {"comment": ["This field is required."]}
  1540. }
  1541. )
  1542. # No change
  1543. self.session.commit()
  1544. request = pagure.lib.search_pull_requests(
  1545. self.session, project_id=1, requestid=1)
  1546. self.assertEqual(len(request.comments), 0)
  1547. data = {
  1548. 'comment': 'This is a very interesting question',
  1549. }
  1550. # Valid request
  1551. output = self.app.post(
  1552. '/api/0/test/pull-request/1/comment', data=data, headers=headers)
  1553. self.assertEqual(output.status_code, 200)
  1554. data = json.loads(output.get_data(as_text=True))
  1555. self.assertDictEqual(
  1556. data,
  1557. {'message': 'Comment added'}
  1558. )
  1559. # One comment added
  1560. self.session.commit()
  1561. request = pagure.lib.search_pull_requests(
  1562. self.session, project_id=1, requestid=1)
  1563. self.assertEqual(len(request.comments), 1)
  1564. @patch('pagure.lib.notify.send_email')
  1565. def test_api_subscribe_pull_request_pr_disabled(self, p_send_email):
  1566. """ Test the api_subscribe_pull_request method of the flask api. """
  1567. p_send_email.return_value = True
  1568. tests.create_projects(self.session)
  1569. tests.create_tokens(self.session)
  1570. tests.create_tokens_acl(self.session)
  1571. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1572. settings = repo.settings
  1573. settings['pull_requests'] = False
  1574. repo.settings = settings
  1575. self.session.add(repo)
  1576. self.session.commit()
  1577. headers = {'Authorization': 'token aaabbbcccddd'}
  1578. # Invalid project
  1579. output = self.app.post(
  1580. '/api/0/test/pull-request/1/subscribe', headers=headers)
  1581. self.assertEqual(output.status_code, 404)
  1582. data = json.loads(output.get_data(as_text=True))
  1583. self.assertDictEqual(
  1584. data,
  1585. {
  1586. u'error': u'Pull-Request have been deactivated for this project',
  1587. u'error_code': u'EPULLREQUESTSDISABLED'
  1588. }
  1589. )
  1590. @patch('pagure.lib.git.update_git')
  1591. @patch('pagure.lib.notify.send_email')
  1592. def test_api_subscribe_pull_request_invalid_token(self, p_send_email, p_ugt):
  1593. """ Test the api_subscribe_pull_request method of the flask api. """
  1594. p_send_email.return_value = True
  1595. p_ugt.return_value = True
  1596. item = pagure.lib.model.User(
  1597. user='bar',
  1598. fullname='bar foo',
  1599. password='foo',
  1600. default_email='bar@bar.com',
  1601. )
  1602. self.session.add(item)
  1603. item = pagure.lib.model.UserEmail(
  1604. user_id=3,
  1605. email='bar@bar.com')
  1606. self.session.add(item)
  1607. self.session.commit()
  1608. tests.create_projects(self.session)
  1609. tests.create_tokens(self.session, user_id=3, project_id=2)
  1610. tests.create_tokens_acl(self.session)
  1611. headers = {'Authorization': 'token aaabbbcccddd'}
  1612. # Create pull-request
  1613. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1614. req = pagure.lib.new_pull_request(
  1615. session=self.session,
  1616. repo_from=repo,
  1617. branch_from='feature',
  1618. repo_to=repo,
  1619. branch_to='master',
  1620. title='test pull-request',
  1621. user='pingou',
  1622. )
  1623. self.session.commit()
  1624. self.assertEqual(req.id, 1)
  1625. self.assertEqual(req.title, 'test pull-request')
  1626. # Check subscribtion before
  1627. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1628. request = pagure.lib.search_pull_requests(
  1629. self.session, project_id=1, requestid=1)
  1630. self.assertEqual(
  1631. pagure.lib.get_watch_list(self.session, request),
  1632. set(['pingou']))
  1633. data = {}
  1634. output = self.app.post(
  1635. '/api/0/test/pull-request/1/subscribe',
  1636. data=data, headers=headers)
  1637. self.assertEqual(output.status_code, 401)
  1638. data = json.loads(output.get_data(as_text=True))
  1639. self.assertDictEqual(
  1640. data,
  1641. {
  1642. u'error': u'Invalid or expired token. Please visit '
  1643. 'http://localhost.localdomain/settings#api-keys to get or '
  1644. 'renew your API token.',
  1645. u'error_code': u'EINVALIDTOK'
  1646. }
  1647. )
  1648. @patch('pagure.lib.git.update_git')
  1649. @patch('pagure.lib.notify.send_email')
  1650. def test_api_subscribe_pull_request(self, p_send_email, p_ugt):
  1651. """ Test the api_subscribe_pull_request method of the flask api. """
  1652. p_send_email.return_value = True
  1653. p_ugt.return_value = True
  1654. item = pagure.lib.model.User(
  1655. user='bar',
  1656. fullname='bar foo',
  1657. password='foo',
  1658. default_email='bar@bar.com',
  1659. )
  1660. self.session.add(item)
  1661. item = pagure.lib.model.UserEmail(
  1662. user_id=3,
  1663. email='bar@bar.com')
  1664. self.session.add(item)
  1665. self.session.commit()
  1666. tests.create_projects(self.session)
  1667. tests.create_tokens(self.session, user_id=3)
  1668. tests.create_tokens_acl(self.session)
  1669. headers = {'Authorization': 'token aaabbbcccddd'}
  1670. # Invalid project
  1671. output = self.app.post(
  1672. '/api/0/foo/pull-request/1/subscribe', headers=headers)
  1673. self.assertEqual(output.status_code, 404)
  1674. data = json.loads(output.get_data(as_text=True))
  1675. self.assertDictEqual(
  1676. data,
  1677. {
  1678. "error": "Project not found",
  1679. "error_code": "ENOPROJECT",
  1680. }
  1681. )
  1682. # Valid token, wrong project
  1683. output = self.app.post(
  1684. '/api/0/test2/pull-request/1/subscribe', headers=headers)
  1685. self.assertEqual(output.status_code, 401)
  1686. data = json.loads(output.get_data(as_text=True))
  1687. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  1688. data['error_code'])
  1689. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  1690. # No input
  1691. output = self.app.post(
  1692. '/api/0/test/pull-request/1/subscribe', headers=headers)
  1693. self.assertEqual(output.status_code, 404)
  1694. data = json.loads(output.get_data(as_text=True))
  1695. self.assertDictEqual(
  1696. data,
  1697. {
  1698. 'error': 'Pull-Request not found',
  1699. 'error_code': 'ENOREQ'
  1700. }
  1701. )
  1702. # Create pull-request
  1703. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1704. req = pagure.lib.new_pull_request(
  1705. session=self.session,
  1706. repo_from=repo,
  1707. branch_from='feature',
  1708. repo_to=repo,
  1709. branch_to='master',
  1710. title='test pull-request',
  1711. user='pingou',
  1712. )
  1713. self.session.commit()
  1714. self.assertEqual(req.id, 1)
  1715. self.assertEqual(req.title, 'test pull-request')
  1716. # Check subscribtion before
  1717. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1718. request = pagure.lib.search_pull_requests(
  1719. self.session, project_id=1, requestid=1)
  1720. self.assertEqual(
  1721. pagure.lib.get_watch_list(self.session, request),
  1722. set(['pingou']))
  1723. # Unsubscribe - no changes
  1724. data = {}
  1725. output = self.app.post(
  1726. '/api/0/test/pull-request/1/subscribe',
  1727. data=data, headers=headers)
  1728. self.assertEqual(output.status_code, 200)
  1729. data = json.loads(output.get_data(as_text=True))
  1730. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  1731. self.assertDictEqual(
  1732. data,
  1733. {'message': 'You are no longer watching this pull-request',
  1734. 'avatar_url': 'https://seccdn.libravatar.org/avatar/...',
  1735. 'user': 'bar',
  1736. }
  1737. )
  1738. data = {}
  1739. output = self.app.post(
  1740. '/api/0/test/pull-request/1/subscribe',
  1741. data=data, headers=headers)
  1742. self.assertEqual(output.status_code, 200)
  1743. data = json.loads(output.get_data(as_text=True))
  1744. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  1745. self.assertDictEqual(
  1746. data,
  1747. {'message': 'You are no longer watching this pull-request',
  1748. 'avatar_url': 'https://seccdn.libravatar.org/avatar/...',
  1749. 'user': 'bar',
  1750. }
  1751. )
  1752. # No change
  1753. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1754. request = pagure.lib.search_pull_requests(
  1755. self.session, project_id=1, requestid=1)
  1756. self.assertEqual(
  1757. pagure.lib.get_watch_list(self.session, request),
  1758. set(['pingou']))
  1759. # Subscribe
  1760. data = {'status': True}
  1761. output = self.app.post(
  1762. '/api/0/test/pull-request/1/subscribe',
  1763. data=data, headers=headers)
  1764. self.assertEqual(output.status_code, 200)
  1765. data = json.loads(output.get_data(as_text=True))
  1766. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  1767. self.assertDictEqual(
  1768. data,
  1769. {'message': 'You are now watching this pull-request',
  1770. 'avatar_url': 'https://seccdn.libravatar.org/avatar/...',
  1771. 'user': 'bar',
  1772. }
  1773. )
  1774. # Subscribe - no changes
  1775. data = {'status': True}
  1776. output = self.app.post(
  1777. '/api/0/test/pull-request/1/subscribe',
  1778. data=data, headers=headers)
  1779. self.assertEqual(output.status_code, 200)
  1780. data = json.loads(output.get_data(as_text=True))
  1781. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  1782. self.assertDictEqual(
  1783. data,
  1784. {'message': 'You are now watching this pull-request',
  1785. 'avatar_url': 'https://seccdn.libravatar.org/avatar/...',
  1786. 'user': 'bar',
  1787. }
  1788. )
  1789. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1790. request = pagure.lib.search_pull_requests(
  1791. self.session, project_id=1, requestid=1)
  1792. self.assertEqual(
  1793. pagure.lib.get_watch_list(self.session, request),
  1794. set(['pingou', 'bar']))
  1795. # Unsubscribe
  1796. data = {}
  1797. output = self.app.post(
  1798. '/api/0/test/pull-request/1/subscribe',
  1799. data=data, headers=headers)
  1800. self.assertEqual(output.status_code, 200)
  1801. data = json.loads(output.get_data(as_text=True))
  1802. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  1803. self.assertDictEqual(
  1804. data,
  1805. {'message': 'You are no longer watching this pull-request',
  1806. 'avatar_url': 'https://seccdn.libravatar.org/avatar/...',
  1807. 'user': 'bar',
  1808. }
  1809. )
  1810. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1811. request = pagure.lib.search_pull_requests(
  1812. self.session, project_id=1, requestid=1)
  1813. self.assertEqual(
  1814. pagure.lib.get_watch_list(self.session, request),
  1815. set(['pingou']))
  1816. @patch('pagure.lib.git.update_git')
  1817. @patch('pagure.lib.notify.send_email')
  1818. def test_api_subscribe_pull_request_logged_in(self, p_send_email, p_ugt):
  1819. """ Test the api_subscribe_pull_request method of the flask api
  1820. when the user is logged in via the UI. """
  1821. p_send_email.return_value = True
  1822. p_ugt.return_value = True
  1823. item = pagure.lib.model.User(
  1824. user='bar',
  1825. fullname='bar foo',
  1826. password='foo',
  1827. default_email='bar@bar.com',
  1828. )
  1829. self.session.add(item)
  1830. item = pagure.lib.model.UserEmail(
  1831. user_id=3,
  1832. email='bar@bar.com')
  1833. self.session.add(item)
  1834. self.session.commit()
  1835. tests.create_projects(self.session)
  1836. tests.create_tokens(self.session, user_id=3)
  1837. tests.create_tokens_acl(self.session)
  1838. # Create pull-request
  1839. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1840. req = pagure.lib.new_pull_request(
  1841. session=self.session,
  1842. repo_from=repo,
  1843. branch_from='feature',
  1844. repo_to=repo,
  1845. branch_to='master',
  1846. title='test pull-request',
  1847. user='pingou',
  1848. )
  1849. self.session.commit()
  1850. self.assertEqual(req.id, 1)
  1851. self.assertEqual(req.title, 'test pull-request')
  1852. # Check subscribtion before
  1853. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1854. request = pagure.lib.search_pull_requests(
  1855. self.session, project_id=1, requestid=1)
  1856. self.assertEqual(
  1857. pagure.lib.get_watch_list(self.session, request),
  1858. set(['pingou']))
  1859. # Subscribe
  1860. user = tests.FakeUser(username='foo')
  1861. with tests.user_set(self.app.application, user):
  1862. data = {'status': True}
  1863. output = self.app.post(
  1864. '/api/0/test/pull-request/1/subscribe', data=data)
  1865. self.assertEqual(output.status_code, 200)
  1866. data = json.loads(output.get_data(as_text=True))
  1867. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  1868. self.assertDictEqual(
  1869. data,
  1870. {'message': 'You are now watching this pull-request',
  1871. 'avatar_url': 'https://seccdn.libravatar.org/avatar/...',
  1872. 'user': 'foo',
  1873. }
  1874. )
  1875. # Check subscribtions after
  1876. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1877. request = pagure.lib.search_pull_requests(
  1878. self.session, project_id=1, requestid=1)
  1879. self.assertEqual(
  1880. pagure.lib.get_watch_list(self.session, request),
  1881. set(['pingou', 'foo']))
  1882. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1883. def test_api_pull_request_open_invalid_project(self):
  1884. """ Test the api_pull_request_create method of the flask api when
  1885. not the project doesn't exist.
  1886. """
  1887. tests.create_projects(self.session)
  1888. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1889. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1890. bare=True)
  1891. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1892. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1893. branch='test')
  1894. tests.create_tokens(self.session)
  1895. tests.create_tokens_acl(self.session)
  1896. headers = {'Authorization': 'token aaabbbcccddd'}
  1897. data = {
  1898. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1899. 'branch_to': 'master',
  1900. 'branch_from': 'test',
  1901. }
  1902. output = self.app.post(
  1903. '/api/0/foobar/pull-request/new', headers=headers, data=data)
  1904. self.assertEqual(output.status_code, 404)
  1905. data = json.loads(output.get_data(as_text=True))
  1906. self.assertDictEqual(
  1907. data,
  1908. {'error': 'Project not found', 'error_code': 'ENOPROJECT'}
  1909. )
  1910. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1911. def test_api_pull_request_open_missing_title(self):
  1912. """ Test the api_pull_request_create method of the flask api when
  1913. not title is submitted.
  1914. """
  1915. tests.create_projects(self.session)
  1916. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1917. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1918. bare=True)
  1919. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1920. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1921. branch='test')
  1922. tests.create_tokens(self.session)
  1923. tests.create_tokens_acl(self.session)
  1924. headers = {'Authorization': 'token aaabbbcccddd'}
  1925. data = {
  1926. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1927. 'branch_to': 'master',
  1928. 'branch_from': 'test',
  1929. }
  1930. output = self.app.post(
  1931. '/api/0/test/pull-request/new', headers=headers, data=data)
  1932. self.assertEqual(output.status_code, 400)
  1933. data = json.loads(output.get_data(as_text=True))
  1934. self.assertDictEqual(
  1935. data,
  1936. {
  1937. 'error': 'Invalid or incomplete input submitted',
  1938. 'error_code': 'EINVALIDREQ',
  1939. 'errors': {'title': ['This field is required.']}
  1940. }
  1941. )
  1942. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1943. def test_api_pull_request_open_missing_branch_to(self):
  1944. """ Test the api_pull_request_create method of the flask api when
  1945. not branch to is submitted.
  1946. """
  1947. tests.create_projects(self.session)
  1948. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1949. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1950. bare=True)
  1951. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1952. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1953. branch='test')
  1954. tests.create_tokens(self.session)
  1955. tests.create_tokens_acl(self.session)
  1956. headers = {'Authorization': 'token aaabbbcccddd'}
  1957. data = {
  1958. 'title': 'Test PR',
  1959. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1960. 'branch_from': 'test',
  1961. }
  1962. output = self.app.post(
  1963. '/api/0/test/pull-request/new', headers=headers, data=data)
  1964. self.assertEqual(output.status_code, 400)
  1965. data = json.loads(output.get_data(as_text=True))
  1966. self.assertDictEqual(
  1967. data,
  1968. {
  1969. 'error': 'Invalid or incomplete input submitted',
  1970. 'error_code': 'EINVALIDREQ',
  1971. 'errors': {'branch_to': ['This field is required.']}
  1972. }
  1973. )
  1974. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1975. def test_api_pull_request_open_missing_branch_from(self):
  1976. """ Test the api_pull_request_create method of the flask api when
  1977. not branch from is submitted.
  1978. """
  1979. tests.create_projects(self.session)
  1980. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1981. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1982. bare=True)
  1983. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  1984. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  1985. branch='test')
  1986. tests.create_tokens(self.session)
  1987. tests.create_tokens_acl(self.session)
  1988. headers = {'Authorization': 'token aaabbbcccddd'}
  1989. data = {
  1990. 'title': 'Test PR',
  1991. 'initial_comment': 'Nothing much, the changes speak for themselves',
  1992. 'branch_to': 'master',
  1993. }
  1994. output = self.app.post(
  1995. '/api/0/test/pull-request/new', headers=headers, data=data)
  1996. self.assertEqual(output.status_code, 400)
  1997. data = json.loads(output.get_data(as_text=True))
  1998. self.assertDictEqual(
  1999. data,
  2000. {
  2001. 'error': 'Invalid or incomplete input submitted',
  2002. 'error_code': 'EINVALIDREQ',
  2003. 'errors': {'branch_from': ['This field is required.']}
  2004. }
  2005. )
  2006. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2007. def test_api_pull_request_open_pr_disabled(self):
  2008. """ Test the api_pull_request_create method of the flask api when
  2009. the parent repo disabled pull-requests.
  2010. """
  2011. tests.create_projects(self.session)
  2012. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  2013. tests.create_projects_git(os.path.join(self.path, 'requests'),
  2014. bare=True)
  2015. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  2016. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  2017. branch='test')
  2018. tests.create_tokens(self.session)
  2019. tests.create_tokens_acl(self.session)
  2020. # Check the behavior if the project disabled the issue tracker
  2021. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2022. settings = repo.settings
  2023. settings['pull_requests'] = False
  2024. repo.settings = settings
  2025. self.session.add(repo)
  2026. self.session.commit()
  2027. headers = {'Authorization': 'token aaabbbcccddd'}
  2028. data = {
  2029. 'title': 'Test PR',
  2030. 'initial_comment': 'Nothing much, the changes speak for themselves',
  2031. 'branch_to': 'master',
  2032. 'branch_from': 'test',
  2033. }
  2034. output = self.app.post(
  2035. '/api/0/test/pull-request/new', headers=headers, data=data)
  2036. self.assertEqual(output.status_code, 404)
  2037. data = json.loads(output.get_data(as_text=True))
  2038. self.assertDictEqual(
  2039. data,
  2040. {
  2041. 'error': 'Pull-Request have been deactivated for this project',
  2042. 'error_code': 'EPULLREQUESTSDISABLED'
  2043. }
  2044. )
  2045. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2046. def test_api_pull_request_open_signed_pr(self):
  2047. """ Test the api_pull_request_create method of the flask api when
  2048. the parent repo enforces signed-off pull-requests.
  2049. """
  2050. tests.create_projects(self.session)
  2051. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  2052. tests.create_projects_git(os.path.join(self.path, 'requests'),
  2053. bare=True)
  2054. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  2055. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  2056. branch='test')
  2057. tests.create_tokens(self.session)
  2058. tests.create_tokens_acl(self.session)
  2059. # Check the behavior if the project disabled the issue tracker
  2060. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2061. settings = repo.settings
  2062. settings['Enforce_signed-off_commits_in_pull-request'] = True
  2063. repo.settings = settings
  2064. self.session.add(repo)
  2065. self.session.commit()
  2066. headers = {'Authorization': 'token aaabbbcccddd'}
  2067. data = {
  2068. 'title': 'Test PR',
  2069. 'initial_comment': 'Nothing much, the changes speak for themselves',
  2070. 'branch_to': 'master',
  2071. 'branch_from': 'test',
  2072. }
  2073. output = self.app.post(
  2074. '/api/0/test/pull-request/new', headers=headers, data=data)
  2075. self.assertEqual(output.status_code, 400)
  2076. data = json.loads(output.get_data(as_text=True))
  2077. self.assertDictEqual(
  2078. data,
  2079. {
  2080. 'error': 'This repo enforces that all commits are signed '
  2081. 'off by their author.',
  2082. 'error_code': 'ENOSIGNEDOFF'
  2083. }
  2084. )
  2085. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2086. def test_api_pull_request_open_invalid_branch_from(self):
  2087. """ Test the api_pull_request_create method of the flask api when
  2088. the branch from does not exist.
  2089. """
  2090. tests.create_projects(self.session)
  2091. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  2092. tests.create_projects_git(os.path.join(self.path, 'requests'),
  2093. bare=True)
  2094. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  2095. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  2096. branch='test')
  2097. tests.create_tokens(self.session)
  2098. tests.create_tokens_acl(self.session)
  2099. # Check the behavior if the project disabled the issue tracker
  2100. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2101. settings = repo.settings
  2102. settings['Enforce_signed-off_commits_in_pull-request'] = True
  2103. repo.settings = settings
  2104. self.session.add(repo)
  2105. self.session.commit()
  2106. headers = {'Authorization': 'token aaabbbcccddd'}
  2107. data = {
  2108. 'title': 'Test PR',
  2109. 'initial_comment': 'Nothing much, the changes speak for themselves',
  2110. 'branch_to': 'master',
  2111. 'branch_from': 'foobarbaz',
  2112. }
  2113. output = self.app.post(
  2114. '/api/0/test/pull-request/new', headers=headers, data=data)
  2115. self.assertEqual(output.status_code, 400)
  2116. data = json.loads(output.get_data(as_text=True))
  2117. self.assertDictEqual(
  2118. data,
  2119. {
  2120. 'error': 'Invalid or incomplete input submitted',
  2121. 'error_code': 'EINVALIDREQ',
  2122. 'errors': 'Branch foobarbaz does not exist'
  2123. }
  2124. )
  2125. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2126. def test_api_pull_request_open_invalid_token(self):
  2127. """ Test the api_pull_request_create method of the flask api when
  2128. queried with an invalid token.
  2129. """
  2130. tests.create_projects(self.session)
  2131. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  2132. tests.create_projects_git(os.path.join(self.path, 'requests'),
  2133. bare=True)
  2134. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  2135. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  2136. branch='test')
  2137. tests.create_tokens(self.session)
  2138. tests.create_tokens_acl(self.session)
  2139. headers = {'Authorization': 'token aaabbbcccddd'}
  2140. data = {
  2141. 'title': 'Test PR',
  2142. 'initial_comment': 'Nothing much, the changes speak for themselves',
  2143. 'branch_to': 'master',
  2144. 'branch_from': 'foobarbaz',
  2145. }
  2146. output = self.app.post(
  2147. '/api/0/test2/pull-request/new', headers=headers, data=data)
  2148. self.assertEqual(output.status_code, 401)
  2149. data = json.loads(output.get_data(as_text=True))
  2150. self.assertDictEqual(
  2151. data,
  2152. {
  2153. u'error': u'Invalid or expired token. Please visit '
  2154. 'http://localhost.localdomain/settings#api-keys to get or '
  2155. 'renew your API token.',
  2156. u'error_code': u'EINVALIDTOK',
  2157. }
  2158. )
  2159. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2160. def test_api_pull_request_open_invalid_access(self):
  2161. """ Test the api_pull_request_create method of the flask api when
  2162. the user opening the PR doesn't have commit access.
  2163. """
  2164. tests.create_projects(self.session)
  2165. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  2166. tests.create_projects_git(os.path.join(self.path, 'requests'),
  2167. bare=True)
  2168. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  2169. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  2170. branch='test')
  2171. tests.create_tokens(self.session, user_id=2)
  2172. tests.create_tokens_acl(self.session)
  2173. headers = {'Authorization': 'token aaabbbcccddd'}
  2174. data = {
  2175. 'title': 'Test PR',
  2176. 'initial_comment': 'Nothing much, the changes speak for themselves',
  2177. 'branch_to': 'master',
  2178. 'branch_from': 'foobarbaz',
  2179. }
  2180. output = self.app.post(
  2181. '/api/0/test/pull-request/new', headers=headers, data=data)
  2182. self.assertEqual(output.status_code, 401)
  2183. data = json.loads(output.get_data(as_text=True))
  2184. self.assertDictEqual(
  2185. data,
  2186. {
  2187. u'error': u'You do not have sufficient permissions to '
  2188. u'perform this action',
  2189. u'error_code': u'ENOTHIGHENOUGH'
  2190. }
  2191. )
  2192. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2193. def test_api_pull_request_open_invalid_branch_to(self):
  2194. """ Test the api_pull_request_create method of the flask api when
  2195. the branch to does not exist.
  2196. """
  2197. tests.create_projects(self.session)
  2198. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  2199. tests.create_projects_git(os.path.join(self.path, 'requests'),
  2200. bare=True)
  2201. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  2202. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  2203. branch='test')
  2204. tests.create_tokens(self.session)
  2205. tests.create_tokens_acl(self.session)
  2206. # Check the behavior if the project disabled the issue tracker
  2207. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2208. settings = repo.settings
  2209. settings['Enforce_signed-off_commits_in_pull-request'] = True
  2210. repo.settings = settings
  2211. self.session.add(repo)
  2212. self.session.commit()
  2213. headers = {'Authorization': 'token aaabbbcccddd'}
  2214. data = {
  2215. 'title': 'Test PR',
  2216. 'initial_comment': 'Nothing much, the changes speak for themselves',
  2217. 'branch_to': 'foobarbaz',
  2218. 'branch_from': 'test',
  2219. }
  2220. output = self.app.post(
  2221. '/api/0/test/pull-request/new', headers=headers, data=data)
  2222. self.assertEqual(output.status_code, 400)
  2223. data = json.loads(output.get_data(as_text=True))
  2224. self.assertDictEqual(
  2225. data,
  2226. {
  2227. 'error': 'Invalid or incomplete input submitted',
  2228. 'error_code': 'EINVALIDREQ',
  2229. 'errors': 'Branch foobarbaz could not be found in the '
  2230. 'target repo'
  2231. }
  2232. )
  2233. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2234. def test_api_pull_request_open(self):
  2235. """ Test the api_pull_request_create method of the flask api. """
  2236. tests.create_projects(self.session)
  2237. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  2238. tests.create_projects_git(os.path.join(self.path, 'requests'),
  2239. bare=True)
  2240. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  2241. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  2242. branch='test')
  2243. tests.create_tokens(self.session)
  2244. tests.create_tokens_acl(self.session)
  2245. headers = {'Authorization': 'token aaabbbcccddd'}
  2246. data = {
  2247. 'title': 'Test PR',
  2248. 'initial_comment': 'Nothing much, the changes speak for themselves',
  2249. 'branch_to': 'master',
  2250. 'branch_from': 'test',
  2251. }
  2252. output = self.app.post(
  2253. '/api/0/test/pull-request/new', headers=headers, data=data)
  2254. self.assertEqual(output.status_code, 200)
  2255. data = json.loads(output.get_data(as_text=True))
  2256. data['project']['date_created'] = '1516348115'
  2257. data['project']['date_modified'] = '1516348115'
  2258. data['repo_from']['date_created'] = '1516348115'
  2259. data['repo_from']['date_modified'] = '1516348115'
  2260. data['uid'] = 'e8b68df8711648deac67c3afed15a798'
  2261. data['commit_start'] = '114f1b468a5f05e635fcb6394273f3f907386eab'
  2262. data['commit_stop'] = '114f1b468a5f05e635fcb6394273f3f907386eab'
  2263. data['date_created'] = '1516348115'
  2264. data['last_updated'] = '1516348115'
  2265. data['updated_on'] = '1516348115'
  2266. self.assertDictEqual(
  2267. data,
  2268. {
  2269. 'assignee': None,
  2270. 'branch': 'master',
  2271. 'branch_from': 'test',
  2272. 'cached_merge_status': 'unknown',
  2273. 'closed_at': None,
  2274. 'closed_by': None,
  2275. 'comments': [],
  2276. 'commit_start': '114f1b468a5f05e635fcb6394273f3f907386eab',
  2277. 'commit_stop': '114f1b468a5f05e635fcb6394273f3f907386eab',
  2278. 'date_created': '1516348115',
  2279. 'id': 1,
  2280. 'initial_comment': 'Nothing much, the changes speak for themselves',
  2281. 'last_updated': '1516348115',
  2282. 'project': {'access_groups': {'admin': [],
  2283. 'commit': [],
  2284. 'ticket':[]},
  2285. 'access_users': {'admin': [],
  2286. 'commit': [],
  2287. 'owner': ['pingou'],
  2288. 'ticket': []},
  2289. 'close_status': ['Invalid',
  2290. 'Insufficient data',
  2291. 'Fixed',
  2292. 'Duplicate'],
  2293. 'custom_keys': [],
  2294. 'date_created': '1516348115',
  2295. 'date_modified': '1516348115',
  2296. 'description': 'test project #1',
  2297. 'fullname': 'test',
  2298. 'id': 1,
  2299. 'milestones': {},
  2300. 'name': 'test',
  2301. 'namespace': None,
  2302. 'parent': None,
  2303. 'priorities': {},
  2304. 'tags': [],
  2305. 'url_path': 'test',
  2306. 'user': {'fullname': 'PY C', 'name': 'pingou'}},
  2307. 'remote_git': None,
  2308. 'repo_from': {'access_groups': {'admin': [],
  2309. 'commit': [],
  2310. 'ticket': []},
  2311. 'access_users': {'admin': [],
  2312. 'commit': [],
  2313. 'owner': ['pingou'],
  2314. 'ticket': []},
  2315. 'close_status': ['Invalid',
  2316. 'Insufficient data',
  2317. 'Fixed',
  2318. 'Duplicate'],
  2319. 'custom_keys': [],
  2320. 'date_created': '1516348115',
  2321. 'date_modified': '1516348115',
  2322. 'description': 'test project #1',
  2323. 'fullname': 'test',
  2324. 'id': 1,
  2325. 'milestones': {},
  2326. 'name': 'test',
  2327. 'namespace': None,
  2328. 'parent': None,
  2329. 'priorities': {},
  2330. 'tags': [],
  2331. 'url_path': 'test',
  2332. 'user': {'fullname': 'PY C', 'name': 'pingou'}},
  2333. 'status': 'Open',
  2334. 'title': 'Test PR',
  2335. 'uid': 'e8b68df8711648deac67c3afed15a798',
  2336. 'updated_on': '1516348115',
  2337. 'user': {'fullname': 'PY C', 'name': 'pingou'}
  2338. }
  2339. )
  2340. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2341. def test_api_pull_request_open_missing_initial_comment(self):
  2342. """ Test the api_pull_request_create method of the flask api when
  2343. not initial comment is submitted.
  2344. """
  2345. tests.create_projects(self.session)
  2346. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  2347. tests.create_projects_git(os.path.join(self.path, 'requests'),
  2348. bare=True)
  2349. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  2350. tests.add_commit_git_repo(os.path.join(self.path, 'repos', 'test.git'),
  2351. branch='test')
  2352. tests.create_tokens(self.session)
  2353. tests.create_tokens_acl(self.session)
  2354. headers = {'Authorization': 'token aaabbbcccddd'}
  2355. data = {
  2356. 'title': 'Test PR',
  2357. 'branch_to': 'master',
  2358. 'branch_from': 'test',
  2359. }
  2360. output = self.app.post(
  2361. '/api/0/test/pull-request/new', headers=headers, data=data)
  2362. self.assertEqual(output.status_code, 200)
  2363. data = json.loads(output.get_data(as_text=True))
  2364. data['project']['date_created'] = '1516348115'
  2365. data['project']['date_modified'] = '1516348115'
  2366. data['repo_from']['date_created'] = '1516348115'
  2367. data['repo_from']['date_modified'] = '1516348115'
  2368. data['uid'] = 'e8b68df8711648deac67c3afed15a798'
  2369. data['commit_start'] = '114f1b468a5f05e635fcb6394273f3f907386eab'
  2370. data['commit_stop'] = '114f1b468a5f05e635fcb6394273f3f907386eab'
  2371. data['date_created'] = '1516348115'
  2372. data['last_updated'] = '1516348115'
  2373. data['updated_on'] = '1516348115'
  2374. self.assertDictEqual(
  2375. data,
  2376. {
  2377. 'assignee': None,
  2378. 'branch': 'master',
  2379. 'branch_from': 'test',
  2380. 'cached_merge_status': 'unknown',
  2381. 'closed_at': None,
  2382. 'closed_by': None,
  2383. 'comments': [],
  2384. 'commit_start': '114f1b468a5f05e635fcb6394273f3f907386eab',
  2385. 'commit_stop': '114f1b468a5f05e635fcb6394273f3f907386eab',
  2386. 'date_created': '1516348115',
  2387. 'id': 1,
  2388. 'initial_comment': None,
  2389. 'last_updated': '1516348115',
  2390. 'project': {'access_groups': {'admin': [],
  2391. 'commit': [],
  2392. 'ticket':[]},
  2393. 'access_users': {'admin': [],
  2394. 'commit': [],
  2395. 'owner': ['pingou'],
  2396. 'ticket': []},
  2397. 'close_status': ['Invalid',
  2398. 'Insufficient data',
  2399. 'Fixed',
  2400. 'Duplicate'],
  2401. 'custom_keys': [],
  2402. 'date_created': '1516348115',
  2403. 'date_modified': '1516348115',
  2404. 'description': 'test project #1',
  2405. 'fullname': 'test',
  2406. 'id': 1,
  2407. 'milestones': {},
  2408. 'name': 'test',
  2409. 'namespace': None,
  2410. 'parent': None,
  2411. 'priorities': {},
  2412. 'tags': [],
  2413. 'url_path': 'test',
  2414. 'user': {'fullname': 'PY C', 'name': 'pingou'}},
  2415. 'remote_git': None,
  2416. 'repo_from': {'access_groups': {'admin': [],
  2417. 'commit': [],
  2418. 'ticket': []},
  2419. 'access_users': {'admin': [],
  2420. 'commit': [],
  2421. 'owner': ['pingou'],
  2422. 'ticket': []},
  2423. 'close_status': ['Invalid',
  2424. 'Insufficient data',
  2425. 'Fixed',
  2426. 'Duplicate'],
  2427. 'custom_keys': [],
  2428. 'date_created': '1516348115',
  2429. 'date_modified': '1516348115',
  2430. 'description': 'test project #1',
  2431. 'fullname': 'test',
  2432. 'id': 1,
  2433. 'milestones': {},
  2434. 'name': 'test',
  2435. 'namespace': None,
  2436. 'parent': None,
  2437. 'priorities': {},
  2438. 'tags': [],
  2439. 'url_path': 'test',
  2440. 'user': {'fullname': 'PY C', 'name': 'pingou'}},
  2441. 'status': 'Open',
  2442. 'title': 'Test PR',
  2443. 'uid': 'e8b68df8711648deac67c3afed15a798',
  2444. 'updated_on': '1516348115',
  2445. 'user': {'fullname': 'PY C', 'name': 'pingou'}
  2446. }
  2447. )
  2448. class PagureFlaskApiForkPRDiffStatstests(tests.Modeltests):
  2449. """ Tests for the flask API of pagure for the diff stats endpoint of PRs
  2450. """
  2451. maxDiff = None
  2452. def setUp(self):
  2453. """ Set up the environnment, ran before every tests. """
  2454. super(PagureFlaskApiForkPRDiffStatstests, self).setUp()
  2455. pagure.config.config['REQUESTS_FOLDER'] = None
  2456. tests.create_projects(self.session)
  2457. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  2458. tests.create_projects_git(os.path.join(self.path, 'requests'),
  2459. bare=True)
  2460. tests.add_readme_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  2461. tests.add_commit_git_repo(
  2462. os.path.join(self.path, 'repos', 'test.git'), ncommits=5)
  2463. tests.add_commit_git_repo(
  2464. os.path.join(self.path, 'repos', 'test.git'), branch='test')
  2465. # Create the pull-request to close
  2466. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2467. req = pagure.lib.new_pull_request(
  2468. session=self.session,
  2469. repo_from=repo,
  2470. branch_from='test',
  2471. repo_to=repo,
  2472. branch_to='master',
  2473. title='test pull-request',
  2474. user='pingou',
  2475. )
  2476. self.session.commit()
  2477. self.assertEqual(req.id, 1)
  2478. self.assertEqual(req.title, 'test pull-request')
  2479. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  2480. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2481. def test_api_pull_request_diffstats_no_repo(self):
  2482. """ Test the api_pull_request_merge method of the flask api. """
  2483. output = self.app.get('/api/0/invalid/pull-request/404/diffstats')
  2484. self.assertEqual(output.status_code, 404)
  2485. data = json.loads(output.get_data(as_text=True))
  2486. self.assertEqual(
  2487. data,
  2488. {'error': 'Project not found', 'error_code': 'ENOPROJECT'}
  2489. )
  2490. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  2491. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2492. def test_api_pull_request_diffstats_no_pr(self):
  2493. """ Test the api_pull_request_merge method of the flask api. """
  2494. output = self.app.get('/api/0/test/pull-request/404/diffstats')
  2495. self.assertEqual(output.status_code, 404)
  2496. data = json.loads(output.get_data(as_text=True))
  2497. self.assertEqual(
  2498. data,
  2499. {'error': 'Pull-Request not found', 'error_code': 'ENOREQ'}
  2500. )
  2501. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  2502. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2503. def test_api_pull_request_diffstats_file_modified(self):
  2504. """ Test the api_pull_request_merge method of the flask api. """
  2505. output = self.app.get('/api/0/test/pull-request/1/diffstats')
  2506. self.assertEqual(output.status_code, 200)
  2507. data = json.loads(output.get_data(as_text=True))
  2508. self.assertEqual(
  2509. data,
  2510. {
  2511. 'sources': {
  2512. 'lines_added': 10,
  2513. 'lines_removed': 0,
  2514. 'old_path': 'sources',
  2515. 'status': 'M'
  2516. }
  2517. }
  2518. )
  2519. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  2520. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2521. def test_api_pull_request_diffstats_file_added_mofidied(self):
  2522. """ Test the api_pull_request_merge method of the flask api. """
  2523. tests.add_commit_git_repo(
  2524. os.path.join(self.path, 'repos', 'test.git'), ncommits=5)
  2525. tests.add_readme_git_repo(
  2526. os.path.join(self.path, 'repos', 'test.git'),
  2527. readme_name='README.md', branch='test')
  2528. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2529. self.assertEqual(len(repo.requests), 1)
  2530. output = self.app.get('/api/0/test/pull-request/1/diffstats')
  2531. self.assertEqual(output.status_code, 200)
  2532. data = json.loads(output.get_data(as_text=True))
  2533. self.assertTrue(
  2534. data in
  2535. [
  2536. {
  2537. "README.md": {
  2538. "lines_added": 5,
  2539. "lines_removed": 0,
  2540. "old_path": "README.md",
  2541. "status": "A"
  2542. },
  2543. "sources": {
  2544. "lines_added": 5,
  2545. "lines_removed": 0,
  2546. "old_path": "sources",
  2547. "status": "M"
  2548. }
  2549. },
  2550. {
  2551. "README.md": {
  2552. "lines_added": 5,
  2553. "lines_removed": 0,
  2554. "old_path": "README.md",
  2555. "status": "A"
  2556. },
  2557. "sources": {
  2558. "lines_added": 10,
  2559. "lines_removed": 0,
  2560. "old_path": "sources",
  2561. "status": "M"
  2562. }
  2563. }
  2564. ]
  2565. )
  2566. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  2567. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2568. def test_api_pull_request_diffstats_file_modified_deleted(self):
  2569. """ Test the api_pull_request_merge method of the flask api. """
  2570. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2571. self.assertEqual(len(repo.requests), 1)
  2572. pagure.lib.tasks.update_pull_request(repo.requests[0].uid)
  2573. tests.add_readme_git_repo(
  2574. os.path.join(self.path, 'repos', 'test.git'),
  2575. readme_name='README.md', branch='test')
  2576. tests.remove_file_git_repo(
  2577. os.path.join(self.path, 'repos', 'test.git'),
  2578. filename='sources', branch='test')
  2579. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2580. self.assertEqual(len(repo.requests), 1)
  2581. pagure.lib.tasks.update_pull_request(repo.requests[0].uid)
  2582. output = self.app.get('/api/0/test/pull-request/1/diffstats')
  2583. self.assertEqual(output.status_code, 200)
  2584. data = json.loads(output.get_data(as_text=True))
  2585. self.assertEqual(
  2586. data,
  2587. {
  2588. "README.md": {
  2589. "lines_added": 5,
  2590. "lines_removed": 0,
  2591. "old_path": "README.md",
  2592. "status": "A"
  2593. },
  2594. "sources": {
  2595. "lines_added": 0,
  2596. "lines_removed": 5,
  2597. "old_path": "sources",
  2598. "status": "D"
  2599. }
  2600. }
  2601. )
  2602. if __name__ == '__main__':
  2603. unittest.main(verbosity=2)