test_pagure_flask_internal.py 107 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015-2017 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. from __future__ import unicode_literals
  8. __requires__ = ['SQLAlchemy >= 0.8']
  9. import pkg_resources
  10. import datetime
  11. import json
  12. import unittest
  13. import shutil
  14. import sys
  15. import time
  16. import os
  17. import pygit2
  18. from mock import patch, MagicMock, Mock
  19. sys.path.insert(0, os.path.join(os.path.dirname(
  20. os.path.abspath(__file__)), '..'))
  21. import pagure
  22. import pagure.lib
  23. import tests
  24. from pagure.lib.repo import PagureRepo
  25. class PagureFlaskInternaltests(tests.Modeltests):
  26. """ Tests for flask Internal controller of pagure """
  27. maxDiff = None
  28. def setUp(self):
  29. """ Set up the environnment, ran before every tests. """
  30. super(PagureFlaskInternaltests, self).setUp()
  31. pagure.config.config['IP_ALLOWED_INTERNAL'] = list(set(
  32. pagure.config.config['IP_ALLOWED_INTERNAL'] + [None]))
  33. pagure.config.config['GIT_FOLDER'] = os.path.join(
  34. self.path, 'repos')
  35. @patch('pagure.lib.notify.send_email')
  36. def test_pull_request_add_comment(self, send_email):
  37. """ Test the pull_request_add_comment function. """
  38. send_email.return_value = True
  39. tests.create_projects(self.session)
  40. repo = pagure.lib.get_authorized_project(self.session, 'test')
  41. req = pagure.lib.new_pull_request(
  42. session=self.session,
  43. repo_from=repo,
  44. branch_from='feature',
  45. repo_to=repo,
  46. branch_to='master',
  47. title='PR from the feature branch',
  48. user='pingou',
  49. )
  50. self.session.commit()
  51. self.assertEqual(req.id, 1)
  52. self.assertEqual(req.title, 'PR from the feature branch')
  53. request = repo.requests[0]
  54. self.assertEqual(len(request.comments), 0)
  55. self.assertEqual(len(request.discussion), 0)
  56. data = {
  57. 'objid': 'foo',
  58. }
  59. # Wrong http request
  60. output = self.app.post('/pv/pull-request/comment/', data=data)
  61. self.assertEqual(output.status_code, 405)
  62. # Invalid request
  63. output = self.app.put('/pv/pull-request/comment/', data=data)
  64. self.assertEqual(output.status_code, 400)
  65. data = {
  66. 'objid': 'foo',
  67. 'useremail': 'foo@pingou.com',
  68. }
  69. # Invalid objid
  70. output = self.app.put('/pv/pull-request/comment/', data=data)
  71. self.assertEqual(output.status_code, 404)
  72. data = {
  73. 'objid': request.uid,
  74. 'useremail': 'foo@pingou.com',
  75. }
  76. # Valid objid, in-complete data for a comment
  77. output = self.app.put('/pv/pull-request/comment/', data=data)
  78. self.assertEqual(output.status_code, 400)
  79. data = {
  80. 'objid': request.uid,
  81. 'useremail': 'foo@pingou.com',
  82. 'comment': 'Looks good to me!',
  83. }
  84. # Add comment
  85. output = self.app.put('/pv/pull-request/comment/', data=data)
  86. self.assertEqual(output.status_code, 200)
  87. js_data = json.loads(output.get_data(as_text=True))
  88. self.assertDictEqual(js_data, {'message': 'Comment added'})
  89. self.session.commit()
  90. repo = pagure.lib.get_authorized_project(self.session, 'test')
  91. request = repo.requests[0]
  92. self.assertEqual(len(request.comments), 1)
  93. self.assertEqual(len(request.discussion), 1)
  94. # Check the @localonly
  95. before = pagure.config.config['IP_ALLOWED_INTERNAL'][:]
  96. pagure.config.config['IP_ALLOWED_INTERNAL'] = []
  97. output = self.app.put('/pv/pull-request/comment/', data=data)
  98. self.assertEqual(output.status_code, 403)
  99. pagure.config.config['IP_ALLOWED_INTERNAL'] = before[:]
  100. @patch('pagure.lib.notify.send_email')
  101. def test_ticket_add_comment(self, send_email):
  102. """ Test the ticket_add_comment function. """
  103. send_email.return_value = True
  104. tests.create_projects(self.session)
  105. # Create issues to play with
  106. repo = pagure.lib.get_authorized_project(self.session, 'test')
  107. msg = pagure.lib.new_issue(
  108. session=self.session,
  109. repo=repo,
  110. title='Test issue',
  111. content='We should work on this',
  112. user='pingou',
  113. )
  114. self.session.commit()
  115. self.assertEqual(msg.title, 'Test issue')
  116. issue = repo.issues[0]
  117. self.assertEqual(len(issue.comments), 0)
  118. data = {
  119. 'objid': 'foo',
  120. }
  121. # Wrong http request
  122. output = self.app.post('/pv/ticket/comment/', data=data)
  123. self.assertEqual(output.status_code, 405)
  124. # Invalid request
  125. output = self.app.put('/pv/ticket/comment/', data=data)
  126. self.assertEqual(output.status_code, 400)
  127. data = {
  128. 'objid': 'foo',
  129. 'useremail': 'foo@pingou.com',
  130. }
  131. # Invalid objid
  132. output = self.app.put('/pv/ticket/comment/', data=data)
  133. self.assertEqual(output.status_code, 404)
  134. data = {
  135. 'objid': issue.uid,
  136. 'useremail': 'foo@pingou.com',
  137. }
  138. # Valid objid, in-complete data for a comment
  139. output = self.app.put('/pv/ticket/comment/', data=data)
  140. self.assertEqual(output.status_code, 400)
  141. data = {
  142. 'objid': issue.uid,
  143. 'useremail': 'foo@pingou.com',
  144. 'comment': 'Looks good to me!',
  145. }
  146. # Add comment
  147. output = self.app.put('/pv/ticket/comment/', data=data)
  148. self.assertEqual(output.status_code, 200)
  149. js_data = json.loads(output.get_data(as_text=True))
  150. self.assertDictEqual(js_data, {'message': 'Comment added'})
  151. self.session.commit()
  152. repo = pagure.lib.get_authorized_project(self.session, 'test')
  153. issue = repo.issues[0]
  154. self.assertEqual(len(issue.comments), 1)
  155. # Check the @localonly
  156. pagure.config.config['IP_ALLOWED_INTERNAL'].remove(None)
  157. before = pagure.config.config['IP_ALLOWED_INTERNAL'][:]
  158. pagure.config.config['IP_ALLOWED_INTERNAL'] = []
  159. output = self.app.put('/pv/ticket/comment/', data=data)
  160. self.assertEqual(output.status_code, 403)
  161. pagure.config.config['IP_ALLOWED_INTERNAL'] = before[:]
  162. @patch('pagure.lib.notify.send_email')
  163. def test_private_ticket_add_comment(self, send_email):
  164. """ Test the ticket_add_comment function on a private ticket. """
  165. send_email.return_value = True
  166. tests.create_projects(self.session)
  167. # Create issues to play with
  168. repo = pagure.lib.get_authorized_project(self.session, 'test')
  169. msg = pagure.lib.new_issue(
  170. session=self.session,
  171. repo=repo,
  172. title='Test issue',
  173. content='We should work on this, really',
  174. user='pingou',
  175. private=True,
  176. )
  177. self.session.commit()
  178. self.assertEqual(msg.title, 'Test issue')
  179. issue = repo.issues[0]
  180. self.assertEqual(len(issue.comments), 0)
  181. data = {
  182. 'objid': 'foo',
  183. }
  184. # Wrong http request
  185. output = self.app.post('/pv/ticket/comment/', data=data)
  186. self.assertEqual(output.status_code, 405)
  187. # Invalid request
  188. output = self.app.put('/pv/ticket/comment/', data=data)
  189. self.assertEqual(output.status_code, 400)
  190. data = {
  191. 'objid': 'foo',
  192. 'useremail': 'foo@pingou.com',
  193. }
  194. # Invalid objid
  195. output = self.app.put('/pv/ticket/comment/', data=data)
  196. self.assertEqual(output.status_code, 404)
  197. data = {
  198. 'objid': issue.uid,
  199. 'useremail': 'foo@bar.com',
  200. }
  201. # Valid objid, un-allowed user for this (private) ticket
  202. output = self.app.put('/pv/ticket/comment/', data=data)
  203. self.assertEqual(output.status_code, 403)
  204. data = {
  205. 'objid': issue.uid,
  206. 'useremail': 'foo@pingou.com',
  207. }
  208. # Valid objid, un-allowed user for this (private) ticket
  209. output = self.app.put('/pv/ticket/comment/', data=data)
  210. self.assertEqual(output.status_code, 400)
  211. data = {
  212. 'objid': issue.uid,
  213. 'useremail': 'foo@pingou.com',
  214. 'comment': 'Looks good to me!',
  215. }
  216. # Add comment
  217. output = self.app.put('/pv/ticket/comment/', data=data)
  218. self.assertEqual(output.status_code, 200)
  219. js_data = json.loads(output.get_data(as_text=True))
  220. self.assertDictEqual(js_data, {'message': 'Comment added'})
  221. self.session.commit()
  222. repo = pagure.lib.get_authorized_project(self.session, 'test')
  223. issue = repo.issues[0]
  224. self.assertEqual(len(issue.comments), 1)
  225. # Check the @localonly
  226. before = pagure.config.config['IP_ALLOWED_INTERNAL'][:]
  227. pagure.config.config['IP_ALLOWED_INTERNAL'] = []
  228. output = self.app.put('/pv/ticket/comment/', data=data)
  229. self.assertEqual(output.status_code, 403)
  230. pagure.config.config['IP_ALLOWED_INTERNAL'] = before[:]
  231. @patch('pagure.lib.notify.send_email')
  232. def test_private_ticket_add_comment_acl(self, send_email):
  233. """ Test the ticket_add_comment function on a private ticket. """
  234. send_email.return_value = True
  235. tests.create_projects(self.session)
  236. # Create issues to play with
  237. repo = pagure.lib.get_authorized_project(self.session, 'test')
  238. msg = pagure.lib.new_issue(
  239. session=self.session,
  240. repo=repo,
  241. title='Test issue',
  242. content='We should work on this, really',
  243. user='pingou',
  244. private=True,
  245. )
  246. self.session.commit()
  247. self.assertEqual(msg.title, 'Test issue')
  248. repo = pagure.lib.get_authorized_project(self.session, 'test')
  249. issue = repo.issues[0]
  250. self.assertEqual(len(issue.comments), 0)
  251. # Currently, he is just an average user,
  252. # He doesn't have any access in this repo
  253. data = {
  254. 'objid': issue.uid,
  255. 'useremail': 'foo@bar.com',
  256. 'comment': 'Looks good to me!',
  257. }
  258. # Valid objid, un-allowed user for this (private) ticket
  259. output = self.app.put('/pv/ticket/comment/', data=data)
  260. self.assertEqual(output.status_code, 403)
  261. repo = pagure.lib.get_authorized_project(self.session, 'test')
  262. # Let's promote him to be a ticketer
  263. # He shoudn't be able to comment even then though
  264. msg = pagure.lib.add_user_to_project(
  265. self.session,
  266. project=repo,
  267. new_user='foo',
  268. user='pingou',
  269. access='ticket'
  270. )
  271. self.session.commit()
  272. self.assertEqual(msg, 'User added')
  273. repo = pagure.lib.get_authorized_project(self.session, 'test')
  274. self.assertEqual(
  275. sorted([u.username for u in repo.users]), ['foo'])
  276. self.assertEqual(
  277. sorted([u.username for u in repo.committers]), [])
  278. self.assertEqual(
  279. sorted([u.username for u in repo.admins]), [])
  280. output = self.app.put('/pv/ticket/comment/', data=data)
  281. self.assertEqual(output.status_code, 403)
  282. repo = pagure.lib.get_authorized_project(self.session, 'test')
  283. # Let's promote him to be a committer
  284. # He should be able to comment
  285. msg = pagure.lib.add_user_to_project(
  286. self.session,
  287. project=repo,
  288. new_user='foo',
  289. user='pingou',
  290. access='commit'
  291. )
  292. self.session.commit()
  293. self.assertEqual(msg, 'User access updated')
  294. repo = pagure.lib.get_authorized_project(self.session, 'test')
  295. self.assertEqual(
  296. sorted([u.username for u in repo.users]), ['foo'])
  297. self.assertEqual(
  298. sorted([u.username for u in repo.committers]), ['foo'])
  299. self.assertEqual(
  300. sorted([u.username for u in repo.admins]), [])
  301. # Add comment
  302. output = self.app.put('/pv/ticket/comment/', data=data)
  303. self.assertEqual(output.status_code, 200)
  304. js_data = json.loads(output.get_data(as_text=True))
  305. self.assertDictEqual(js_data, {'message': 'Comment added'})
  306. repo = pagure.lib.get_authorized_project(self.session, 'test')
  307. issue = repo.issues[0]
  308. self.assertEqual(len(issue.comments), 1)
  309. # Let's promote him to be a admin
  310. # He should be able to comment
  311. msg = pagure.lib.add_user_to_project(
  312. self.session,
  313. project=repo,
  314. new_user='foo',
  315. user='pingou',
  316. access='admin'
  317. )
  318. self.session.commit()
  319. self.assertEqual(msg, 'User access updated')
  320. repo = pagure.lib.get_authorized_project(self.session, 'test')
  321. self.assertEqual(
  322. sorted([u.username for u in repo.users]), ['foo'])
  323. self.assertEqual(
  324. sorted([u.username for u in repo.committers]), ['foo'])
  325. self.assertEqual(
  326. sorted([u.username for u in repo.admins]), ['foo'])
  327. # Add comment
  328. output = self.app.put('/pv/ticket/comment/', data=data)
  329. self.assertEqual(output.status_code, 200)
  330. js_data = json.loads(output.get_data(as_text=True))
  331. self.assertDictEqual(js_data, {'message': 'Comment added'})
  332. repo = pagure.lib.get_authorized_project(self.session, 'test')
  333. issue = repo.issues[0]
  334. self.assertEqual(len(issue.comments), 2)
  335. # Check the @localonly
  336. before = pagure.config.config['IP_ALLOWED_INTERNAL'][:]
  337. pagure.config.config['IP_ALLOWED_INTERNAL'] = []
  338. output = self.app.put('/pv/ticket/comment/', data=data)
  339. self.assertEqual(output.status_code, 403)
  340. pagure.config.config['IP_ALLOWED_INTERNAL'] = before[:]
  341. @patch('pagure.lib.notify.send_email')
  342. def test_mergeable_request_pull_FF(self, send_email):
  343. """ Test the mergeable_request_pull endpoint with a fast-forward
  344. merge.
  345. """
  346. send_email.return_value = True
  347. # Create a git repo to play with
  348. origgitrepo = os.path.join(self.path, 'repos', 'test.git')
  349. self.assertFalse(os.path.exists(origgitrepo))
  350. os.makedirs(origgitrepo)
  351. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  352. os.makedirs(os.path.join(self.path, 'repos_tmp'))
  353. gitrepo = os.path.join(self.path, 'repos_tmp', 'test.git')
  354. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  355. # Create a file in that git repo
  356. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  357. stream.write('foo\n bar')
  358. repo.index.add('sources')
  359. repo.index.write()
  360. # Commits the files added
  361. tree = repo.index.write_tree()
  362. author = pygit2.Signature(
  363. 'Alice Author', 'alice@authors.tld')
  364. committer = pygit2.Signature(
  365. 'Cecil Committer', 'cecil@committers.tld')
  366. repo.create_commit(
  367. 'refs/heads/master', # the name of the reference to update
  368. author,
  369. committer,
  370. 'Add sources file for testing',
  371. # binary string representing the tree object ID
  372. tree,
  373. # list of binary strings representing parents of the new commit
  374. []
  375. )
  376. first_commit = repo.revparse_single('HEAD')
  377. refname = 'refs/heads/master:refs/heads/master'
  378. ori_remote = repo.remotes[0]
  379. PagureRepo.push(ori_remote, refname)
  380. # Edit the sources file again
  381. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  382. stream.write('foo\n bar\nbaz\n boose')
  383. repo.index.add('sources')
  384. repo.index.write()
  385. # Commits the files added
  386. tree = repo.index.write_tree()
  387. author = pygit2.Signature(
  388. 'Alice Author', 'alice@authors.tld')
  389. committer = pygit2.Signature(
  390. 'Cecil Committer', 'cecil@committers.tld')
  391. repo.create_commit(
  392. 'refs/heads/feature', # the name of the reference to update
  393. author,
  394. committer,
  395. 'Add baz and boose to the sources\n\n There are more objects to '
  396. 'consider',
  397. # binary string representing the tree object ID
  398. tree,
  399. # list of binary strings representing parents of the new commit
  400. [first_commit.oid.hex]
  401. )
  402. second_commit = repo.revparse_single('HEAD')
  403. refname = 'refs/heads/feature:refs/heads/feature'
  404. ori_remote = repo.remotes[0]
  405. PagureRepo.push(ori_remote, refname)
  406. # Create a PR for these changes
  407. tests.create_projects(self.session)
  408. project = pagure.lib.get_authorized_project(self.session, 'test')
  409. req = pagure.lib.new_pull_request(
  410. session=self.session,
  411. repo_from=project,
  412. branch_from='feature',
  413. repo_to=project,
  414. branch_to='master',
  415. title='PR from the feature branch',
  416. user='pingou',
  417. )
  418. self.session.commit()
  419. self.assertEqual(req.id, 1)
  420. self.assertEqual(req.title, 'PR from the feature branch')
  421. # Check if the PR can be merged
  422. data = {
  423. 'objid': 'blah',
  424. }
  425. # Missing CSRF
  426. output = self.app.post('/pv/pull-request/merge', data=data)
  427. self.assertEqual(output.status_code, 400)
  428. user = tests.FakeUser()
  429. user.username = 'pingou'
  430. with tests.user_set(self.app.application, user):
  431. output = self.app.get('/test/adduser')
  432. csrf_token = output.get_data(as_text=True).split(
  433. 'name="csrf_token" type="hidden" value="')[1].split('">')[0]
  434. # Missing request identifier
  435. data = {
  436. 'csrf_token': csrf_token,
  437. }
  438. output = self.app.post('/pv/pull-request/merge', data=data)
  439. self.assertEqual(output.status_code, 404)
  440. # With all the desired information
  441. project = pagure.lib.get_authorized_project(self.session, 'test')
  442. data = {
  443. 'csrf_token': csrf_token,
  444. 'requestid': project.requests[0].uid,
  445. }
  446. output = self.app.post('/pv/pull-request/merge', data=data)
  447. self.assertEqual(output.status_code, 200)
  448. exp = {
  449. "code": "FFORWARD",
  450. "message": "The pull-request can be merged and fast-forwarded",
  451. "short_code": "Ok"
  452. }
  453. js_data = json.loads(output.get_data(as_text=True))
  454. self.assertDictEqual(js_data, exp)
  455. @patch('pagure.lib.notify.send_email')
  456. def test_mergeable_request_pull_no_change(self, send_email):
  457. """ Test the mergeable_request_pull endpoint when there are no
  458. changes to merge.
  459. """
  460. send_email.return_value = True
  461. # Create a git repo to play with
  462. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  463. self.assertFalse(os.path.exists(gitrepo))
  464. os.makedirs(gitrepo)
  465. repo = pygit2.init_repository(gitrepo)
  466. # Create a file in that git repo
  467. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  468. stream.write('foo\n bar')
  469. repo.index.add('sources')
  470. repo.index.write()
  471. # Commits the files added
  472. tree = repo.index.write_tree()
  473. author = pygit2.Signature(
  474. 'Alice Author', 'alice@authors.tld')
  475. committer = pygit2.Signature(
  476. 'Cecil Committer', 'cecil@committers.tld')
  477. repo.create_commit(
  478. 'refs/heads/master', # the name of the reference to update
  479. author,
  480. committer,
  481. 'Add sources file for testing',
  482. # binary string representing the tree object ID
  483. tree,
  484. # list of binary strings representing parents of the new commit
  485. []
  486. )
  487. first_commit = repo.revparse_single('HEAD')
  488. # Edit the sources file again
  489. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  490. stream.write('foo\n bar\nbaz\n boose')
  491. repo.index.add('sources')
  492. repo.index.write()
  493. # Commits the files added
  494. tree = repo.index.write_tree()
  495. author = pygit2.Signature(
  496. 'Alice Author', 'alice@authors.tld')
  497. committer = pygit2.Signature(
  498. 'Cecil Committer', 'cecil@committers.tld')
  499. repo.create_commit(
  500. 'refs/heads/master', # the name of the reference to update
  501. author,
  502. committer,
  503. 'Add baz and boose to the sources\n\n There are more objects to '
  504. 'consider',
  505. # binary string representing the tree object ID
  506. tree,
  507. # list of binary strings representing parents of the new commit
  508. [first_commit.oid.hex]
  509. )
  510. second_commit = repo.revparse_single('HEAD')
  511. # Create a PR for these changes
  512. tests.create_projects(self.session)
  513. project = pagure.lib.get_authorized_project(self.session, 'test')
  514. req = pagure.lib.new_pull_request(
  515. session=self.session,
  516. repo_from=project,
  517. branch_from='master',
  518. repo_to=project,
  519. branch_to='master',
  520. title='PR from the feature branch',
  521. user='pingou',
  522. )
  523. self.session.commit()
  524. self.assertEqual(req.id, 1)
  525. self.assertEqual(req.title, 'PR from the feature branch')
  526. # Check if the PR can be merged
  527. data = {
  528. 'objid': 'blah',
  529. }
  530. # Missing CSRF
  531. output = self.app.post('/pv/pull-request/merge', data=data)
  532. self.assertEqual(output.status_code, 400)
  533. user = tests.FakeUser()
  534. user.username = 'pingou'
  535. with tests.user_set(self.app.application, user):
  536. output = self.app.get('/test/adduser')
  537. csrf_token = output.get_data(as_text=True).split(
  538. 'name="csrf_token" type="hidden" value="')[1].split('">')[0]
  539. # Missing request identifier
  540. data = {
  541. 'csrf_token': csrf_token,
  542. }
  543. output = self.app.post('/pv/pull-request/merge', data=data)
  544. self.assertEqual(output.status_code, 404)
  545. # With all the desired information
  546. project = pagure.lib.get_authorized_project(self.session, 'test')
  547. data = {
  548. 'csrf_token': csrf_token,
  549. 'requestid': project.requests[0].uid,
  550. }
  551. output = self.app.post('/pv/pull-request/merge', data=data)
  552. self.assertEqual(output.status_code, 200)
  553. exp = {
  554. "code": "NO_CHANGE",
  555. "message": "Nothing to change, git is up to date",
  556. "short_code": "No changes"
  557. }
  558. js_data = json.loads(output.get_data(as_text=True))
  559. self.assertDictEqual(js_data, exp)
  560. @patch('pagure.lib.notify.send_email')
  561. def test_mergeable_request_pull_merge(self, send_email):
  562. """ Test the mergeable_request_pull endpoint when the changes can
  563. be merged with a merge commit.
  564. """
  565. send_email.return_value = True
  566. # Create a git repo to play with
  567. origgitrepo = os.path.join(self.path, 'repos', 'test.git')
  568. self.assertFalse(os.path.exists(origgitrepo))
  569. os.makedirs(origgitrepo)
  570. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  571. os.makedirs(os.path.join(self.path, 'repos_tmp'))
  572. gitrepo = os.path.join(self.path, 'repos_tmp', 'test.git')
  573. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  574. # Create a file in that git repo
  575. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  576. stream.write('foo\n bar')
  577. repo.index.add('sources')
  578. repo.index.write()
  579. # Commits the files added
  580. tree = repo.index.write_tree()
  581. author = pygit2.Signature(
  582. 'Alice Author', 'alice@authors.tld')
  583. committer = pygit2.Signature(
  584. 'Cecil Committer', 'cecil@committers.tld')
  585. repo.create_commit(
  586. 'refs/heads/master', # the name of the reference to update
  587. author,
  588. committer,
  589. 'Add sources file for testing',
  590. # binary string representing the tree object ID
  591. tree,
  592. # list of binary strings representing parents of the new commit
  593. []
  594. )
  595. first_commit = repo.revparse_single('HEAD')
  596. refname = 'refs/heads/master:refs/heads/master'
  597. ori_remote = repo.remotes[0]
  598. PagureRepo.push(ori_remote, refname)
  599. # Edit the sources file again
  600. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  601. stream.write('foo\n bar\nbaz\n boose')
  602. repo.index.add('sources')
  603. repo.index.write()
  604. # Commits the files added
  605. tree = repo.index.write_tree()
  606. author = pygit2.Signature(
  607. 'Alice Author', 'alice@authors.tld')
  608. committer = pygit2.Signature(
  609. 'Cecil Committer', 'cecil@committers.tld')
  610. repo.create_commit(
  611. 'refs/heads/feature', # the name of the reference to update
  612. author,
  613. committer,
  614. 'Add baz and boose to the sources\n\n There are more objects to '
  615. 'consider',
  616. # binary string representing the tree object ID
  617. tree,
  618. # list of binary strings representing parents of the new commit
  619. [first_commit.oid.hex]
  620. )
  621. refname = 'refs/heads/feature:refs/heads/feature'
  622. ori_remote = repo.remotes[0]
  623. PagureRepo.push(ori_remote, refname)
  624. # Create another file in the master branch
  625. with open(os.path.join(gitrepo, '.gitignore'), 'w') as stream:
  626. stream.write('*~')
  627. repo.index.add('.gitignore')
  628. repo.index.write()
  629. # Commits the files added
  630. tree = repo.index.write_tree()
  631. author = pygit2.Signature(
  632. 'Alice Author', 'alice@authors.tld')
  633. committer = pygit2.Signature(
  634. 'Cecil Committer', 'cecil@committers.tld')
  635. repo.create_commit(
  636. 'refs/heads/master', # the name of the reference to update
  637. author,
  638. committer,
  639. 'Add .gitignore file for testing',
  640. # binary string representing the tree object ID
  641. tree,
  642. # list of binary strings representing parents of the new commit
  643. [first_commit.oid.hex]
  644. )
  645. refname = 'refs/heads/master:refs/heads/master'
  646. ori_remote = repo.remotes[0]
  647. PagureRepo.push(ori_remote, refname)
  648. # Create a PR for these changes
  649. tests.create_projects(self.session)
  650. project = pagure.lib.get_authorized_project(self.session, 'test')
  651. req = pagure.lib.new_pull_request(
  652. session=self.session,
  653. repo_from=project,
  654. branch_from='feature',
  655. repo_to=project,
  656. branch_to='master',
  657. title='PR from the feature branch',
  658. user='pingou',
  659. )
  660. self.session.commit()
  661. self.assertEqual(req.id, 1)
  662. self.assertEqual(req.title, 'PR from the feature branch')
  663. # Check if the PR can be merged
  664. data = {}
  665. # Missing CSRF
  666. output = self.app.post('/pv/pull-request/merge', data=data)
  667. self.assertEqual(output.status_code, 400)
  668. user = tests.FakeUser()
  669. user.username = 'pingou'
  670. with tests.user_set(self.app.application, user):
  671. output = self.app.get('/test/adduser')
  672. csrf_token = output.get_data(as_text=True).split(
  673. 'name="csrf_token" type="hidden" value="')[1].split('">')[0]
  674. # Missing request identifier
  675. data = {
  676. 'csrf_token': csrf_token,
  677. }
  678. output = self.app.post('/pv/pull-request/merge', data=data)
  679. self.assertEqual(output.status_code, 404)
  680. # With all the desired information
  681. project = pagure.lib.get_authorized_project(self.session, 'test')
  682. data = {
  683. 'csrf_token': csrf_token,
  684. 'requestid': project.requests[0].uid,
  685. 'force': True,
  686. }
  687. output = self.app.post('/pv/pull-request/merge', data=data)
  688. self.assertEqual(output.status_code, 200)
  689. exp = {
  690. "code": "MERGE",
  691. "message": "The pull-request can be merged with a merge commit",
  692. "short_code": "With merge"
  693. }
  694. js_data = json.loads(output.get_data(as_text=True))
  695. self.assertDictEqual(js_data, exp)
  696. # Asking a second time will trigger the cache
  697. data = {
  698. 'csrf_token': csrf_token,
  699. 'requestid': project.requests[0].uid,
  700. }
  701. output = self.app.post('/pv/pull-request/merge', data=data)
  702. self.assertEqual(output.status_code, 200)
  703. exp = {
  704. "code": "MERGE",
  705. "message": "The pull-request can be merged with a merge commit",
  706. "short_code": "With merge"
  707. }
  708. js_data = json.loads(output.get_data(as_text=True))
  709. self.assertDictEqual(js_data, exp)
  710. @patch('pagure.lib.notify.send_email')
  711. def test_mergeable_request_pull_conflicts(self, send_email):
  712. """ Test the mergeable_request_pull endpoint when the changes cannot
  713. be merged due to conflicts.
  714. """
  715. send_email.return_value = True
  716. # Create a git repo to play with
  717. origgitrepo = os.path.join(self.path, 'repos', 'test.git')
  718. self.assertFalse(os.path.exists(origgitrepo))
  719. os.makedirs(origgitrepo)
  720. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  721. os.makedirs(os.path.join(self.path, 'repos_tmp'))
  722. gitrepo = os.path.join(self.path, 'repos_tmp', 'test.git')
  723. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  724. # Create a file in that git repo
  725. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  726. stream.write('foo\n bar')
  727. repo.index.add('sources')
  728. repo.index.write()
  729. # Commits the files added
  730. tree = repo.index.write_tree()
  731. author = pygit2.Signature(
  732. 'Alice Author', 'alice@authors.tld')
  733. committer = pygit2.Signature(
  734. 'Cecil Committer', 'cecil@committers.tld')
  735. repo.create_commit(
  736. 'refs/heads/master', # the name of the reference to update
  737. author,
  738. committer,
  739. 'Add sources file for testing',
  740. # binary string representing the tree object ID
  741. tree,
  742. # list of binary strings representing parents of the new commit
  743. []
  744. )
  745. first_commit = repo.revparse_single('HEAD')
  746. refname = 'refs/heads/master:refs/heads/master'
  747. ori_remote = repo.remotes[0]
  748. PagureRepo.push(ori_remote, refname)
  749. # Edit the sources file again
  750. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  751. stream.write('foo\n bar\nbaz\n boose')
  752. repo.index.add('sources')
  753. repo.index.write()
  754. # Commits the files added
  755. tree = repo.index.write_tree()
  756. author = pygit2.Signature(
  757. 'Alice Author', 'alice@authors.tld')
  758. committer = pygit2.Signature(
  759. 'Cecil Committer', 'cecil@committers.tld')
  760. repo.create_commit(
  761. 'refs/heads/feature', # the name of the reference to update
  762. author,
  763. committer,
  764. 'Add baz and boose to the sources\n\n There are more objects to '
  765. 'consider',
  766. # binary string representing the tree object ID
  767. tree,
  768. # list of binary strings representing parents of the new commit
  769. [first_commit.oid.hex]
  770. )
  771. refname = 'refs/heads/feature:refs/heads/feature'
  772. ori_remote = repo.remotes[0]
  773. PagureRepo.push(ori_remote, refname)
  774. # Create another file in the master branch
  775. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  776. stream.write('foo\n bar\nbaz\n')
  777. repo.index.add('sources')
  778. repo.index.write()
  779. # Commits the files added
  780. tree = repo.index.write_tree()
  781. author = pygit2.Signature(
  782. 'Alice Author', 'alice@authors.tld')
  783. committer = pygit2.Signature(
  784. 'Cecil Committer', 'cecil@committers.tld')
  785. repo.create_commit(
  786. 'refs/heads/master', # the name of the reference to update
  787. author,
  788. committer,
  789. 'Add .gitignore file for testing',
  790. # binary string representing the tree object ID
  791. tree,
  792. # list of binary strings representing parents of the new commit
  793. [first_commit.oid.hex]
  794. )
  795. refname = 'refs/heads/master:refs/heads/master'
  796. ori_remote = repo.remotes[0]
  797. PagureRepo.push(ori_remote, refname)
  798. # Create a PR for these changes
  799. tests.create_projects(self.session)
  800. project = pagure.lib.get_authorized_project(self.session, 'test')
  801. req = pagure.lib.new_pull_request(
  802. session=self.session,
  803. repo_from=project,
  804. branch_from='feature',
  805. repo_to=project,
  806. branch_to='master',
  807. title='PR from the feature branch',
  808. user='pingou',
  809. )
  810. self.session.commit()
  811. self.assertEqual(req.id, 1)
  812. self.assertEqual(req.title, 'PR from the feature branch')
  813. # Check if the PR can be merged
  814. data = {}
  815. # Missing CSRF
  816. output = self.app.post('/pv/pull-request/merge', data=data)
  817. self.assertEqual(output.status_code, 400)
  818. user = tests.FakeUser()
  819. user.username = 'pingou'
  820. with tests.user_set(self.app.application, user):
  821. output = self.app.get('/test/adduser')
  822. csrf_token = output.get_data(as_text=True).split(
  823. 'name="csrf_token" type="hidden" value="')[1].split('">')[0]
  824. # Missing request identifier
  825. data = {
  826. 'csrf_token': csrf_token,
  827. }
  828. output = self.app.post('/pv/pull-request/merge', data=data)
  829. self.assertEqual(output.status_code, 404)
  830. # With all the desired information
  831. project = pagure.lib.get_authorized_project(self.session, 'test')
  832. data = {
  833. 'csrf_token': csrf_token,
  834. 'requestid': project.requests[0].uid,
  835. }
  836. output = self.app.post('/pv/pull-request/merge', data=data)
  837. self.assertEqual(output.status_code, 200)
  838. exp = {
  839. "code": "CONFLICTS",
  840. "message": "The pull-request cannot be merged due to conflicts",
  841. "short_code": "Conflicts"
  842. }
  843. js_data = json.loads(output.get_data(as_text=True))
  844. self.assertDictEqual(js_data, exp)
  845. @patch('pagure.lib.notify.send_email')
  846. def test_mergeable_request_pull_merge_no_nonff_merges(self, send_email):
  847. """ Test the mergeable_request_pull endpoint when the changes can
  848. be merged with a merge commit, but project settings prohibit this.
  849. """
  850. send_email.return_value = True
  851. # Create a git repo to play with
  852. origgitrepo = os.path.join(self.path, 'repos', 'test.git')
  853. self.assertFalse(os.path.exists(origgitrepo))
  854. os.makedirs(origgitrepo)
  855. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  856. os.makedirs(os.path.join(self.path, 'repos_tmp'))
  857. gitrepo = os.path.join(self.path, 'repos_tmp', 'test.git')
  858. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  859. # Create a file in that git repo
  860. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  861. stream.write('foo\n bar')
  862. repo.index.add('sources')
  863. repo.index.write()
  864. # Commits the files added
  865. tree = repo.index.write_tree()
  866. author = pygit2.Signature(
  867. 'Alice Author', 'alice@authors.tld')
  868. committer = pygit2.Signature(
  869. 'Cecil Committer', 'cecil@committers.tld')
  870. repo.create_commit(
  871. 'refs/heads/master', # the name of the reference to update
  872. author,
  873. committer,
  874. 'Add sources file for testing',
  875. # binary string representing the tree object ID
  876. tree,
  877. # list of binary strings representing parents of the new commit
  878. []
  879. )
  880. first_commit = repo.revparse_single('HEAD')
  881. refname = 'refs/heads/master:refs/heads/master'
  882. ori_remote = repo.remotes[0]
  883. PagureRepo.push(ori_remote, refname)
  884. # Edit the sources file again
  885. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  886. stream.write('foo\n bar\nbaz\n boose')
  887. repo.index.add('sources')
  888. repo.index.write()
  889. # Commits the files added
  890. tree = repo.index.write_tree()
  891. author = pygit2.Signature(
  892. 'Alice Author', 'alice@authors.tld')
  893. committer = pygit2.Signature(
  894. 'Cecil Committer', 'cecil@committers.tld')
  895. repo.create_commit(
  896. 'refs/heads/feature', # the name of the reference to update
  897. author,
  898. committer,
  899. 'Add baz and boose to the sources\n\n There are more objects to '
  900. 'consider',
  901. # binary string representing the tree object ID
  902. tree,
  903. # list of binary strings representing parents of the new commit
  904. [first_commit.oid.hex]
  905. )
  906. refname = 'refs/heads/feature:refs/heads/feature'
  907. ori_remote = repo.remotes[0]
  908. PagureRepo.push(ori_remote, refname)
  909. # Create another file in the master branch
  910. with open(os.path.join(gitrepo, '.gitignore'), 'w') as stream:
  911. stream.write('*~')
  912. repo.index.add('.gitignore')
  913. repo.index.write()
  914. # Commits the files added
  915. tree = repo.index.write_tree()
  916. author = pygit2.Signature(
  917. 'Alice Author', 'alice@authors.tld')
  918. committer = pygit2.Signature(
  919. 'Cecil Committer', 'cecil@committers.tld')
  920. repo.create_commit(
  921. 'refs/heads/master', # the name of the reference to update
  922. author,
  923. committer,
  924. 'Add .gitignore file for testing',
  925. # binary string representing the tree object ID
  926. tree,
  927. # list of binary strings representing parents of the new commit
  928. [first_commit.oid.hex]
  929. )
  930. refname = 'refs/heads/master:refs/heads/master'
  931. ori_remote = repo.remotes[0]
  932. PagureRepo.push(ori_remote, refname)
  933. # Create a PR for these changes
  934. tests.create_projects(self.session)
  935. project = pagure.lib.get_authorized_project(self.session, 'test')
  936. req = pagure.lib.new_pull_request(
  937. session=self.session,
  938. repo_from=project,
  939. branch_from='feature',
  940. repo_to=project,
  941. branch_to='master',
  942. title='PR from the feature branch',
  943. user='pingou',
  944. )
  945. settings = {'disable_non_fast-forward_merges': True}
  946. project.settings = settings
  947. self.session.commit()
  948. self.assertEqual(req.id, 1)
  949. self.assertEqual(req.title, 'PR from the feature branch')
  950. # Check if the PR can be merged
  951. data = {}
  952. user = tests.FakeUser()
  953. user.username = 'pingou'
  954. with tests.user_set(self.app.application, user):
  955. output = self.app.get('/test/adduser')
  956. csrf_token = output.get_data(as_text=True).split(
  957. 'name="csrf_token" type="hidden" value="')[1].split('">')[0]
  958. # With all the desired information
  959. project = pagure.lib.get_authorized_project(self.session, 'test')
  960. data = {
  961. 'csrf_token': csrf_token,
  962. 'requestid': project.requests[0].uid,
  963. 'force': True,
  964. }
  965. output = self.app.post('/pv/pull-request/merge', data=data)
  966. self.assertEqual(output.status_code, 200)
  967. exp = {
  968. "code": "CONFLICTS",
  969. "message": "The pull-request must be rebased before merging",
  970. "short_code": "Conflicts"
  971. }
  972. js_data = json.loads(output.get_data(as_text=True))
  973. self.assertDictEqual(js_data, exp)
  974. # Asking a second time will trigger the cache
  975. data = {
  976. 'csrf_token': csrf_token,
  977. 'requestid': project.requests[0].uid,
  978. }
  979. output = self.app.post('/pv/pull-request/merge', data=data)
  980. self.assertEqual(output.status_code, 200)
  981. exp = {
  982. "code": "CONFLICTS",
  983. "message": "The pull-request must be rebased before merging",
  984. "short_code": "Conflicts"
  985. }
  986. js_data = json.loads(output.get_data(as_text=True))
  987. self.assertDictEqual(js_data, exp)
  988. @patch('pagure.lib.notify.send_email')
  989. def test_mergeable_request_pull_minimum_score(self, send_email):
  990. """ Test the mergeable_request_pull endpoint when the changes can
  991. be merged with a merge FF, but project settings enforces vote on
  992. the PR.
  993. """
  994. send_email.return_value = True
  995. # Create a git repo to play with
  996. origgitrepo = os.path.join(self.path, 'repos', 'test.git')
  997. self.assertFalse(os.path.exists(origgitrepo))
  998. os.makedirs(origgitrepo)
  999. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  1000. os.makedirs(os.path.join(self.path, 'repos_tmp'))
  1001. gitrepo = os.path.join(self.path, 'repos_tmp', 'test.git')
  1002. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  1003. # Create a file in that git repo
  1004. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  1005. stream.write('foo\n bar')
  1006. repo.index.add('sources')
  1007. repo.index.write()
  1008. # Commits the files added
  1009. tree = repo.index.write_tree()
  1010. author = pygit2.Signature(
  1011. 'Alice Author', 'alice@authors.tld')
  1012. committer = pygit2.Signature(
  1013. 'Cecil Committer', 'cecil@committers.tld')
  1014. repo.create_commit(
  1015. 'refs/heads/master', # the name of the reference to update
  1016. author,
  1017. committer,
  1018. 'Add sources file for testing',
  1019. # binary string representing the tree object ID
  1020. tree,
  1021. # list of binary strings representing parents of the new commit
  1022. []
  1023. )
  1024. first_commit = repo.revparse_single('HEAD')
  1025. refname = 'refs/heads/master:refs/heads/master'
  1026. ori_remote = repo.remotes[0]
  1027. PagureRepo.push(ori_remote, refname)
  1028. # Edit the sources file again
  1029. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  1030. stream.write('foo\n bar\nbaz\n boose')
  1031. repo.index.add('sources')
  1032. repo.index.write()
  1033. # Commits the files added
  1034. tree = repo.index.write_tree()
  1035. author = pygit2.Signature(
  1036. 'Alice Author', 'alice@authors.tld')
  1037. committer = pygit2.Signature(
  1038. 'Cecil Committer', 'cecil@committers.tld')
  1039. repo.create_commit(
  1040. 'refs/heads/feature', # the name of the reference to update
  1041. author,
  1042. committer,
  1043. 'Add baz and boose to the sources\n\n There are more objects to '
  1044. 'consider',
  1045. # binary string representing the tree object ID
  1046. tree,
  1047. # list of binary strings representing parents of the new commit
  1048. [first_commit.oid.hex]
  1049. )
  1050. refname = 'refs/heads/feature:refs/heads/feature'
  1051. ori_remote = repo.remotes[0]
  1052. PagureRepo.push(ori_remote, refname)
  1053. # Create a PR for these changes
  1054. tests.create_projects(self.session)
  1055. project = pagure.lib.get_authorized_project(self.session, 'test')
  1056. req = pagure.lib.new_pull_request(
  1057. session=self.session,
  1058. repo_from=project,
  1059. branch_from='feature',
  1060. repo_to=project,
  1061. branch_to='master',
  1062. title='PR from the feature branch',
  1063. user='pingou',
  1064. )
  1065. settings = {'Minimum_score_to_merge_pull-request': 2}
  1066. project.settings = settings
  1067. self.session.commit()
  1068. self.assertEqual(req.id, 1)
  1069. self.assertEqual(req.title, 'PR from the feature branch')
  1070. # Check if the PR can be merged
  1071. data = {}
  1072. user = tests.FakeUser()
  1073. user.username = 'pingou'
  1074. with tests.user_set(self.app.application, user):
  1075. output = self.app.get('/test/adduser')
  1076. csrf_token = output.get_data(as_text=True).split(
  1077. 'name="csrf_token" type="hidden" value="')[1].split('">')[0]
  1078. # With all the desired information
  1079. project = pagure.lib.get_authorized_project(self.session, 'test')
  1080. data = {
  1081. 'csrf_token': csrf_token,
  1082. 'requestid': project.requests[0].uid,
  1083. 'force': True,
  1084. }
  1085. output = self.app.post('/pv/pull-request/merge', data=data)
  1086. self.assertEqual(output.status_code, 400)
  1087. exp = {
  1088. "code": "CONFLICTS",
  1089. "message": "Pull-Request does not meet the minimal number "
  1090. "of review required: 0/2"
  1091. }
  1092. js_data = json.loads(output.get_data(as_text=True))
  1093. self.assertDictEqual(js_data, exp)
  1094. # Asking a second time will trigger the cache
  1095. data = {
  1096. 'csrf_token': csrf_token,
  1097. 'requestid': project.requests[0].uid,
  1098. }
  1099. output = self.app.post('/pv/pull-request/merge', data=data)
  1100. self.assertEqual(output.status_code, 400)
  1101. exp = {
  1102. "code": "CONFLICTS",
  1103. "message": "Pull-Request does not meet the minimal number "
  1104. "of review required: 0/2"
  1105. }
  1106. js_data = json.loads(output.get_data(as_text=True))
  1107. self.assertDictEqual(js_data, exp)
  1108. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1109. @patch(
  1110. 'pagure.lib.git.merge_pull_request',
  1111. MagicMock(side_effect=pagure.exceptions.PagureException('error')))
  1112. def test_mergeable_request_pull_merge_pagureerror(self):
  1113. """ Test the mergeable_request_pull endpoint when the backend
  1114. raises an GitError exception.
  1115. """
  1116. # Create a git repo to play with
  1117. origgitrepo = os.path.join(self.path, 'repos', 'test.git')
  1118. self.assertFalse(os.path.exists(origgitrepo))
  1119. os.makedirs(origgitrepo)
  1120. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  1121. os.makedirs(os.path.join(self.path, 'repos_tmp'))
  1122. gitrepo = os.path.join(self.path, 'repos_tmp', 'test.git')
  1123. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  1124. # Create a file in that git repo
  1125. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  1126. stream.write('foo\n bar')
  1127. repo.index.add('sources')
  1128. repo.index.write()
  1129. # Commits the files added
  1130. tree = repo.index.write_tree()
  1131. author = pygit2.Signature(
  1132. 'Alice Author', 'alice@authors.tld')
  1133. committer = pygit2.Signature(
  1134. 'Cecil Committer', 'cecil@committers.tld')
  1135. repo.create_commit(
  1136. 'refs/heads/master', # the name of the reference to update
  1137. author,
  1138. committer,
  1139. 'Add sources file for testing',
  1140. # binary string representing the tree object ID
  1141. tree,
  1142. # list of binary strings representing parents of the new commit
  1143. []
  1144. )
  1145. first_commit = repo.revparse_single('HEAD')
  1146. refname = 'refs/heads/master:refs/heads/master'
  1147. ori_remote = repo.remotes[0]
  1148. PagureRepo.push(ori_remote, refname)
  1149. # Edit the sources file again
  1150. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  1151. stream.write('foo\n bar\nbaz\n boose')
  1152. repo.index.add('sources')
  1153. repo.index.write()
  1154. # Commits the files added
  1155. tree = repo.index.write_tree()
  1156. author = pygit2.Signature(
  1157. 'Alice Author', 'alice@authors.tld')
  1158. committer = pygit2.Signature(
  1159. 'Cecil Committer', 'cecil@committers.tld')
  1160. repo.create_commit(
  1161. 'refs/heads/feature', # the name of the reference to update
  1162. author,
  1163. committer,
  1164. 'Add baz and boose to the sources\n\n There are more objects to '
  1165. 'consider',
  1166. # binary string representing the tree object ID
  1167. tree,
  1168. # list of binary strings representing parents of the new commit
  1169. [first_commit.oid.hex]
  1170. )
  1171. refname = 'refs/heads/feature:refs/heads/feature'
  1172. ori_remote = repo.remotes[0]
  1173. PagureRepo.push(ori_remote, refname)
  1174. # Create another file in the master branch
  1175. with open(os.path.join(gitrepo, '.gitignore'), 'w') as stream:
  1176. stream.write('*~')
  1177. repo.index.add('.gitignore')
  1178. repo.index.write()
  1179. # Commits the files added
  1180. tree = repo.index.write_tree()
  1181. author = pygit2.Signature(
  1182. 'Alice Author', 'alice@authors.tld')
  1183. committer = pygit2.Signature(
  1184. 'Cecil Committer', 'cecil@committers.tld')
  1185. repo.create_commit(
  1186. 'refs/heads/master', # the name of the reference to update
  1187. author,
  1188. committer,
  1189. 'Add .gitignore file for testing',
  1190. # binary string representing the tree object ID
  1191. tree,
  1192. # list of binary strings representing parents of the new commit
  1193. [first_commit.oid.hex]
  1194. )
  1195. refname = 'refs/heads/master:refs/heads/master'
  1196. ori_remote = repo.remotes[0]
  1197. PagureRepo.push(ori_remote, refname)
  1198. # Create a PR for these changes
  1199. tests.create_projects(self.session)
  1200. project = pagure.lib.get_authorized_project(self.session, 'test')
  1201. req = pagure.lib.new_pull_request(
  1202. session=self.session,
  1203. repo_from=project,
  1204. branch_from='feature',
  1205. repo_to=project,
  1206. branch_to='master',
  1207. title='PR from the feature branch',
  1208. user='pingou',
  1209. )
  1210. self.session.commit()
  1211. self.assertEqual(req.id, 1)
  1212. self.assertEqual(req.title, 'PR from the feature branch')
  1213. # Check if the PR can be merged
  1214. data = {}
  1215. user = tests.FakeUser()
  1216. user.username = 'pingou'
  1217. with tests.user_set(self.app.application, user):
  1218. output = self.app.get('/test/adduser')
  1219. csrf_token = self.get_csrf(output=output)
  1220. # With all the desired information
  1221. project = pagure.lib.get_authorized_project(self.session, 'test')
  1222. data = {
  1223. 'csrf_token': csrf_token,
  1224. 'requestid': project.requests[0].uid,
  1225. 'force': True,
  1226. }
  1227. output = self.app.post('/pv/pull-request/merge', data=data)
  1228. self.assertEqual(output.status_code, 500)
  1229. exp = {u'code': u'CONFLICTS', u'message': u'error'}
  1230. js_data = json.loads(output.get_data(as_text=True))
  1231. self.assertDictEqual(js_data, exp)
  1232. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1233. @patch(
  1234. 'pagure.lib.git.merge_pull_request',
  1235. MagicMock(side_effect=pygit2.GitError('git error')))
  1236. def test_mergeable_request_pull_merge_giterror(self):
  1237. """ Test the mergeable_request_pull endpoint when the backend
  1238. raises an GitError exception.
  1239. """
  1240. # Create a git repo to play with
  1241. origgitrepo = os.path.join(self.path, 'repos', 'test.git')
  1242. self.assertFalse(os.path.exists(origgitrepo))
  1243. os.makedirs(origgitrepo)
  1244. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  1245. os.makedirs(os.path.join(self.path, 'repos_tmp'))
  1246. gitrepo = os.path.join(self.path, 'repos_tmp', 'test.git')
  1247. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  1248. # Create a file in that git repo
  1249. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  1250. stream.write('foo\n bar')
  1251. repo.index.add('sources')
  1252. repo.index.write()
  1253. # Commits the files added
  1254. tree = repo.index.write_tree()
  1255. author = pygit2.Signature(
  1256. 'Alice Author', 'alice@authors.tld')
  1257. committer = pygit2.Signature(
  1258. 'Cecil Committer', 'cecil@committers.tld')
  1259. repo.create_commit(
  1260. 'refs/heads/master', # the name of the reference to update
  1261. author,
  1262. committer,
  1263. 'Add sources file for testing',
  1264. # binary string representing the tree object ID
  1265. tree,
  1266. # list of binary strings representing parents of the new commit
  1267. []
  1268. )
  1269. first_commit = repo.revparse_single('HEAD')
  1270. refname = 'refs/heads/master:refs/heads/master'
  1271. ori_remote = repo.remotes[0]
  1272. PagureRepo.push(ori_remote, refname)
  1273. # Edit the sources file again
  1274. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  1275. stream.write('foo\n bar\nbaz\n boose')
  1276. repo.index.add('sources')
  1277. repo.index.write()
  1278. # Commits the files added
  1279. tree = repo.index.write_tree()
  1280. author = pygit2.Signature(
  1281. 'Alice Author', 'alice@authors.tld')
  1282. committer = pygit2.Signature(
  1283. 'Cecil Committer', 'cecil@committers.tld')
  1284. repo.create_commit(
  1285. 'refs/heads/feature', # the name of the reference to update
  1286. author,
  1287. committer,
  1288. 'Add baz and boose to the sources\n\n There are more objects to '
  1289. 'consider',
  1290. # binary string representing the tree object ID
  1291. tree,
  1292. # list of binary strings representing parents of the new commit
  1293. [first_commit.oid.hex]
  1294. )
  1295. refname = 'refs/heads/feature:refs/heads/feature'
  1296. ori_remote = repo.remotes[0]
  1297. PagureRepo.push(ori_remote, refname)
  1298. # Create another file in the master branch
  1299. with open(os.path.join(gitrepo, '.gitignore'), 'w') as stream:
  1300. stream.write('*~')
  1301. repo.index.add('.gitignore')
  1302. repo.index.write()
  1303. # Commits the files added
  1304. tree = repo.index.write_tree()
  1305. author = pygit2.Signature(
  1306. 'Alice Author', 'alice@authors.tld')
  1307. committer = pygit2.Signature(
  1308. 'Cecil Committer', 'cecil@committers.tld')
  1309. repo.create_commit(
  1310. 'refs/heads/master', # the name of the reference to update
  1311. author,
  1312. committer,
  1313. 'Add .gitignore file for testing',
  1314. # binary string representing the tree object ID
  1315. tree,
  1316. # list of binary strings representing parents of the new commit
  1317. [first_commit.oid.hex]
  1318. )
  1319. refname = 'refs/heads/master:refs/heads/master'
  1320. ori_remote = repo.remotes[0]
  1321. PagureRepo.push(ori_remote, refname)
  1322. # Create a PR for these changes
  1323. tests.create_projects(self.session)
  1324. project = pagure.lib.get_authorized_project(self.session, 'test')
  1325. req = pagure.lib.new_pull_request(
  1326. session=self.session,
  1327. repo_from=project,
  1328. branch_from='feature',
  1329. repo_to=project,
  1330. branch_to='master',
  1331. title='PR from the feature branch',
  1332. user='pingou',
  1333. )
  1334. self.session.commit()
  1335. self.assertEqual(req.id, 1)
  1336. self.assertEqual(req.title, 'PR from the feature branch')
  1337. # Check if the PR can be merged
  1338. data = {}
  1339. user = tests.FakeUser()
  1340. user.username = 'pingou'
  1341. with tests.user_set(self.app.application, user):
  1342. output = self.app.get('/test/adduser')
  1343. csrf_token = self.get_csrf(output=output)
  1344. # With all the desired information
  1345. project = pagure.lib.get_authorized_project(self.session, 'test')
  1346. data = {
  1347. 'csrf_token': csrf_token,
  1348. 'requestid': project.requests[0].uid,
  1349. 'force': True,
  1350. }
  1351. output = self.app.post('/pv/pull-request/merge', data=data)
  1352. self.assertEqual(output.status_code, 409)
  1353. exp = {u'code': u'CONFLICTS', u'message': u'git error'}
  1354. js_data = json.loads(output.get_data(as_text=True))
  1355. self.assertDictEqual(js_data, exp)
  1356. def test_get_branches_of_commit(self):
  1357. ''' Test the get_branches_of_commit from the internal API. '''
  1358. tests.create_projects(self.session)
  1359. tests.create_projects_git(os.path.join(self.path, 'repos'))
  1360. user = tests.FakeUser()
  1361. user.username = 'pingou'
  1362. with tests.user_set(self.app.application, user):
  1363. output = self.app.get('/test/adduser')
  1364. self.assertEqual(output.status_code, 200)
  1365. csrf_token = output.get_data(as_text=True).split(
  1366. 'name="csrf_token" type="hidden" value="')[1].split('">')[0]
  1367. # No CSRF token
  1368. data = {
  1369. 'repo': 'fakerepo',
  1370. 'commit_id': 'foo',
  1371. }
  1372. output = self.app.post('/pv/branches/commit/', data=data)
  1373. self.assertEqual(output.status_code, 400)
  1374. js_data = json.loads(output.get_data(as_text=True))
  1375. self.assertDictEqual(
  1376. js_data,
  1377. {'code': 'ERROR', 'message': 'Invalid input submitted'}
  1378. )
  1379. # Invalid repo
  1380. data = {
  1381. 'repo': 'fakerepo',
  1382. 'commit_id': 'foo',
  1383. 'csrf_token': csrf_token,
  1384. }
  1385. output = self.app.post('/pv/branches/commit/', data=data)
  1386. self.assertEqual(output.status_code, 404)
  1387. js_data = json.loads(output.get_data(as_text=True))
  1388. self.assertDictEqual(
  1389. js_data,
  1390. {
  1391. 'code': 'ERROR',
  1392. 'message': 'No repo found with the information provided'
  1393. }
  1394. )
  1395. # Rigth repo, no commit
  1396. data = {
  1397. 'repo': 'test',
  1398. 'csrf_token': csrf_token,
  1399. }
  1400. output = self.app.post('/pv/branches/commit/', data=data)
  1401. self.assertEqual(output.status_code, 400)
  1402. js_data = json.loads(output.get_data(as_text=True))
  1403. self.assertDictEqual(
  1404. js_data,
  1405. {'code': 'ERROR', 'message': 'No commit id submitted'}
  1406. )
  1407. # Request is fine, but git repo doesn't exist
  1408. item = pagure.lib.model.Project(
  1409. user_id=1, # pingou
  1410. name='test20',
  1411. description='test project #20',
  1412. hook_token='aaabbbhhh',
  1413. )
  1414. self.session.add(item)
  1415. self.session.commit()
  1416. data = {
  1417. 'repo': 'test20',
  1418. 'commit_id': 'foo',
  1419. 'csrf_token': csrf_token,
  1420. }
  1421. output = self.app.post('/pv/branches/commit/', data=data)
  1422. self.assertEqual(output.status_code, 404)
  1423. js_data = json.loads(output.get_data(as_text=True))
  1424. self.assertDictEqual(
  1425. js_data,
  1426. {
  1427. 'code': 'ERROR',
  1428. 'message': 'No git repo found with the information provided'
  1429. }
  1430. )
  1431. # Create a git repo to play with
  1432. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  1433. self.assertTrue(os.path.exists(gitrepo))
  1434. repo = pygit2.Repository(gitrepo)
  1435. # Create a file in that git repo
  1436. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  1437. stream.write('foo\n bar')
  1438. repo.index.add('sources')
  1439. repo.index.write()
  1440. # Commits the files added
  1441. tree = repo.index.write_tree()
  1442. author = pygit2.Signature(
  1443. 'Alice Author', 'alice@authors.tld')
  1444. committer = pygit2.Signature(
  1445. 'Cecil Committer', 'cecil@committers.tld')
  1446. repo.create_commit(
  1447. 'refs/heads/master', # the name of the reference to update
  1448. author,
  1449. committer,
  1450. 'Add sources file for testing',
  1451. # binary string representing the tree object ID
  1452. tree,
  1453. # list of binary strings representing parents of the new commit
  1454. []
  1455. )
  1456. first_commit = repo.revparse_single('HEAD')
  1457. # Edit the sources file again
  1458. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  1459. stream.write('foo\n bar\nbaz\n boose')
  1460. repo.index.add('sources')
  1461. repo.index.write()
  1462. # Commits the files added
  1463. tree = repo.index.write_tree()
  1464. author = pygit2.Signature(
  1465. 'Alice Author', 'alice@authors.tld')
  1466. committer = pygit2.Signature(
  1467. 'Cecil Committer', 'cecil@committers.tld')
  1468. repo.create_commit(
  1469. 'refs/heads/feature', # the name of the reference to update
  1470. author,
  1471. committer,
  1472. 'Add baz and boose to the sources\n\n There are more objects to '
  1473. 'consider',
  1474. # binary string representing the tree object ID
  1475. tree,
  1476. # list of binary strings representing parents of the new commit
  1477. [first_commit.oid.hex]
  1478. )
  1479. # Create another file in the master branch
  1480. with open(os.path.join(gitrepo, '.gitignore'), 'w') as stream:
  1481. stream.write('*~')
  1482. repo.index.add('.gitignore')
  1483. repo.index.write()
  1484. # Commits the files added
  1485. tree = repo.index.write_tree()
  1486. author = pygit2.Signature(
  1487. 'Alice Author', 'alice@authors.tld')
  1488. committer = pygit2.Signature(
  1489. 'Cecil Committer', 'cecil@committers.tld')
  1490. commit_hash = repo.create_commit(
  1491. 'refs/heads/feature_branch', # the name of the reference to update
  1492. author,
  1493. committer,
  1494. 'Add .gitignore file for testing',
  1495. # binary string representing the tree object ID
  1496. tree,
  1497. # list of binary strings representing parents of the new commit
  1498. [first_commit.oid.hex]
  1499. )
  1500. # All good but the commit id
  1501. data = {
  1502. 'repo': 'test',
  1503. 'commit_id': 'foo',
  1504. 'csrf_token': csrf_token,
  1505. }
  1506. output = self.app.post('/pv/branches/commit/', data=data)
  1507. self.assertEqual(output.status_code, 404)
  1508. js_data = json.loads(output.get_data(as_text=True))
  1509. self.assertDictEqual(
  1510. js_data,
  1511. {
  1512. 'code': 'ERROR',
  1513. 'message': 'This commit could not be found in this repo'
  1514. }
  1515. )
  1516. # All good
  1517. data = {
  1518. 'repo': 'test',
  1519. 'commit_id': commit_hash,
  1520. 'csrf_token': csrf_token,
  1521. }
  1522. output = self.app.post('/pv/branches/commit/', data=data)
  1523. self.assertEqual(output.status_code, 200)
  1524. js_data = json.loads(output.get_data(as_text=True))
  1525. self.assertDictEqual(
  1526. js_data,
  1527. {
  1528. 'code': 'OK',
  1529. 'branches': ['feature_branch'],
  1530. }
  1531. )
  1532. def test_get_branches_of_commit_with_unrelated_branches(self):
  1533. ''' Test the get_branches_of_commit from the internal API. '''
  1534. tests.create_projects(self.session)
  1535. tests.create_projects_git(os.path.join(self.path, 'repos'))
  1536. user = tests.FakeUser(username='pingou')
  1537. with tests.user_set(self.app.application, user):
  1538. csrf_token = self.get_csrf()
  1539. # Create a git repo to play with
  1540. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  1541. self.assertTrue(os.path.exists(gitrepo))
  1542. repo = pygit2.Repository(gitrepo)
  1543. # Create a file in that git repo
  1544. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  1545. stream.write('foo\n bar')
  1546. repo.index.add('sources')
  1547. repo.index.write()
  1548. # Commits the files added
  1549. tree = repo.index.write_tree()
  1550. author = pygit2.Signature(
  1551. 'Alice Author', 'alice@authors.tld')
  1552. committer = pygit2.Signature(
  1553. 'Cecil Committer', 'cecil@committers.tld')
  1554. repo.create_commit(
  1555. 'refs/heads/master', # the name of the reference to update
  1556. author,
  1557. committer,
  1558. 'Add sources file for testing',
  1559. # binary string representing the tree object ID
  1560. tree,
  1561. # list of binary strings representing parents of the new commit
  1562. []
  1563. )
  1564. first_commit = repo.revparse_single('HEAD')
  1565. # Edit the sources file again
  1566. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  1567. stream.write('foo\n bar\nbaz\n boose')
  1568. repo.index.add('sources')
  1569. repo.index.write()
  1570. # Commits the files added, but unrelated with the first commit
  1571. tree = repo.index.write_tree()
  1572. author = pygit2.Signature(
  1573. 'Alice Author', 'alice@authors.tld')
  1574. committer = pygit2.Signature(
  1575. 'Cecil Committer', 'cecil@committers.tld')
  1576. commit = repo.create_commit(
  1577. 'refs/heads/feature', # the name of the reference to update
  1578. author,
  1579. committer,
  1580. 'Add baz and boose to the sources\n\n There are more objects to '
  1581. 'consider',
  1582. # binary string representing the tree object ID
  1583. tree,
  1584. # list of binary strings representing parents of the new commit
  1585. []
  1586. )
  1587. commit_hash = commit.hex
  1588. # All good
  1589. data = {
  1590. 'repo': 'test',
  1591. 'commit_id': commit_hash,
  1592. 'csrf_token': csrf_token,
  1593. }
  1594. output = self.app.post('/pv/branches/commit/', data=data)
  1595. self.assertEqual(output.status_code, 200)
  1596. js_data = json.loads(output.get_data(as_text=True))
  1597. self.assertDictEqual(
  1598. js_data,
  1599. {
  1600. u'code': u'OK',
  1601. u'branches': ['feature'],
  1602. }
  1603. )
  1604. def test_get_branches_head(self):
  1605. ''' Test the get_branches_head from the internal API. '''
  1606. tests.create_projects(self.session)
  1607. tests.create_projects_git(os.path.join(self.path, 'repos'))
  1608. user = tests.FakeUser()
  1609. user.username = 'pingou'
  1610. with tests.user_set(self.app.application, user):
  1611. csrf_token = self.get_csrf()
  1612. # No CSRF token
  1613. data = {
  1614. 'repo': 'fakerepo',
  1615. }
  1616. output = self.app.post('/pv/branches/heads/', data=data)
  1617. self.assertEqual(output.status_code, 400)
  1618. js_data = json.loads(output.get_data(as_text=True))
  1619. self.assertDictEqual(
  1620. js_data,
  1621. {'code': 'ERROR', 'message': 'Invalid input submitted'}
  1622. )
  1623. # Invalid repo
  1624. data = {
  1625. 'repo': 'fakerepo',
  1626. 'commit_id': 'foo',
  1627. 'csrf_token': csrf_token,
  1628. }
  1629. output = self.app.post('/pv/branches/heads/', data=data)
  1630. self.assertEqual(output.status_code, 404)
  1631. js_data = json.loads(output.get_data(as_text=True))
  1632. self.assertDictEqual(
  1633. js_data,
  1634. {
  1635. 'code': 'ERROR',
  1636. 'message': 'No repo found with the information provided'
  1637. }
  1638. )
  1639. # Rigth repo, no commit
  1640. data = {
  1641. 'repo': 'test',
  1642. 'csrf_token': csrf_token,
  1643. }
  1644. output = self.app.post('/pv/branches/heads/', data=data)
  1645. self.assertEqual(output.status_code, 200)
  1646. js_data = json.loads(output.get_data(as_text=True))
  1647. self.assertDictEqual(
  1648. js_data,
  1649. {"branches": {}, "code": "OK", "heads": {}}
  1650. )
  1651. # Request is fine, but git repo doesn't exist
  1652. item = pagure.lib.model.Project(
  1653. user_id=1, # pingou
  1654. name='test20',
  1655. description='test project #20',
  1656. hook_token='aaabbbhhh',
  1657. )
  1658. self.session.add(item)
  1659. self.session.commit()
  1660. data = {
  1661. 'repo': 'test20',
  1662. 'csrf_token': csrf_token,
  1663. }
  1664. output = self.app.post('/pv/branches/heads/', data=data)
  1665. self.assertEqual(output.status_code, 404)
  1666. js_data = json.loads(output.get_data(as_text=True))
  1667. self.assertDictEqual(
  1668. js_data,
  1669. {
  1670. 'code': 'ERROR',
  1671. 'message': 'No git repo found with the information provided'
  1672. }
  1673. )
  1674. # Create a git repo to play with
  1675. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  1676. self.assertTrue(os.path.exists(gitrepo))
  1677. repo = pygit2.Repository(gitrepo)
  1678. # Create a file in that git repo
  1679. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  1680. stream.write('foo\n bar')
  1681. repo.index.add('sources')
  1682. repo.index.write()
  1683. # Commits the files added
  1684. tree = repo.index.write_tree()
  1685. author = pygit2.Signature(
  1686. 'Alice Author', 'alice@authors.tld')
  1687. committer = pygit2.Signature(
  1688. 'Cecil Committer', 'cecil@committers.tld')
  1689. repo.create_commit(
  1690. 'refs/heads/master', # the name of the reference to update
  1691. author,
  1692. committer,
  1693. 'Add sources file for testing',
  1694. # binary string representing the tree object ID
  1695. tree,
  1696. # list of binary strings representing parents of the new commit
  1697. []
  1698. )
  1699. first_commit = repo.revparse_single('HEAD')
  1700. # Edit the sources file again
  1701. with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
  1702. stream.write('foo\n bar\nbaz\n boose')
  1703. repo.index.add('sources')
  1704. repo.index.write()
  1705. # Commits the files added
  1706. tree = repo.index.write_tree()
  1707. author = pygit2.Signature(
  1708. 'Alice Author', 'alice@authors.tld')
  1709. committer = pygit2.Signature(
  1710. 'Cecil Committer', 'cecil@committers.tld')
  1711. repo.create_commit(
  1712. 'refs/heads/feature', # the name of the reference to update
  1713. author,
  1714. committer,
  1715. 'Add baz and boose to the sources\n\n There are more objects to '
  1716. 'consider',
  1717. # binary string representing the tree object ID
  1718. tree,
  1719. # list of binary strings representing parents of the new commit
  1720. [first_commit.oid.hex]
  1721. )
  1722. # Create another file in the master branch
  1723. with open(os.path.join(gitrepo, '.gitignore'), 'w') as stream:
  1724. stream.write('*~')
  1725. repo.index.add('.gitignore')
  1726. repo.index.write()
  1727. # Commits the files added
  1728. tree = repo.index.write_tree()
  1729. author = pygit2.Signature(
  1730. 'Alice Author', 'alice@authors.tld')
  1731. committer = pygit2.Signature(
  1732. 'Cecil Committer', 'cecil@committers.tld')
  1733. commit_hash = repo.create_commit(
  1734. 'refs/heads/feature_branch', # the name of the reference to update
  1735. author,
  1736. committer,
  1737. 'Add .gitignore file for testing',
  1738. # binary string representing the tree object ID
  1739. tree,
  1740. # list of binary strings representing parents of the new commit
  1741. [first_commit.oid.hex]
  1742. )
  1743. # All good
  1744. data = {
  1745. 'repo': 'test',
  1746. 'csrf_token': csrf_token,
  1747. }
  1748. output = self.app.post('/pv/branches/heads/', data=data)
  1749. self.assertEqual(output.status_code, 200)
  1750. js_data = json.loads(output.get_data(as_text=True))
  1751. # We can't test the content since the commit hash will change all
  1752. # the time, so let's just check the structure
  1753. self.assertEqual(
  1754. sorted(js_data.keys()), ['branches', 'code', 'heads'])
  1755. self.assertEqual(js_data['code'], 'OK')
  1756. self.assertEqual(len(js_data['heads']), 3)
  1757. self.assertEqual(len(js_data['branches']), 3)
  1758. def test_get_stats_commits_no_token(self):
  1759. ''' Test the get_stats_commits from the internal API. '''
  1760. # No CSRF token
  1761. data = {
  1762. 'repo': 'fakerepo',
  1763. }
  1764. output = self.app.post('/pv/stats/commits/authors', data=data)
  1765. self.assertEqual(output.status_code, 400)
  1766. js_data = json.loads(output.get_data(as_text=True))
  1767. self.assertDictEqual(
  1768. js_data,
  1769. {'code': 'ERROR', 'message': 'Invalid input submitted'}
  1770. )
  1771. def test_get_stats_commits_invalid_repo(self):
  1772. ''' Test the get_stats_commits from the internal API. '''
  1773. user = tests.FakeUser()
  1774. user.username = 'pingou'
  1775. with tests.user_set(self.app.application, user):
  1776. csrf_token = self.get_csrf()
  1777. # Invalid repo
  1778. data = {
  1779. 'repo': 'fakerepo',
  1780. 'csrf_token': csrf_token,
  1781. }
  1782. output = self.app.post('/pv/stats/commits/authors', data=data)
  1783. self.assertEqual(output.status_code, 404)
  1784. js_data = json.loads(output.get_data(as_text=True))
  1785. self.assertDictEqual(
  1786. js_data,
  1787. {'code': 'ERROR',
  1788. 'message': 'No repo found with the information provided'}
  1789. )
  1790. def test_get_stats_commits_empty_git(self):
  1791. ''' Test the get_stats_commits from the internal API. '''
  1792. tests.create_projects(self.session)
  1793. tests.create_projects_git(os.path.join(self.path, 'repos'))
  1794. user = tests.FakeUser()
  1795. user.username = 'pingou'
  1796. with tests.user_set(self.app.application, user):
  1797. csrf_token = self.get_csrf()
  1798. # No content in git
  1799. data = {
  1800. 'repo': 'test',
  1801. 'csrf_token': csrf_token,
  1802. }
  1803. output = self.app.post('/pv/stats/commits/authors', data=data)
  1804. self.assertEqual(output.status_code, 200)
  1805. js_data = json.loads(output.get_data(as_text=True))
  1806. self.assertEqual(
  1807. sorted(js_data.keys()),
  1808. ['code', 'message', 'task_id', 'url']
  1809. )
  1810. self.assertEqual(js_data['code'], 'OK')
  1811. self.assertEqual(js_data['message'], 'Stats asked')
  1812. self.assertTrue(js_data['url'].startswith('/pv/task/'))
  1813. output = self.app.get(js_data['url'])
  1814. js_data2 = json.loads(output.get_data(as_text=True))
  1815. self.assertTrue(
  1816. js_data2 in [
  1817. {'results': "reference 'refs/heads/master' not found"},
  1818. {'results': "Reference 'refs/heads/master' not found"}
  1819. ]
  1820. )
  1821. def test_get_stats_commits_git_populated(self):
  1822. ''' Test the get_stats_commits from the internal API. '''
  1823. tests.create_projects(self.session)
  1824. tests.create_projects_git(
  1825. os.path.join(self.path, 'repos'), bare=True)
  1826. tests.add_content_git_repo(
  1827. os.path.join(self.path, 'repos', 'test.git'))
  1828. user = tests.FakeUser()
  1829. user.username = 'pingou'
  1830. with tests.user_set(self.app.application, user):
  1831. csrf_token = self.get_csrf()
  1832. # Content in git
  1833. data = {
  1834. 'repo': 'test',
  1835. 'csrf_token': csrf_token,
  1836. }
  1837. output = self.app.post('/pv/stats/commits/authors', data=data)
  1838. self.assertEqual(output.status_code, 200)
  1839. js_data = json.loads(output.get_data(as_text=True))
  1840. self.assertEqual(
  1841. sorted(js_data.keys()),
  1842. ['code', 'message', 'task_id', 'url']
  1843. )
  1844. self.assertEqual(js_data['code'], 'OK')
  1845. self.assertEqual(js_data['message'], 'Stats asked')
  1846. self.assertTrue(js_data['url'].startswith('/pv/task/'))
  1847. output = self.app.get(js_data['url'])
  1848. while output.status_code == 418:
  1849. time.sleep(0.5)
  1850. output = self.app.get(js_data['url'])
  1851. js_data2 = json.loads(output.get_data(as_text=True))
  1852. self.assertTrue(js_data2['results'][3] > 1509110062)
  1853. js_data2['results'][3] = 1509110062
  1854. self.assertDictEqual(
  1855. js_data2,
  1856. {'results': [
  1857. 2,
  1858. [[2, [['Alice Author', 'alice@authors.tld']]]],
  1859. 1,
  1860. 1509110062
  1861. ]
  1862. }
  1863. )
  1864. def test_get_stats_commits_trend_no_token(self):
  1865. ''' Test the get_stats_commits_trend from the internal API. '''
  1866. # No CSRF token
  1867. data = {
  1868. 'repo': 'fakerepo',
  1869. }
  1870. output = self.app.post('/pv/stats/commits/trend', data=data)
  1871. self.assertEqual(output.status_code, 400)
  1872. js_data = json.loads(output.get_data(as_text=True))
  1873. self.assertDictEqual(
  1874. js_data,
  1875. {'code': 'ERROR', 'message': 'Invalid input submitted'}
  1876. )
  1877. def test_get_stats_commits_trend_invalid_repo(self):
  1878. """ Test the get_stats_commits_trend from the internal API. """
  1879. user = tests.FakeUser()
  1880. user.username = 'pingou'
  1881. with tests.user_set(self.app.application, user):
  1882. csrf_token = self.get_csrf()
  1883. # Invalid repo
  1884. data = {
  1885. 'repo': 'fakerepo',
  1886. 'csrf_token': csrf_token,
  1887. }
  1888. output = self.app.post('/pv/stats/commits/trend', data=data)
  1889. self.assertEqual(output.status_code, 404)
  1890. js_data = json.loads(output.get_data(as_text=True))
  1891. self.assertDictEqual(
  1892. js_data,
  1893. {'code': 'ERROR',
  1894. 'message': 'No repo found with the information provided'}
  1895. )
  1896. def test_get_stats_commits_trend_empty_git(self):
  1897. ''' Test the get_stats_commits_trend from the internal API. '''
  1898. tests.create_projects(self.session)
  1899. tests.create_projects_git(os.path.join(self.path, 'repos'))
  1900. user = tests.FakeUser()
  1901. user.username = 'pingou'
  1902. with tests.user_set(self.app.application, user):
  1903. csrf_token = self.get_csrf()
  1904. # No content in git
  1905. data = {
  1906. 'repo': 'test',
  1907. 'csrf_token': csrf_token,
  1908. }
  1909. output = self.app.post('/pv/stats/commits/trend', data=data)
  1910. self.assertEqual(output.status_code, 200)
  1911. js_data = json.loads(output.get_data(as_text=True))
  1912. self.assertEqual(
  1913. sorted(js_data.keys()),
  1914. ['code', 'message', 'task_id', 'url']
  1915. )
  1916. self.assertEqual(js_data['code'], 'OK')
  1917. self.assertEqual(js_data['message'], 'Stats asked')
  1918. self.assertTrue(js_data['url'].startswith('/pv/task/'))
  1919. output = self.app.get(js_data['url'])
  1920. js_data2 = json.loads(output.get_data(as_text=True))
  1921. self.assertTrue(
  1922. js_data2 in [
  1923. {'results': "reference 'refs/heads/master' not found"},
  1924. {'results': "Reference 'refs/heads/master' not found"}
  1925. ]
  1926. )
  1927. def test_get_stats_commits_trend_git_populated(self):
  1928. ''' Test the get_stats_commits_trend from the internal API. '''
  1929. tests.create_projects(self.session)
  1930. tests.create_projects_git(
  1931. os.path.join(self.path, 'repos'), bare=True)
  1932. tests.add_content_git_repo(
  1933. os.path.join(self.path, 'repos', 'test.git'))
  1934. user = tests.FakeUser()
  1935. user.username = 'pingou'
  1936. with tests.user_set(self.app.application, user):
  1937. csrf_token = self.get_csrf()
  1938. # Content in git
  1939. data = {
  1940. 'repo': 'test',
  1941. 'csrf_token': csrf_token,
  1942. }
  1943. output = self.app.post('/pv/stats/commits/trend', data=data)
  1944. self.assertEqual(output.status_code, 200)
  1945. js_data = json.loads(output.get_data(as_text=True))
  1946. self.assertEqual(
  1947. sorted(js_data.keys()),
  1948. ['code', 'message', 'task_id', 'url']
  1949. )
  1950. self.assertEqual(js_data['code'], 'OK')
  1951. self.assertEqual(js_data['message'], 'Stats asked')
  1952. self.assertTrue(js_data['url'].startswith('/pv/task/'))
  1953. output = self.app.get(js_data['url'])
  1954. js_data2 = json.loads(output.get_data(as_text=True))
  1955. today = datetime.datetime.utcnow().date()
  1956. self.assertDictEqual(
  1957. js_data2,
  1958. {'results': [[str(today), 2]]}
  1959. )
  1960. def test_get_project_family_no_project(self):
  1961. ''' Test the get_project_family from the internal API. '''
  1962. output = self.app.post('/pv/test/family')
  1963. self.assertEqual(output.status_code, 404)
  1964. def test_get_project_family_no_csrf(self):
  1965. ''' Test the get_project_family from the internal API. '''
  1966. tests.create_projects(self.session)
  1967. tests.create_projects_git(
  1968. os.path.join(self.path, 'repos'), bare=True)
  1969. tests.add_content_git_repo(
  1970. os.path.join(self.path, 'repos', 'test.git'))
  1971. output = self.app.post('/pv/test/family')
  1972. self.assertEqual(output.status_code, 400)
  1973. js_data = json.loads(output.get_data(as_text=True))
  1974. self.assertEqual(
  1975. sorted(js_data.keys()),
  1976. ['code', 'message']
  1977. )
  1978. self.assertEqual(js_data['code'], 'ERROR')
  1979. self.assertEqual(js_data['message'], 'Invalid input submitted')
  1980. def test_get_project_family(self):
  1981. ''' Test the get_project_family from the internal API. '''
  1982. tests.create_projects(self.session)
  1983. tests.create_projects_git(
  1984. os.path.join(self.path, 'repos'), bare=True)
  1985. tests.add_content_git_repo(
  1986. os.path.join(self.path, 'repos', 'test.git'))
  1987. user = tests.FakeUser()
  1988. user.username = 'pingou'
  1989. with tests.user_set(self.app.application, user):
  1990. csrf_token = self.get_csrf()
  1991. data = {
  1992. 'csrf_token': csrf_token,
  1993. }
  1994. output = self.app.post('/pv/test/family', data=data)
  1995. self.assertEqual(output.status_code, 200)
  1996. js_data = json.loads(output.get_data(as_text=True))
  1997. self.assertEqual(
  1998. sorted(js_data.keys()),
  1999. ['code', 'family']
  2000. )
  2001. self.assertEqual(js_data['code'], 'OK')
  2002. self.assertEqual(js_data['family'], ['test'])
  2003. def test_get_project_larger_family(self):
  2004. ''' Test the get_project_family from the internal API. '''
  2005. tests.create_projects(self.session)
  2006. tests.create_projects_git(
  2007. os.path.join(self.path, 'repos'), bare=True)
  2008. # Create a 3rd user
  2009. item = pagure.lib.model.User(
  2010. user='ralph',
  2011. fullname='Ralph bar',
  2012. password='ralph_foo',
  2013. default_email='ralph@bar.com',
  2014. )
  2015. self.session.add(item)
  2016. item = pagure.lib.model.UserEmail(
  2017. user_id=3,
  2018. email='ralph@bar.com')
  2019. self.session.add(item)
  2020. self.session.commit()
  2021. # Create a couple of forks of the test project
  2022. item = pagure.lib.model.Project(
  2023. user_id=2, # foo
  2024. name='test',
  2025. is_fork=True,
  2026. parent_id=1, # test
  2027. description='test project #1',
  2028. hook_token='aaabbbcccddd',
  2029. )
  2030. item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
  2031. self.session.add(item)
  2032. item = pagure.lib.model.Project(
  2033. user_id=3, # Ralph
  2034. name='test',
  2035. is_fork=True,
  2036. parent_id=1, # test
  2037. description='test project #1',
  2038. hook_token='aaabbbccceee',
  2039. )
  2040. item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
  2041. self.session.add(item)
  2042. self.session.commit()
  2043. # Get on with testing
  2044. user = tests.FakeUser()
  2045. user.username = 'pingou'
  2046. with tests.user_set(self.app.application, user):
  2047. csrf_token = self.get_csrf()
  2048. data = {
  2049. 'csrf_token': csrf_token,
  2050. }
  2051. output = self.app.post('/pv/test/family', data=data)
  2052. self.assertEqual(output.status_code, 200)
  2053. js_data = json.loads(output.get_data(as_text=True))
  2054. self.assertEqual(
  2055. sorted(js_data.keys()),
  2056. ['code', 'family']
  2057. )
  2058. self.assertEqual(js_data['code'], 'OK')
  2059. self.assertEqual(
  2060. js_data['family'],
  2061. ['test', 'fork/foo/test', 'fork/ralph/test'])
  2062. def test_get_project_larger_family_pr_only(self):
  2063. ''' Test the get_project_family from the internal API. '''
  2064. tests.create_projects(self.session)
  2065. tests.create_projects_git(
  2066. os.path.join(self.path, 'repos'), bare=True)
  2067. # Create a 3rd user
  2068. item = pagure.lib.model.User(
  2069. user='ralph',
  2070. fullname='Ralph bar',
  2071. password='ralph_foo',
  2072. default_email='ralph@bar.com',
  2073. )
  2074. self.session.add(item)
  2075. item = pagure.lib.model.UserEmail(
  2076. user_id=3,
  2077. email='ralph@bar.com')
  2078. self.session.add(item)
  2079. self.session.commit()
  2080. # Create a couple of forks of the test project
  2081. item = pagure.lib.model.Project(
  2082. user_id=2, # foo
  2083. name='test',
  2084. is_fork=True,
  2085. parent_id=1, # test
  2086. description='test project #1',
  2087. hook_token='aaabbbcccddd',
  2088. )
  2089. item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
  2090. # disable issues in this fork
  2091. default_repo_settings = item.settings
  2092. default_repo_settings['issue_tracker'] = False
  2093. item.settings = default_repo_settings
  2094. self.session.add(item)
  2095. item = pagure.lib.model.Project(
  2096. user_id=3, # Ralph
  2097. name='test',
  2098. is_fork=True,
  2099. parent_id=1, # test
  2100. description='test project #1',
  2101. hook_token='aaabbbccceee',
  2102. )
  2103. item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
  2104. # disable PRs in this fork
  2105. default_repo_settings = item.settings
  2106. default_repo_settings['pull_requests'] = False
  2107. item.settings = default_repo_settings
  2108. self.session.add(item)
  2109. self.session.commit()
  2110. # Get on with testing
  2111. user = tests.FakeUser()
  2112. user.username = 'pingou'
  2113. with tests.user_set(self.app.application, user):
  2114. csrf_token = self.get_csrf()
  2115. data = {
  2116. 'csrf_token': csrf_token,
  2117. 'allows_pr': '1',
  2118. }
  2119. output = self.app.post('/pv/test/family', data=data)
  2120. self.assertEqual(output.status_code, 200)
  2121. js_data = json.loads(output.get_data(as_text=True))
  2122. self.assertEqual(
  2123. sorted(js_data.keys()),
  2124. ['code', 'family']
  2125. )
  2126. self.assertEqual(js_data['code'], 'OK')
  2127. self.assertEqual(
  2128. js_data['family'],
  2129. ['test', 'fork/foo/test'])
  2130. data = {
  2131. 'csrf_token': csrf_token,
  2132. 'allows_issues': '1',
  2133. }
  2134. output = self.app.post('/pv/test/family', data=data)
  2135. self.assertEqual(output.status_code, 200)
  2136. js_data = json.loads(output.get_data(as_text=True))
  2137. self.assertEqual(
  2138. sorted(js_data.keys()),
  2139. ['code', 'family']
  2140. )
  2141. self.assertEqual(js_data['code'], 'OK')
  2142. self.assertEqual(
  2143. js_data['family'],
  2144. ['test', 'fork/ralph/test'])
  2145. def test_get_pull_request_ready_branch_no_csrf(self):
  2146. '''Test the get_pull_request_ready_branch from the internal API
  2147. on the main repository
  2148. '''
  2149. tests.create_projects(self.session)
  2150. tests.create_projects_git(
  2151. os.path.join(self.path, 'repos'), bare=True)
  2152. # Query branches on the main repo
  2153. data = {
  2154. 'repo': 'test',
  2155. }
  2156. output = self.app.post('/pv/pull-request/ready', data=data)
  2157. self.assertEqual(output.status_code, 400)
  2158. js_data = json.loads(output.get_data(as_text=True))
  2159. self.assertEqual(
  2160. sorted(js_data.keys()),
  2161. ['code', 'message']
  2162. )
  2163. self.assertEqual(js_data['code'], 'ERROR')
  2164. self.assertEqual(
  2165. js_data['message'],
  2166. 'Invalid input submitted'
  2167. )
  2168. def test_get_pull_request_ready_branch_no_repo(self):
  2169. '''Test the get_pull_request_ready_branch from the internal API
  2170. on the main repository
  2171. '''
  2172. with tests.user_set(self.app.application, tests.FakeUser()):
  2173. csrf_token = self.get_csrf()
  2174. # Query branches on an invalid repo
  2175. data = {
  2176. 'repo': 'test',
  2177. 'namespace': 'fake',
  2178. 'csrf_token': csrf_token,
  2179. }
  2180. output = self.app.post('/pv/pull-request/ready', data=data)
  2181. self.assertEqual(output.status_code, 404)
  2182. js_data = json.loads(output.get_data(as_text=True))
  2183. self.assertEqual(
  2184. sorted(js_data.keys()),
  2185. ['code', 'message']
  2186. )
  2187. self.assertEqual(js_data['code'], 'ERROR')
  2188. self.assertEqual(
  2189. js_data['message'],
  2190. 'No repo found with the information provided'
  2191. )
  2192. def test_get_pull_request_ready_branch_main_repo_no_branch(self):
  2193. '''Test the get_pull_request_ready_branch from the internal API
  2194. on the main repository
  2195. '''
  2196. tests.create_projects(self.session)
  2197. tests.create_projects_git(
  2198. os.path.join(self.path, 'repos'), bare=True)
  2199. # Get on with testing
  2200. user = tests.FakeUser()
  2201. user.username = 'pingou'
  2202. with tests.user_set(self.app.application, user):
  2203. csrf_token = self.get_csrf()
  2204. # Query branches on the main repo
  2205. data = {
  2206. 'csrf_token': csrf_token,
  2207. 'repo': 'test',
  2208. }
  2209. output = self.app.post('/pv/pull-request/ready', data=data)
  2210. self.assertEqual(output.status_code, 200)
  2211. js_data = json.loads(output.get_data(as_text=True))
  2212. self.assertEqual(
  2213. sorted(js_data.keys()),
  2214. ['code', 'task']
  2215. )
  2216. self.assertEqual(js_data['code'], 'OK')
  2217. def test_get_pull_request_ready_branch_on_fork(self):
  2218. '''Test the get_pull_request_ready_branch from the internal API on
  2219. a fork
  2220. '''
  2221. tests.create_projects(self.session)
  2222. tests.create_projects_git(
  2223. os.path.join(self.path, 'repos'), bare=True)
  2224. tests.create_projects_git(
  2225. os.path.join(self.path, 'repos', 'forks', 'foo'), bare=True)
  2226. tests.add_content_git_repo(
  2227. os.path.join(self.path, 'repos', 'forks', 'foo', 'test.git'),
  2228. branch='feature')
  2229. # Create foo's fork of the test project
  2230. item = pagure.lib.model.Project(
  2231. user_id=2, # foo
  2232. name='test',
  2233. is_fork=True,
  2234. parent_id=1, # test
  2235. description='test project #1',
  2236. hook_token='aaabbbcccddd',
  2237. )
  2238. item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
  2239. self.session.add(item)
  2240. self.session.commit()
  2241. # Get on with testing
  2242. user = tests.FakeUser()
  2243. user.username = 'pingou'
  2244. with tests.user_set(self.app.application, user):
  2245. csrf_token = self.get_csrf()
  2246. # Query branches on the Ralph's fork
  2247. data = {
  2248. 'csrf_token': csrf_token,
  2249. 'repo': 'test',
  2250. 'repouser': 'foo',
  2251. }
  2252. output = self.app.post('/pv/pull-request/ready', data=data)
  2253. self.assertEqual(output.status_code, 200)
  2254. js_data = json.loads(output.get_data(as_text=True))
  2255. self.assertEqual(
  2256. sorted(js_data.keys()),
  2257. ['code', 'task']
  2258. )
  2259. self.assertEqual(js_data['code'], 'OK')
  2260. output = self.app.get('/pv/task/' + js_data['task'])
  2261. self.assertEqual(output.status_code, 200)
  2262. js_data = json.loads(output.get_data(as_text=True))
  2263. self.assertEqual(
  2264. js_data,
  2265. {'results': {
  2266. 'branch_w_pr': {},
  2267. 'new_branch': {'feature':
  2268. {'commits': 2, 'target_branch': 'master'}}}}
  2269. )
  2270. def test_get_pull_request_ready_branch_on_fork_no_parent_no_pr(self):
  2271. '''Test the get_pull_request_ready_branch from the internal API on
  2272. a fork that has no parent repo (deleted) and doesn't allow PR
  2273. '''
  2274. tests.create_projects(self.session)
  2275. tests.create_projects_git(
  2276. os.path.join(self.path, 'repos'), bare=True)
  2277. tests.create_projects_git(
  2278. os.path.join(self.path, 'repos', 'forks', 'foo'), bare=True)
  2279. tests.add_content_git_repo(
  2280. os.path.join(self.path, 'repos', 'forks', 'foo', 'test.git'),
  2281. branch='feature')
  2282. # Create foo's fork of the test project
  2283. item = pagure.lib.model.Project(
  2284. user_id=2, # foo
  2285. name='test',
  2286. is_fork=True,
  2287. parent_id=1, # test
  2288. description='test project #1',
  2289. hook_token='aaabbbcccddd',
  2290. )
  2291. item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
  2292. self.session.add(item)
  2293. self.session.commit()
  2294. settings = item.settings
  2295. settings['pull_requests'] = False
  2296. item.settings = settings
  2297. self.session.add(item)
  2298. self.session.commit()
  2299. # Delete the parent project
  2300. project = pagure.lib.get_authorized_project(self.session, 'test')
  2301. self.session.delete(project)
  2302. self.session.commit()
  2303. # Get on with testing
  2304. user = tests.FakeUser()
  2305. user.username = 'pingou'
  2306. with tests.user_set(self.app.application, user):
  2307. csrf_token = self.get_csrf()
  2308. # Query branches on the Ralph's fork
  2309. data = {
  2310. 'csrf_token': csrf_token,
  2311. 'repo': 'test',
  2312. 'repouser': 'foo',
  2313. }
  2314. output = self.app.post('/pv/pull-request/ready', data=data)
  2315. self.assertEqual(output.status_code, 400)
  2316. js_data = json.loads(output.get_data(as_text=True))
  2317. self.assertEqual(
  2318. sorted(js_data.keys()),
  2319. ['code', 'message']
  2320. )
  2321. self.assertEqual(js_data['code'], 'ERROR')
  2322. self.assertEqual(
  2323. js_data['message'],
  2324. 'Pull-request have been disabled for this repo')
  2325. def test_get_pull_request_ready_branch_on_fork_no_parent(self):
  2326. '''Test the get_pull_request_ready_branch from the internal API on
  2327. a fork that has no parent repo (deleted).
  2328. '''
  2329. tests.create_projects(self.session)
  2330. tests.create_projects_git(
  2331. os.path.join(self.path, 'repos'), bare=True)
  2332. tests.create_projects_git(
  2333. os.path.join(self.path, 'repos', 'forks', 'foo'), bare=True)
  2334. tests.add_content_git_repo(
  2335. os.path.join(self.path, 'repos', 'forks', 'foo', 'test.git'),
  2336. branch='feature')
  2337. # Create foo's fork of the test project
  2338. item = pagure.lib.model.Project(
  2339. user_id=2, # foo
  2340. name='test',
  2341. is_fork=True,
  2342. parent_id=1, # test
  2343. description='test project #1',
  2344. hook_token='aaabbbcccddd',
  2345. )
  2346. item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
  2347. self.session.add(item)
  2348. self.session.commit()
  2349. settings = item.settings
  2350. settings['pull_requests'] = True
  2351. item.settings = settings
  2352. self.session.add(item)
  2353. self.session.commit()
  2354. # Delete the parent project
  2355. project = pagure.lib.get_authorized_project(self.session, 'test')
  2356. self.session.delete(project)
  2357. self.session.commit()
  2358. # Get on with testing
  2359. user = tests.FakeUser()
  2360. user.username = 'pingou'
  2361. with tests.user_set(self.app.application, user):
  2362. csrf_token = self.get_csrf()
  2363. # Query branches on the Ralph's fork
  2364. data = {
  2365. 'csrf_token': csrf_token,
  2366. 'repo': 'test',
  2367. 'repouser': 'foo',
  2368. }
  2369. output = self.app.post('/pv/pull-request/ready', data=data)
  2370. self.assertEqual(output.status_code, 200)
  2371. js_data = json.loads(output.get_data(as_text=True))
  2372. self.assertEqual(
  2373. sorted(js_data.keys()),
  2374. ['code', 'task']
  2375. )
  2376. self.assertEqual(js_data['code'], 'OK')
  2377. output = self.app.get('/pv/task/' + js_data['task'])
  2378. self.assertEqual(output.status_code, 200)
  2379. js_data = json.loads(output.get_data(as_text=True))
  2380. self.assertEqual(
  2381. js_data,
  2382. {'results': {
  2383. 'branch_w_pr': {},
  2384. 'new_branch': {'feature':
  2385. {'commits': 2, 'target_branch': 'master'}}}}
  2386. )
  2387. def test_get_pull_request_ready_branch_matching_target_off(self):
  2388. '''Test the get_pull_request_ready_branch from the internal API on
  2389. a fork while PR_TARGET_MATCHING_BRANCH is False
  2390. '''
  2391. tests.create_projects(self.session)
  2392. # make sure that head is not unborn
  2393. tests.add_content_git_repo(
  2394. os.path.join(self.path, 'repos', 'test.git'),
  2395. branch='master')
  2396. tests.add_content_git_repo(
  2397. os.path.join(self.path, 'repos', 'test.git'),
  2398. branch='feature')
  2399. tests.create_projects_git(
  2400. os.path.join(self.path, 'repos'), bare=True)
  2401. tests.create_projects_git(
  2402. os.path.join(self.path, 'repos', 'forks', 'foo'), bare=True)
  2403. tests.add_content_git_repo(
  2404. os.path.join(self.path, 'repos', 'forks', 'foo', 'test.git'),
  2405. branch='feature')
  2406. # Create foo's fork of the test project
  2407. item = pagure.lib.model.Project(
  2408. user_id=2, # foo
  2409. name='test',
  2410. is_fork=True,
  2411. parent_id=1, # test
  2412. description='test project #1',
  2413. hook_token='aaabbbcccddd',
  2414. )
  2415. item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
  2416. self.session.add(item)
  2417. self.session.commit()
  2418. # Get on with testing
  2419. user = tests.FakeUser()
  2420. user.username = 'pingou'
  2421. with tests.user_set(self.app.application, user):
  2422. csrf_token = self.get_csrf()
  2423. # Query branches on the Ralph's fork
  2424. data = {
  2425. 'csrf_token': csrf_token,
  2426. 'repo': 'test',
  2427. 'repouser': 'foo',
  2428. }
  2429. output = self.app.post('/pv/pull-request/ready', data=data)
  2430. self.assertEqual(output.status_code, 200)
  2431. js_data = json.loads(output.get_data(as_text=True))
  2432. self.assertEqual(
  2433. sorted(js_data.keys()),
  2434. ['code', 'task']
  2435. )
  2436. self.assertEqual(js_data['code'], 'OK')
  2437. output = self.app.get('/pv/task/' + js_data['task'])
  2438. self.assertEqual(output.status_code, 200)
  2439. js_data = json.loads(output.get_data(as_text=True))
  2440. self.assertEqual(
  2441. js_data,
  2442. {'results': {
  2443. 'branch_w_pr': {},
  2444. 'new_branch': {'feature':
  2445. {'commits': 2, 'target_branch': 'master'}}}}
  2446. )
  2447. @patch.dict('pagure.config.config', {'PR_TARGET_MATCHING_BRANCH': True})
  2448. def test_get_pull_request_ready_branch_matching_target_on(self):
  2449. '''Test the get_pull_request_ready_branch from the internal API on
  2450. a fork while PR_TARGET_MATCHING_BRANCH is True
  2451. '''
  2452. tests.create_projects(self.session)
  2453. # make sure that head is not unborn
  2454. tests.add_content_git_repo(
  2455. os.path.join(self.path, 'repos', 'test.git'),
  2456. branch='master')
  2457. tests.add_content_git_repo(
  2458. os.path.join(self.path, 'repos', 'test.git'),
  2459. branch='feature')
  2460. tests.create_projects_git(
  2461. os.path.join(self.path, 'repos'), bare=True)
  2462. tests.create_projects_git(
  2463. os.path.join(self.path, 'repos', 'forks', 'foo'), bare=True)
  2464. tests.add_content_git_repo(
  2465. os.path.join(self.path, 'repos', 'forks', 'foo', 'test.git'),
  2466. append="testing from foo's fork",
  2467. branch='feature')
  2468. # Create foo's fork of the test project
  2469. item = pagure.lib.model.Project(
  2470. user_id=2, # foo
  2471. name='test',
  2472. is_fork=True,
  2473. parent_id=1, # test
  2474. description='test project #1',
  2475. hook_token='aaabbbcccddd',
  2476. )
  2477. item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
  2478. self.session.add(item)
  2479. self.session.commit()
  2480. # Get on with testing
  2481. user = tests.FakeUser()
  2482. user.username = 'pingou'
  2483. with tests.user_set(self.app.application, user):
  2484. csrf_token = self.get_csrf()
  2485. # Query branches on the Ralph's fork
  2486. data = {
  2487. 'csrf_token': csrf_token,
  2488. 'repo': 'test',
  2489. 'repouser': 'foo',
  2490. }
  2491. output = self.app.post('/pv/pull-request/ready', data=data)
  2492. self.assertEqual(output.status_code, 200)
  2493. js_data = json.loads(output.get_data(as_text=True))
  2494. self.assertEqual(
  2495. sorted(js_data.keys()),
  2496. ['code', 'task']
  2497. )
  2498. self.assertEqual(js_data['code'], 'OK')
  2499. output = self.app.get('/pv/task/' + js_data['task'])
  2500. self.assertEqual(output.status_code, 200)
  2501. js_data = json.loads(output.get_data(as_text=True))
  2502. self.assertEqual(
  2503. js_data,
  2504. {'results': {
  2505. 'branch_w_pr': {},
  2506. 'new_branch': {'feature':
  2507. {'commits': 1, 'target_branch': 'feature'}}}}
  2508. )
  2509. def test_task_info_task_running(self):
  2510. """ Test the task_info internal API endpoint when the task isn't
  2511. ready.
  2512. """
  2513. task = MagicMock()
  2514. task.get = MagicMock(return_value='FAILED')
  2515. task.ready = MagicMock(return_value=False)
  2516. with patch('pagure.lib.tasks.get_result', MagicMock(return_value=task)):
  2517. output = self.app.get('/pv/task/2')
  2518. self.assertEqual(output.status_code, 418)
  2519. def test_task_info_task_passed(self):
  2520. """ Test the task_info internal API endpoint when the task failed.
  2521. """
  2522. task = MagicMock()
  2523. task.get = MagicMock(return_value='PASSED')
  2524. with patch('pagure.lib.tasks.get_result', MagicMock(return_value=task)):
  2525. output = self.app.get('/pv/task/2')
  2526. self.assertEqual(output.status_code, 200)
  2527. js_data = json.loads(output.get_data(as_text=True))
  2528. self.assertEqual(js_data, {u'results': u'PASSED'})
  2529. def test_task_info_task_failed(self):
  2530. """ Test the task_info internal API endpoint when the task failed.
  2531. """
  2532. task = MagicMock()
  2533. task.get = MagicMock(return_value=Exception('Random error'))
  2534. with patch('pagure.lib.tasks.get_result', MagicMock(return_value=task)):
  2535. output = self.app.get('/pv/task/2')
  2536. self.assertEqual(output.status_code, 200)
  2537. js_data = json.loads(output.get_data(as_text=True))
  2538. self.assertEqual(js_data, {u'results': u'Random error'})
  2539. def test_lookup_ssh_key(self):
  2540. """ Test the mergeable_request_pull endpoint when the backend
  2541. raises an GitError exception.
  2542. """
  2543. tests.create_projects(self.session)
  2544. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2545. project_key = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC4zmifEL8TLLZUZnjAuVL8495DAkpAAM2eBhwHwawBm'
  2546. project_key_fp = 'SHA256:ZSUQAqpPDWi90Fs6Ow8Epc8F3qiKVfU+H5ssvo7jiI0'
  2547. pingou = pagure.lib.get_user(self.session, 'pingou')
  2548. user_key = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDTsfdTcXw4rlU1aQwOTbLOXqossLwpPIk27S/G17kUz'
  2549. user_key_fp = 'SHA256:jUJHzrq2Ct6Ubf7Y9rnB6tGnbHM9dMVsveyfPojm+i0'
  2550. pagure.lib.add_sshkey_to_project_or_user(
  2551. self.session,
  2552. user_key,
  2553. pushaccess=True,
  2554. creator=pingou,
  2555. user=pingou,
  2556. )
  2557. pagure.lib.add_sshkey_to_project_or_user(
  2558. self.session,
  2559. project_key,
  2560. pushaccess=True,
  2561. creator=pingou,
  2562. project=repo,
  2563. )
  2564. self.session.commit()
  2565. url = '/pv/ssh/lookupkey/'
  2566. output = self.app.post(
  2567. url,
  2568. data={'search_key': 'asdf'},
  2569. )
  2570. self.assertEqual(output.status_code, 200)
  2571. result = json.loads(output.get_data(as_text=True))
  2572. self.assertEqual(result['found'], False)
  2573. output = self.app.post(
  2574. url,
  2575. data={'search_key': user_key_fp},
  2576. )
  2577. self.assertEqual(output.status_code, 200)
  2578. result = json.loads(output.get_data(as_text=True))
  2579. self.assertEqual(result['found'], True)
  2580. self.assertEqual(result['username'], 'pingou')
  2581. self.assertEqual(result['public_key'], user_key)
  2582. output = self.app.post(
  2583. url,
  2584. data={'search_key': user_key_fp,
  2585. 'username': 'pingou'},
  2586. )
  2587. self.assertEqual(output.status_code, 200)
  2588. result = json.loads(output.get_data(as_text=True))
  2589. self.assertEqual(result['found'], True)
  2590. self.assertEqual(result['username'], 'pingou')
  2591. self.assertEqual(result['public_key'], user_key)
  2592. output = self.app.post(
  2593. url,
  2594. data={'search_key': user_key_fp,
  2595. 'username': 'foo'},
  2596. )
  2597. self.assertEqual(output.status_code, 200)
  2598. result = json.loads(output.get_data(as_text=True))
  2599. self.assertEqual(result['found'], False)
  2600. output = self.app.post(
  2601. url,
  2602. data={'search_key': project_key_fp},
  2603. )
  2604. self.assertEqual(output.status_code, 200)
  2605. result = json.loads(output.get_data(as_text=True))
  2606. self.assertEqual(result['found'], True)
  2607. self.assertEqual(result['username'], 'deploykey_test_2')
  2608. self.assertEqual(result['public_key'], project_key)
  2609. def test_check_ssh_access(self):
  2610. """ Test the SSH access check endpoint. """
  2611. tests.create_projects(self.session)
  2612. url = '/pv/ssh/checkaccess/'
  2613. def runtest(project, username, access):
  2614. output = self.app.post(
  2615. url,
  2616. data={
  2617. 'gitdir': project,
  2618. 'username': username,
  2619. }
  2620. )
  2621. self.assertEqual(output.status_code, 200)
  2622. result = json.loads(output.get_data(as_text=True))
  2623. self.assertEqual(result['access'], access)
  2624. return result
  2625. runtest('project.git', 'pingou', False)
  2626. i1 = runtest('test.git', 'pingou', True)
  2627. i2 = runtest('test.git', 'foo', True)
  2628. i3 = runtest('tickets/test.git', 'pingou', True)
  2629. runtest('tickets/test.git', 'foo', False)
  2630. self.assertEqual(i1['reponame'], 'test.git')
  2631. self.assertEqual(i1['repotype'], 'main')
  2632. self.assertEqual(i1['region'], None)
  2633. self.assertEqual(i1['project_name'], 'test')
  2634. self.assertEqual(i1['project_user'], None)
  2635. self.assertEqual(i1['project_namespace'], None)
  2636. self.assertEqual(i1, i2)
  2637. self.assertEqual(i3['reponame'], 'tickets/test.git')
  2638. self.assertEqual(i3['repotype'], 'tickets')
  2639. self.assertEqual(i3['region'], None)
  2640. self.assertEqual(i3['project_name'], 'test')
  2641. self.assertEqual(i3['project_user'], None)
  2642. self.assertEqual(i3['project_namespace'], None)
  2643. if __name__ == '__main__':
  2644. unittest.main(verbosity=2)