test_pagure_flask_api_fork.py 132 KB

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