test_pagure_flask_api_fork.py 129 KB

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