test_pagure_flask_internal.py 109 KB

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