test_pagure_flask_api_project.py 156 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015-2018 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. Karsten Hopp <karsten@redhat.com>
  7. """
  8. from __future__ import unicode_literals, absolute_import
  9. import datetime
  10. import json
  11. import unittest
  12. import shutil
  13. import sys
  14. import tempfile
  15. import os
  16. import pygit2
  17. from celery.result import EagerResult
  18. from mock import patch, Mock
  19. sys.path.insert(0, os.path.join(os.path.dirname(
  20. os.path.abspath(__file__)), '..'))
  21. import pagure.flask_app
  22. import pagure.lib.query
  23. import tests
  24. from pagure.lib.repo import PagureRepo
  25. class PagureFlaskApiProjecttests(tests.Modeltests):
  26. """ Tests for the flask API of pagure for issue """
  27. def setUp(self):
  28. super(PagureFlaskApiProjecttests, self).setUp()
  29. self.gga_patcher = patch(
  30. 'pagure.lib.tasks.generate_gitolite_acls.delay')
  31. self.mock_gen_acls = self.gga_patcher.start()
  32. task_result = EagerResult('abc-1234', True, "SUCCESS")
  33. self.mock_gen_acls.return_value = task_result
  34. def tearDown(self):
  35. self.gga_patcher.stop()
  36. super(PagureFlaskApiProjecttests, self).tearDown()
  37. def test_api_git_tags(self):
  38. """ Test the api_git_tags method of the flask api. """
  39. tests.create_projects(self.session)
  40. # Create a git repo to play with
  41. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  42. repo = pygit2.init_repository(gitrepo, bare=True)
  43. newpath = tempfile.mkdtemp(prefix='pagure-fork-test')
  44. repopath = os.path.join(newpath, 'test')
  45. clone_repo = pygit2.clone_repository(gitrepo, repopath)
  46. # Create a file in that git repo
  47. with open(os.path.join(repopath, 'sources'), 'w') as stream:
  48. stream.write('foo\n bar')
  49. clone_repo.index.add('sources')
  50. clone_repo.index.write()
  51. # Commits the files added
  52. tree = clone_repo.index.write_tree()
  53. author = pygit2.Signature(
  54. 'Alice Author', 'alice@authors.tld')
  55. committer = pygit2.Signature(
  56. 'Cecil Committer', 'cecil@committers.tld')
  57. clone_repo.create_commit(
  58. 'refs/heads/master', # the name of the reference to update
  59. author,
  60. committer,
  61. 'Add sources file for testing',
  62. # binary string representing the tree object ID
  63. tree,
  64. # list of binary strings representing parents of the new commit
  65. []
  66. )
  67. refname = 'refs/heads/master:refs/heads/master'
  68. ori_remote = clone_repo.remotes[0]
  69. PagureRepo.push(ori_remote, refname)
  70. # Tag our first commit
  71. first_commit = repo.revparse_single('HEAD')
  72. tagger = pygit2.Signature('Alice Doe', 'adoe@example.com', 12347, 0)
  73. repo.create_tag(
  74. "0.0.1", first_commit.oid.hex, pygit2.GIT_OBJ_COMMIT, tagger,
  75. "Release 0.0.1")
  76. # Check tags
  77. output = self.app.get('/api/0/test/git/tags')
  78. self.assertEqual(output.status_code, 200)
  79. data = json.loads(output.get_data(as_text=True))
  80. self.assertDictEqual(
  81. data,
  82. {'tags': ['0.0.1'], 'total_tags': 1}
  83. )
  84. # Check tags with commits
  85. output = self.app.get('/api/0/test/git/tags?with_commits=True')
  86. self.assertEqual(output.status_code, 200)
  87. data = json.loads(output.get_data(as_text=True))
  88. data['tags']['0.0.1'] = 'bb8fa2aa199da08d6085e1c9badc3d83d188d38c'
  89. self.assertDictEqual(
  90. data,
  91. {
  92. 'tags': {'0.0.1': 'bb8fa2aa199da08d6085e1c9badc3d83d188d38c'},
  93. 'total_tags': 1}
  94. )
  95. shutil.rmtree(newpath)
  96. def test_api_git_branches(self):
  97. """ Test the api_git_branches method of the flask api. """
  98. # Create a git repo to add branches to
  99. tests.create_projects(self.session)
  100. repo_path = os.path.join(self.path, 'repos', 'test.git')
  101. tests.add_content_git_repo(repo_path)
  102. new_repo_path = tempfile.mkdtemp(prefix='pagure-api-git-branches-test')
  103. clone_repo = pygit2.clone_repository(repo_path, new_repo_path)
  104. # Create two other branches based on master
  105. for branch in ['pats-win-49', 'pats-win-51']:
  106. clone_repo.create_branch(branch, clone_repo.head.peel())
  107. refname = 'refs/heads/{0}:refs/heads/{0}'.format(branch)
  108. PagureRepo.push(clone_repo.remotes[0], refname)
  109. # Check that the branches show up on the API
  110. output = self.app.get('/api/0/test/git/branches')
  111. # Delete the cloned git repo after the API call
  112. shutil.rmtree(new_repo_path)
  113. # Verify the API data
  114. self.assertEqual(output.status_code, 200)
  115. data = json.loads(output.get_data(as_text=True))
  116. self.assertDictEqual(
  117. data,
  118. {
  119. 'branches': ['master', 'pats-win-49', 'pats-win-51'],
  120. 'total_branches': 3
  121. }
  122. )
  123. def test_api_git_branches_empty_repo(self):
  124. """ Test the api_git_branches method of the flask api when the repo is
  125. empty.
  126. """
  127. # Create a git repo without any branches
  128. tests.create_projects(self.session)
  129. repo_base_path = os.path.join(self.path, 'repos')
  130. tests.create_projects_git(repo_base_path)
  131. # Check that no branches show up on the API
  132. output = self.app.get('/api/0/test/git/branches')
  133. self.assertEqual(output.status_code, 200)
  134. data = json.loads(output.get_data(as_text=True))
  135. self.assertDictEqual(
  136. data,
  137. {
  138. 'branches': [],
  139. 'total_branches': 0
  140. }
  141. )
  142. def test_api_git_branches_no_repo(self):
  143. """ Test the api_git_branches method of the flask api when there is no
  144. repo on a project.
  145. """
  146. tests.create_projects(self.session)
  147. output = self.app.get('/api/0/test/git/branches')
  148. self.assertEqual(output.status_code, 404)
  149. def test_api_git_urls(self):
  150. """ Test the api_project_git_urls method of the flask api.
  151. """
  152. tests.create_projects(self.session)
  153. output = self.app.get('/api/0/test/git/urls')
  154. self.assertEqual(output.status_code, 200)
  155. expected_rv = {
  156. 'urls': {
  157. 'git': 'git://localhost.localdomain/test.git',
  158. 'ssh': 'ssh://git@localhost.localdomain/test.git'
  159. },
  160. 'total_urls': 2
  161. }
  162. data = json.loads(output.get_data(as_text=True))
  163. self.assertDictEqual(data, expected_rv)
  164. def test_api_git_urls_no_project(self):
  165. """ Test the api_project_git_urls method of the flask api when there is
  166. no project.
  167. """
  168. output = self.app.get('/api/0/test1234/git/urls')
  169. self.assertEqual(output.status_code, 404)
  170. expected_rv = {
  171. 'error': 'Project not found',
  172. 'error_code': 'ENOPROJECT'
  173. }
  174. data = json.loads(output.get_data(as_text=True))
  175. self.assertDictEqual(data, expected_rv)
  176. @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
  177. def test_api_git_urls_private_project(self):
  178. """ Test the api_project_git_urls method of the flask api when the
  179. project is private.
  180. """
  181. tests.create_projects(self.session)
  182. tests.create_tokens(self.session)
  183. tests.create_tokens_acl(self.session, 'aaabbbcccddd')
  184. headers = {'Authorization': 'token aaabbbcccddd'}
  185. test_project = pagure.lib.query._get_project(self.session, 'test')
  186. test_project.private = True
  187. self.session.add(test_project)
  188. self.session.commit()
  189. output = self.app.get('/api/0/test/git/urls', headers=headers)
  190. self.assertEqual(output.status_code, 200)
  191. expected_rv = {
  192. 'urls': {
  193. 'git': 'git://localhost.localdomain/test.git',
  194. 'ssh': 'ssh://git@localhost.localdomain/test.git'
  195. },
  196. 'total_urls': 2
  197. }
  198. data = json.loads(output.get_data(as_text=True))
  199. self.assertDictEqual(data, expected_rv)
  200. @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
  201. def test_api_git_urls_private_project_no_login(self):
  202. """ Test the api_project_git_urls method of the flask api when the
  203. project is private and the user is not logged in.
  204. """
  205. tests.create_projects(self.session)
  206. test_project = pagure.lib.query._get_project(self.session, 'test')
  207. test_project.private = True
  208. self.session.add(test_project)
  209. self.session.commit()
  210. output = self.app.get('/api/0/test/git/urls')
  211. self.assertEqual(output.status_code, 404)
  212. expected_rv = {
  213. 'error': 'Project not found',
  214. 'error_code': 'ENOPROJECT'
  215. }
  216. data = json.loads(output.get_data(as_text=True))
  217. self.assertDictEqual(data, expected_rv)
  218. def test_api_projects_pattern(self):
  219. """ Test the api_projects method of the flask api. """
  220. tests.create_projects(self.session)
  221. output = self.app.get('/api/0/projects?pattern=test')
  222. self.assertEqual(output.status_code, 200)
  223. data = json.loads(output.get_data(as_text=True))
  224. data['projects'][0]['date_created'] = "1436527638"
  225. data['projects'][0]['date_modified'] = "1436527638"
  226. del data['pagination']
  227. expected_data = {
  228. "args": {
  229. "fork": None,
  230. "namespace": None,
  231. "owner": None,
  232. "page": 1,
  233. "pattern": "test",
  234. "per_page": 20,
  235. "short": False,
  236. "tags": [],
  237. "username": None
  238. },
  239. "projects": [
  240. {
  241. "access_groups": {
  242. "admin": [],
  243. "commit": [],
  244. "ticket": []
  245. },
  246. "access_users": {
  247. "admin": [],
  248. "commit": [],
  249. "owner": [
  250. "pingou"
  251. ],
  252. "ticket": []
  253. },
  254. "close_status": [
  255. "Invalid",
  256. "Insufficient data",
  257. "Fixed",
  258. "Duplicate"
  259. ],
  260. "custom_keys": [],
  261. "date_created": "1436527638",
  262. "date_modified": "1436527638",
  263. "description": "test project #1",
  264. "fullname": "test",
  265. "url_path": "test",
  266. "id": 1,
  267. "milestones": {},
  268. "name": "test",
  269. "namespace": None,
  270. "parent": None,
  271. "priorities": {},
  272. "tags": [],
  273. "user": {
  274. "fullname": "PY C",
  275. "name": "pingou"
  276. }
  277. }
  278. ],
  279. "total_projects": 1
  280. }
  281. self.assertDictEqual(data, expected_data)
  282. def test_api_projects_pattern_short(self):
  283. """ Test the api_projects method of the flask api. """
  284. tests.create_projects(self.session)
  285. output = self.app.get('/api/0/projects?pattern=te*&short=1')
  286. self.assertEqual(output.status_code, 200)
  287. data = json.loads(output.get_data(as_text=True))
  288. del data['pagination']
  289. expected_data = {
  290. "args": {
  291. "fork": None,
  292. "namespace": None,
  293. "owner": None,
  294. "page": 1,
  295. "pattern": "te*",
  296. "per_page": 20,
  297. "short": True,
  298. "tags": [],
  299. "username": None
  300. },
  301. "projects": [
  302. {
  303. "description": "test project #1",
  304. "fullname": "test",
  305. "name": "test",
  306. "namespace": None
  307. },
  308. {
  309. "description": "test project #2",
  310. "fullname": "test2",
  311. "name": "test2",
  312. "namespace": None
  313. },
  314. {
  315. "description": "namespaced test project",
  316. "fullname": "somenamespace/test3",
  317. "name": "test3",
  318. "namespace": "somenamespace"
  319. }
  320. ],
  321. "total_projects": 3
  322. }
  323. self.maxDiff = None
  324. self.assertDictEqual(data, expected_data)
  325. def test_api_projects(self):
  326. """ Test the api_projects method of the flask api. """
  327. tests.create_projects(self.session)
  328. # Check before adding
  329. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  330. self.assertEqual(repo.tags, [])
  331. # Adding a tag
  332. output = pagure.lib.query.update_tags(
  333. self.session, repo, 'infra', 'pingou')
  334. self.assertEqual(output, ['Project tagged with: infra'])
  335. # Check after adding
  336. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  337. self.assertEqual(len(repo.tags), 1)
  338. self.assertEqual(repo.tags_text, ['infra'])
  339. # Check the API
  340. output = self.app.get('/api/0/projects?tags=inf')
  341. self.assertEqual(output.status_code, 200)
  342. data = json.loads(output.get_data(as_text=True))
  343. null = None
  344. del data['pagination']
  345. self.assertDictEqual(
  346. data,
  347. {
  348. "total_projects": 0,
  349. "projects": [],
  350. "args": {
  351. "fork": None,
  352. "namespace": None,
  353. "owner": None,
  354. "page": 1,
  355. "pattern": None,
  356. "per_page": 20,
  357. "short": False,
  358. "tags": ["inf"],
  359. "username": None
  360. },
  361. }
  362. )
  363. output = self.app.get('/api/0/projects?tags=infra')
  364. self.assertEqual(output.status_code, 200)
  365. data = json.loads(output.get_data(as_text=True))
  366. data['projects'][0]['date_created'] = "1436527638"
  367. data['projects'][0]['date_modified'] = "1436527638"
  368. del data['pagination']
  369. expected_data = {
  370. "args": {
  371. "fork": None,
  372. "namespace": None,
  373. "owner": None,
  374. "page": 1,
  375. "pattern": None,
  376. "per_page": 20,
  377. "short": False,
  378. "tags": ["infra"],
  379. "username": None
  380. },
  381. "projects": [{
  382. "access_groups": {
  383. "admin": [],
  384. "commit": [],
  385. "ticket": []},
  386. "access_users": {
  387. "admin": [],
  388. "commit": [],
  389. "owner": ["pingou"],
  390. "ticket": []},
  391. "close_status": [
  392. "Invalid",
  393. "Insufficient data",
  394. "Fixed",
  395. "Duplicate"
  396. ],
  397. "custom_keys": [],
  398. "date_created": "1436527638",
  399. "date_modified": "1436527638",
  400. "description": "test project #1",
  401. "fullname": "test",
  402. "url_path": "test",
  403. "id": 1,
  404. "milestones": {},
  405. "name": "test",
  406. "namespace": None,
  407. "parent": None,
  408. "priorities": {},
  409. "tags": ["infra"],
  410. "user": {
  411. "fullname": "PY C",
  412. "name": "pingou"
  413. }
  414. }],
  415. "total_projects": 1
  416. }
  417. self.assertDictEqual(data, expected_data)
  418. output = self.app.get('/api/0/projects?owner=pingou')
  419. self.assertEqual(output.status_code, 200)
  420. data = json.loads(output.get_data(as_text=True))
  421. data['projects'][0]['date_created'] = "1436527638"
  422. data['projects'][0]['date_modified'] = "1436527638"
  423. data['projects'][1]['date_created'] = "1436527638"
  424. data['projects'][1]['date_modified'] = "1436527638"
  425. data['projects'][2]['date_created'] = "1436527638"
  426. data['projects'][2]['date_modified'] = "1436527638"
  427. del data['pagination']
  428. expected_data = {
  429. "args": {
  430. "fork": None,
  431. "namespace": None,
  432. "owner": "pingou",
  433. "page": 1,
  434. "pattern": None,
  435. "per_page": 20,
  436. "short": False,
  437. "tags": [],
  438. "username": None
  439. },
  440. "projects": [
  441. {
  442. "access_groups": {
  443. "admin": [],
  444. "commit": [],
  445. "ticket": []
  446. },
  447. "access_users": {
  448. "admin": [],
  449. "commit": [],
  450. "owner": ["pingou"],
  451. "ticket": []
  452. },
  453. "close_status": [
  454. "Invalid",
  455. "Insufficient data",
  456. "Fixed",
  457. "Duplicate"
  458. ],
  459. "custom_keys": [],
  460. "date_created": "1436527638",
  461. "date_modified": "1436527638",
  462. "description": "test project #1",
  463. "fullname": "test",
  464. "url_path": "test",
  465. "id": 1,
  466. "milestones": {},
  467. "name": "test",
  468. "namespace": None,
  469. "parent": None,
  470. "priorities": {},
  471. "tags": ["infra"],
  472. "user": {
  473. "fullname": "PY C",
  474. "name": "pingou"
  475. }
  476. },
  477. {
  478. "access_groups": {
  479. "admin": [],
  480. "commit": [],
  481. "ticket": []
  482. },
  483. "access_users": {
  484. "admin": [],
  485. "commit": [],
  486. "owner": ["pingou"],
  487. "ticket": []
  488. },
  489. "close_status": [
  490. "Invalid",
  491. "Insufficient data",
  492. "Fixed",
  493. "Duplicate"
  494. ],
  495. "custom_keys": [],
  496. "date_created": "1436527638",
  497. "date_modified": "1436527638",
  498. "description": "test project #2",
  499. "fullname": "test2",
  500. "url_path": "test2",
  501. "id": 2,
  502. "milestones": {},
  503. "name": "test2",
  504. "namespace": None,
  505. "parent": None,
  506. "priorities": {},
  507. "tags": [],
  508. "user": {
  509. "fullname": "PY C",
  510. "name": "pingou"
  511. }
  512. },
  513. {
  514. "access_groups": {
  515. "admin": [],
  516. "commit": [],
  517. "ticket": []
  518. },
  519. "access_users": {
  520. "admin": [],
  521. "commit": [],
  522. "owner": ["pingou"],
  523. "ticket": []
  524. },
  525. "close_status": [
  526. "Invalid",
  527. "Insufficient data",
  528. "Fixed",
  529. "Duplicate"
  530. ],
  531. "custom_keys": [],
  532. "date_created": "1436527638",
  533. "date_modified": "1436527638",
  534. "description": "namespaced test project",
  535. "fullname": "somenamespace/test3",
  536. "url_path": "somenamespace/test3",
  537. "id": 3,
  538. "milestones": {},
  539. "name": "test3",
  540. "namespace": "somenamespace",
  541. "parent": None,
  542. "priorities": {},
  543. "tags": [],
  544. "user": {
  545. "fullname": "PY C",
  546. "name": "pingou"
  547. }
  548. }
  549. ],
  550. "total_projects": 3
  551. }
  552. self.assertDictEqual(data, expected_data)
  553. output = self.app.get('/api/0/projects?username=pingou')
  554. self.assertEqual(output.status_code, 200)
  555. data = json.loads(output.get_data(as_text=True))
  556. data['projects'][0]['date_created'] = "1436527638"
  557. data['projects'][0]['date_modified'] = "1436527638"
  558. data['projects'][1]['date_created'] = "1436527638"
  559. data['projects'][1]['date_modified'] = "1436527638"
  560. data['projects'][2]['date_created'] = "1436527638"
  561. data['projects'][2]['date_modified'] = "1436527638"
  562. del data['pagination']
  563. expected_data = {
  564. "args": {
  565. "fork": None,
  566. "namespace": None,
  567. "owner": None,
  568. "page": 1,
  569. "pattern": None,
  570. "per_page": 20,
  571. "short": False,
  572. "tags": [],
  573. "username": "pingou"
  574. },
  575. "projects": [
  576. {
  577. "access_groups": {
  578. "admin": [],
  579. "commit": [],
  580. "ticket": []},
  581. "access_users": {
  582. "admin": [],
  583. "commit": [],
  584. "owner": ["pingou"],
  585. "ticket": []
  586. },
  587. "close_status": [
  588. "Invalid",
  589. "Insufficient data",
  590. "Fixed",
  591. "Duplicate"
  592. ],
  593. "custom_keys": [],
  594. "date_created": "1436527638",
  595. "date_modified": "1436527638",
  596. "description": "test project #1",
  597. "fullname": "test",
  598. "url_path": "test",
  599. "id": 1,
  600. "milestones": {},
  601. "name": "test",
  602. "namespace": None,
  603. "parent": None,
  604. "priorities": {},
  605. "tags": ["infra"],
  606. "user": {
  607. "fullname": "PY C",
  608. "name": "pingou"
  609. }
  610. },
  611. {
  612. "access_groups": {
  613. "admin": [],
  614. "commit": [],
  615. "ticket": []
  616. },
  617. "access_users": {
  618. "admin": [],
  619. "commit": [],
  620. "owner": ["pingou"],
  621. "ticket": []
  622. },
  623. "close_status": [
  624. "Invalid",
  625. "Insufficient data",
  626. "Fixed",
  627. "Duplicate"
  628. ],
  629. "custom_keys": [],
  630. "date_created": "1436527638",
  631. "date_modified": "1436527638",
  632. "description": "test project #2",
  633. "fullname": "test2",
  634. "url_path": "test2",
  635. "id": 2,
  636. "milestones": {},
  637. "name": "test2",
  638. "namespace": None,
  639. "parent": None,
  640. "priorities": {},
  641. "tags": [],
  642. "user": {
  643. "fullname": "PY C",
  644. "name": "pingou"
  645. }
  646. },
  647. {
  648. "access_groups": {
  649. "admin": [],
  650. "commit": [],
  651. "ticket": []},
  652. "access_users": {
  653. "admin": [],
  654. "commit": [],
  655. "owner": ["pingou"],
  656. "ticket": []},
  657. "close_status": [
  658. "Invalid",
  659. "Insufficient data",
  660. "Fixed",
  661. "Duplicate"
  662. ],
  663. "custom_keys": [],
  664. "date_created": "1436527638",
  665. "date_modified": "1436527638",
  666. "description": "namespaced test project",
  667. "fullname": "somenamespace/test3",
  668. "url_path": "somenamespace/test3",
  669. "id": 3,
  670. "milestones": {},
  671. "name": "test3",
  672. "namespace": "somenamespace",
  673. "parent": None,
  674. "priorities": {},
  675. "tags": [],
  676. "user": {
  677. "fullname": "PY C",
  678. "name": "pingou"
  679. }
  680. }
  681. ],
  682. "total_projects": 3
  683. }
  684. self.assertDictEqual(data, expected_data)
  685. output = self.app.get('/api/0/projects?username=pingou&tags=infra')
  686. self.assertEqual(output.status_code, 200)
  687. data = json.loads(output.get_data(as_text=True))
  688. data['projects'][0]['date_created'] = "1436527638"
  689. data['projects'][0]['date_modified'] = "1436527638"
  690. del data['pagination']
  691. expected_data = {
  692. "args": {
  693. "fork": None,
  694. "namespace": None,
  695. "owner": None,
  696. "page": 1,
  697. "pattern": None,
  698. "per_page": 20,
  699. "short": False,
  700. "tags": ["infra"],
  701. "username": "pingou",
  702. },
  703. "projects": [{
  704. "access_groups": {
  705. "admin": [],
  706. "commit": [],
  707. "ticket": []
  708. },
  709. "access_users": {
  710. "admin": [],
  711. "commit": [],
  712. "owner": ["pingou"],
  713. "ticket": []},
  714. "close_status": [
  715. "Invalid",
  716. "Insufficient data",
  717. "Fixed",
  718. "Duplicate"],
  719. "custom_keys": [],
  720. "date_created": "1436527638",
  721. "date_modified": "1436527638",
  722. "description": "test project #1",
  723. "fullname": "test",
  724. "url_path": "test",
  725. "id": 1,
  726. "milestones": {},
  727. "name": "test",
  728. "namespace": None,
  729. "parent": None,
  730. "priorities": {},
  731. "tags": ["infra"],
  732. "user": {
  733. "fullname": "PY C",
  734. "name": "pingou"
  735. }
  736. }],
  737. "total_projects": 1
  738. }
  739. self.assertDictEqual(data, expected_data)
  740. output = self.app.get('/api/0/projects?namespace=somenamespace')
  741. self.assertEqual(output.status_code, 200)
  742. data = json.loads(output.get_data(as_text=True))
  743. data['projects'][0]['date_created'] = "1436527638"
  744. data['projects'][0]['date_modified'] = "1436527638"
  745. del data['pagination']
  746. expected_data = {
  747. "args": {
  748. "fork": None,
  749. "owner": None,
  750. "page": 1,
  751. "namespace": "somenamespace",
  752. "per_page": 20,
  753. "pattern": None,
  754. "short": False,
  755. "tags": [],
  756. "username": None
  757. },
  758. "projects": [
  759. {
  760. "access_groups": {
  761. "admin": [],
  762. "commit": [],
  763. "ticket": []},
  764. "access_users": {
  765. "admin": [],
  766. "commit": [],
  767. "owner": ["pingou"],
  768. "ticket": []},
  769. "close_status": [
  770. "Invalid",
  771. "Insufficient data",
  772. "Fixed",
  773. "Duplicate"
  774. ],
  775. "custom_keys": [],
  776. "date_created": "1436527638",
  777. "date_modified": "1436527638",
  778. "description": "namespaced test project",
  779. "fullname": "somenamespace/test3",
  780. "url_path": "somenamespace/test3",
  781. "id": 3,
  782. "milestones": {},
  783. "name": "test3",
  784. "namespace": "somenamespace",
  785. "parent": None,
  786. "priorities": {},
  787. "tags": [],
  788. "user": {
  789. "fullname": "PY C",
  790. "name": "pingou"
  791. }
  792. }
  793. ],
  794. "total_projects": 1
  795. }
  796. self.assertDictEqual(data, expected_data)
  797. def test_api_project(self):
  798. """ Test the api_project method of the flask api. """
  799. tests.create_projects(self.session)
  800. # Check before adding
  801. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  802. self.assertEqual(repo.tags, [])
  803. # Adding a tag
  804. output = pagure.lib.query.update_tags(
  805. self.session, repo, 'infra', 'pingou')
  806. self.assertEqual(output, ['Project tagged with: infra'])
  807. # Check after adding
  808. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  809. self.assertEqual(len(repo.tags), 1)
  810. self.assertEqual(repo.tags_text, ['infra'])
  811. # Check the API
  812. # Non-existing project
  813. output = self.app.get('/api/0/random')
  814. self.assertEqual(output.status_code, 404)
  815. data = json.loads(output.get_data(as_text=True))
  816. self.assertDictEqual(
  817. data,
  818. {'error_code': 'ENOPROJECT', 'error': 'Project not found'}
  819. )
  820. # Existing project
  821. output = self.app.get('/api/0/test')
  822. self.assertEqual(output.status_code, 200)
  823. data = json.loads(output.get_data(as_text=True))
  824. data['date_created'] = "1436527638"
  825. data['date_modified'] = "1436527638"
  826. expected_data ={
  827. "access_groups": {
  828. "admin": [],
  829. "commit": [],
  830. "ticket": []
  831. },
  832. "access_users": {
  833. "admin": [],
  834. "commit": [],
  835. "owner": ["pingou"],
  836. "ticket": []},
  837. "close_status": [
  838. "Invalid",
  839. "Insufficient data",
  840. "Fixed",
  841. "Duplicate"
  842. ],
  843. "custom_keys": [],
  844. "date_created": "1436527638",
  845. "date_modified": "1436527638",
  846. "description": "test project #1",
  847. "fullname": "test",
  848. "url_path": "test",
  849. "id": 1,
  850. "milestones": {},
  851. "name": "test",
  852. "namespace": None,
  853. "parent": None,
  854. "priorities": {},
  855. "tags": ["infra"],
  856. "user": {
  857. "fullname": "PY C",
  858. "name": "pingou"
  859. }
  860. }
  861. self.assertDictEqual(data, expected_data)
  862. def test_api_project_group(self):
  863. """ Test the api_project method of the flask api. """
  864. tests.create_projects(self.session)
  865. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  866. # Adding a tag
  867. output = pagure.lib.query.update_tags(
  868. self.session, repo, 'infra', 'pingou')
  869. self.assertEqual(output, ['Project tagged with: infra'])
  870. # Check after adding
  871. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  872. self.assertEqual(len(repo.tags), 1)
  873. self.assertEqual(repo.tags_text, ['infra'])
  874. # Add a group to the project
  875. msg = pagure.lib.query.add_group(
  876. self.session,
  877. group_name='some_group',
  878. display_name='Some Group',
  879. description=None,
  880. group_type='bar',
  881. user='foo',
  882. is_admin=False,
  883. blacklist=[],
  884. )
  885. self.session.commit()
  886. project = pagure.lib.query.get_authorized_project(self.session, 'test')
  887. group = pagure.lib.query.search_groups(
  888. self.session, group_name='some_group')
  889. pagure.lib.query.add_group_to_project(
  890. self.session,
  891. project,
  892. new_group='some_group',
  893. user='pingou',
  894. access='commit',
  895. create=False,
  896. is_admin=True
  897. )
  898. self.session.commit()
  899. # Check the API
  900. # Existing project
  901. output = self.app.get('/api/0/test?expand_group=1')
  902. self.assertEqual(output.status_code, 200)
  903. data = json.loads(output.get_data(as_text=True))
  904. data['date_created'] = "1436527638"
  905. data['date_modified'] = "1436527638"
  906. expected_data ={
  907. "access_groups": {
  908. "admin": [],
  909. "commit": ["some_group"],
  910. "ticket": []
  911. },
  912. "access_users": {
  913. "admin": [],
  914. "commit": [],
  915. "owner": ["pingou"],
  916. "ticket": []},
  917. "close_status": [
  918. "Invalid",
  919. "Insufficient data",
  920. "Fixed",
  921. "Duplicate"
  922. ],
  923. "custom_keys": [],
  924. "date_created": "1436527638",
  925. "date_modified": "1436527638",
  926. "description": "test project #1",
  927. "fullname": "test",
  928. "url_path": "test",
  929. "group_details": {
  930. "some_group": [
  931. "foo"
  932. ]
  933. },
  934. "id": 1,
  935. "milestones": {},
  936. "name": "test",
  937. "namespace": None,
  938. "parent": None,
  939. "priorities": {},
  940. "tags": ["infra"],
  941. "user": {
  942. "fullname": "PY C",
  943. "name": "pingou"
  944. }
  945. }
  946. self.assertDictEqual(data, expected_data)
  947. def test_api_project_group_but_no_group(self):
  948. """ Test the api_project method of the flask api when asking for
  949. group details while there are none associated.
  950. """
  951. tests.create_projects(self.session)
  952. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  953. # Adding a tag
  954. output = pagure.lib.query.update_tags(
  955. self.session, repo, 'infra', 'pingou')
  956. self.assertEqual(output, ['Project tagged with: infra'])
  957. # Check after adding
  958. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  959. self.assertEqual(len(repo.tags), 1)
  960. self.assertEqual(repo.tags_text, ['infra'])
  961. # Check the API
  962. # Existing project
  963. output = self.app.get('/api/0/test?expand_group=0')
  964. self.assertEqual(output.status_code, 200)
  965. data = json.loads(output.get_data(as_text=True))
  966. data['date_created'] = "1436527638"
  967. data['date_modified'] = "1436527638"
  968. expected_data ={
  969. "access_groups": {
  970. "admin": [],
  971. "commit": [],
  972. "ticket": []
  973. },
  974. "access_users": {
  975. "admin": [],
  976. "commit": [],
  977. "owner": ["pingou"],
  978. "ticket": []},
  979. "close_status": [
  980. "Invalid",
  981. "Insufficient data",
  982. "Fixed",
  983. "Duplicate"
  984. ],
  985. "custom_keys": [],
  986. "date_created": "1436527638",
  987. "date_modified": "1436527638",
  988. "description": "test project #1",
  989. "fullname": "test",
  990. "url_path": "test",
  991. "id": 1,
  992. "milestones": {},
  993. "name": "test",
  994. "namespace": None,
  995. "parent": None,
  996. "priorities": {},
  997. "tags": ["infra"],
  998. "user": {
  999. "fullname": "PY C",
  1000. "name": "pingou"
  1001. }
  1002. }
  1003. self.assertDictEqual(data, expected_data)
  1004. def test_api_projects_pagination(self):
  1005. """ Test the api_projects method of the flask api with pagination. """
  1006. tests.create_projects(self.session)
  1007. output = self.app.get('/api/0/projects?page=1')
  1008. self.assertEqual(output.status_code, 200)
  1009. data = json.loads(output.get_data(as_text=True))
  1010. for i in range(3):
  1011. data['projects'][i]['date_created'] = "1436527638"
  1012. data['projects'][i]['date_modified'] = "1436527638"
  1013. expected_data = {
  1014. "args": {
  1015. "fork": None,
  1016. "namespace": None,
  1017. "owner": None,
  1018. "page": 1,
  1019. "per_page": 20,
  1020. "pattern": None,
  1021. "short": False,
  1022. "tags": [],
  1023. "username": None
  1024. },
  1025. "pagination": {
  1026. "next": None,
  1027. "page": 1,
  1028. "pages": 1,
  1029. "per_page": 20,
  1030. "prev": None
  1031. },
  1032. "projects": [
  1033. {
  1034. "access_groups": {
  1035. "admin": [],
  1036. "commit": [],
  1037. "ticket": []},
  1038. "access_users": {
  1039. "admin": [],
  1040. "commit": [],
  1041. "owner": ["pingou"],
  1042. "ticket": []
  1043. },
  1044. "close_status": [
  1045. "Invalid",
  1046. "Insufficient data",
  1047. "Fixed",
  1048. "Duplicate"
  1049. ],
  1050. "custom_keys": [],
  1051. "date_created": "1436527638",
  1052. "date_modified": "1436527638",
  1053. "description": "test project #1",
  1054. "fullname": "test",
  1055. "url_path": "test",
  1056. "id": 1,
  1057. "milestones": {},
  1058. "name": "test",
  1059. "namespace": None,
  1060. "parent": None,
  1061. "priorities": {},
  1062. "tags": [],
  1063. "user": {
  1064. "fullname": "PY C",
  1065. "name": "pingou"
  1066. }
  1067. },
  1068. {
  1069. "access_groups": {
  1070. "admin": [],
  1071. "commit": [],
  1072. "ticket": []
  1073. },
  1074. "access_users": {
  1075. "admin": [],
  1076. "commit": [],
  1077. "owner": ["pingou"],
  1078. "ticket": []
  1079. },
  1080. "close_status": [
  1081. "Invalid",
  1082. "Insufficient data",
  1083. "Fixed",
  1084. "Duplicate"
  1085. ],
  1086. "custom_keys": [],
  1087. "date_created": "1436527638",
  1088. "date_modified": "1436527638",
  1089. "description": "test project #2",
  1090. "fullname": "test2",
  1091. "url_path": "test2",
  1092. "id": 2,
  1093. "milestones": {},
  1094. "name": "test2",
  1095. "namespace": None,
  1096. "parent": None,
  1097. "priorities": {},
  1098. "tags": [],
  1099. "user": {
  1100. "fullname": "PY C",
  1101. "name": "pingou"
  1102. }
  1103. },
  1104. {
  1105. "access_groups": {
  1106. "admin": [],
  1107. "commit": [],
  1108. "ticket": []},
  1109. "access_users": {
  1110. "admin": [],
  1111. "commit": [],
  1112. "owner": ["pingou"],
  1113. "ticket": []},
  1114. "close_status": [
  1115. "Invalid",
  1116. "Insufficient data",
  1117. "Fixed",
  1118. "Duplicate"
  1119. ],
  1120. "custom_keys": [],
  1121. "date_created": "1436527638",
  1122. "date_modified": "1436527638",
  1123. "description": "namespaced test project",
  1124. "fullname": "somenamespace/test3",
  1125. "url_path": "somenamespace/test3",
  1126. "id": 3,
  1127. "milestones": {},
  1128. "name": "test3",
  1129. "namespace": "somenamespace",
  1130. "parent": None,
  1131. "priorities": {},
  1132. "tags": [],
  1133. "user": {
  1134. "fullname": "PY C",
  1135. "name": "pingou"
  1136. }
  1137. }
  1138. ],
  1139. "total_projects": 3
  1140. }
  1141. # Test URLs
  1142. self.assertURLEqual(
  1143. data["pagination"].pop("first"),
  1144. "http://localhost/api/0/projects?per_page=20&page=1",
  1145. )
  1146. self.assertURLEqual(
  1147. data["pagination"].pop("last"),
  1148. "http://localhost/api/0/projects?per_page=20&page=1",
  1149. )
  1150. self.assertDictEqual(data, expected_data)
  1151. def test_api_projects_pagination_per_page(self):
  1152. """ Test the api_projects method of the flask api with pagination and
  1153. the `per_page` argument set. """
  1154. tests.create_projects(self.session)
  1155. output = self.app.get('/api/0/projects?page=2&per_page=2')
  1156. self.assertEqual(output.status_code, 200)
  1157. data = json.loads(output.get_data(as_text=True))
  1158. data['projects'][0]['date_created'] = "1436527638"
  1159. data['projects'][0]['date_modified'] = "1436527638"
  1160. expected_data = {
  1161. "args": {
  1162. "fork": None,
  1163. "namespace": None,
  1164. "owner": None,
  1165. "page": 2,
  1166. "per_page": 2,
  1167. "pattern": None,
  1168. "short": False,
  1169. "tags": [],
  1170. "username": None
  1171. },
  1172. "pagination": {
  1173. "next": None,
  1174. "page": 2,
  1175. "pages": 2,
  1176. "per_page": 2,
  1177. },
  1178. "projects": [
  1179. {
  1180. "access_groups": {
  1181. "admin": [],
  1182. "commit": [],
  1183. "ticket": []
  1184. },
  1185. "access_users": {
  1186. "admin": [],
  1187. "commit": [],
  1188. "owner": ["pingou"],
  1189. "ticket": []
  1190. },
  1191. "close_status": [
  1192. "Invalid",
  1193. "Insufficient data",
  1194. "Fixed",
  1195. "Duplicate"
  1196. ],
  1197. "custom_keys": [],
  1198. "date_created": "1436527638",
  1199. "date_modified": "1436527638",
  1200. "description": "namespaced test project",
  1201. "fullname": "somenamespace/test3",
  1202. "url_path": "somenamespace/test3",
  1203. "id": 3,
  1204. "milestones": {},
  1205. "name": "test3",
  1206. "namespace": "somenamespace",
  1207. "parent": None,
  1208. "priorities": {},
  1209. "tags": [],
  1210. "user": {
  1211. "fullname": "PY C",
  1212. "name": "pingou"
  1213. }
  1214. }
  1215. ],
  1216. "total_projects": 3
  1217. }
  1218. self.assertURLEqual(
  1219. data["pagination"].pop("first"),
  1220. "http://localhost/api/0/projects?per_page=2&page=1",
  1221. )
  1222. self.assertURLEqual(
  1223. data["pagination"].pop("prev"),
  1224. "http://localhost/api/0/projects?per_page=2&page=1",
  1225. )
  1226. self.assertURLEqual(
  1227. data["pagination"].pop("last"),
  1228. "http://localhost/api/0/projects?per_page=2&page=2",
  1229. )
  1230. self.assertDictEqual(data, expected_data)
  1231. def test_api_projects_pagination_invalid_page(self):
  1232. """ Test the api_projects method of the flask api when an invalid page
  1233. value is entered. """
  1234. tests.create_projects(self.session)
  1235. output = self.app.get('/api/0/projects?page=-3')
  1236. self.assertEqual(output.status_code, 400)
  1237. def test_api_projects_pagination_invalid_page_str(self):
  1238. """ Test the api_projects method of the flask api when an invalid type
  1239. for the page value is entered. """
  1240. tests.create_projects(self.session)
  1241. output = self.app.get('/api/0/projects?page=abcd')
  1242. self.assertEqual(output.status_code, 400)
  1243. def test_api_projects_pagination_invalid_per_page_too_low(self):
  1244. """ Test the api_projects method of the flask api when a per_page
  1245. value is below 1. """
  1246. tests.create_projects(self.session)
  1247. output = self.app.get('/api/0/projects?page=1&per_page=0')
  1248. self.assertEqual(output.status_code, 400)
  1249. error = json.loads(output.get_data(as_text=True))
  1250. self.assertEqual(
  1251. error['error'], 'The per_page value must be between 1 and 100')
  1252. def test_api_projects_pagination_invalid_per_page_too_high(self):
  1253. """ Test the api_projects method of the flask api when a per_page
  1254. value is above 100. """
  1255. tests.create_projects(self.session)
  1256. output = self.app.get('/api/0/projects?page=1&per_page=101')
  1257. self.assertEqual(output.status_code, 400)
  1258. error = json.loads(output.get_data(as_text=True))
  1259. self.assertEqual(
  1260. error['error'], 'The per_page value must be between 1 and 100')
  1261. def test_api_projects_pagination_invalid_per_page_str(self):
  1262. """ Test the api_projects method of the flask api when an invalid type
  1263. for the per_page value is entered. """
  1264. tests.create_projects(self.session)
  1265. output = self.app.get('/api/0/projects?page=1&per_page=abcd')
  1266. self.assertEqual(output.status_code, 400)
  1267. def test_api_projects_pagination_beyond_last_page(self):
  1268. """ Test the api_projects method of the flask api when a page value
  1269. that is larger than the last page is entered. """
  1270. tests.create_projects(self.session)
  1271. output = self.app.get('/api/0/projects?page=99999')
  1272. self.assertEqual(output.status_code, 200)
  1273. data = json.loads(output.get_data(as_text=True))
  1274. self.assertURLEqual(
  1275. data["pagination"].pop("first"),
  1276. "http://localhost/api/0/projects?per_page=20&page=1",
  1277. )
  1278. self.assertURLEqual(
  1279. data["pagination"].pop("last"),
  1280. "http://localhost/api/0/projects?per_page=20&page=1",
  1281. )
  1282. self.assertURLEqual(
  1283. data["pagination"].pop("prev"),
  1284. "http://localhost/api/0/projects?per_page=20&page=99998",
  1285. )
  1286. self.assertEqual(
  1287. data,
  1288. {
  1289. "args": {
  1290. "fork": None,
  1291. "namespace": None,
  1292. "owner": None,
  1293. "page": 99999,
  1294. "pattern": None,
  1295. "per_page": 20,
  1296. "short": False,
  1297. "tags": [],
  1298. "username": None
  1299. },
  1300. "pagination": {
  1301. "next": None,
  1302. "page": 99999,
  1303. "pages": 1,
  1304. "per_page": 20,
  1305. },
  1306. "projects": [],
  1307. "total_projects": 3
  1308. }
  1309. )
  1310. def test_api_modify_project_main_admin(self):
  1311. """ Test the api_modify_project method of the flask api when the
  1312. request is to change the main_admin of the project. """
  1313. tests.create_projects(self.session)
  1314. tests.create_tokens(self.session, project_id=None)
  1315. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1316. headers = {'Authorization': 'token aaabbbcccddd'}
  1317. output = self.app.patch(
  1318. '/api/0/test', headers=headers,
  1319. data={'main_admin': 'foo'})
  1320. self.assertEqual(output.status_code, 200)
  1321. data = json.loads(output.get_data(as_text=True))
  1322. data['date_created'] = '1496338274'
  1323. data['date_modified'] = '1496338274'
  1324. expected_output = {
  1325. "access_groups": {
  1326. "admin": [],
  1327. "commit": [],
  1328. "ticket": []
  1329. },
  1330. "access_users": {
  1331. "admin": [],
  1332. "commit": [],
  1333. "owner": [
  1334. "foo"
  1335. ],
  1336. "ticket": []
  1337. },
  1338. "close_status": [
  1339. "Invalid",
  1340. "Insufficient data",
  1341. "Fixed",
  1342. "Duplicate"
  1343. ],
  1344. "custom_keys": [],
  1345. "date_created": "1496338274",
  1346. "date_modified": "1496338274",
  1347. "description": "test project #1",
  1348. "fullname": "test",
  1349. "url_path": "test",
  1350. "id": 1,
  1351. "milestones": {},
  1352. "name": "test",
  1353. "namespace": None,
  1354. "parent": None,
  1355. "priorities": {},
  1356. "tags": [],
  1357. "user": {
  1358. "default_email": "foo@bar.com",
  1359. "emails": [
  1360. "foo@bar.com"
  1361. ],
  1362. "fullname": "foo bar",
  1363. "name": "foo"
  1364. }
  1365. }
  1366. self.assertEqual(data, expected_output)
  1367. def test_api_modify_project_main_admin_retain_access(self):
  1368. """ Test the api_modify_project method of the flask api when the
  1369. request is to change the main_admin of the project and retain_access
  1370. is true. """
  1371. tests.create_projects(self.session)
  1372. tests.create_tokens(self.session, project_id=None)
  1373. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1374. headers = {'Authorization': 'token aaabbbcccddd'}
  1375. output = self.app.patch(
  1376. '/api/0/test', headers=headers,
  1377. data={'main_admin': 'foo', 'retain_access': True})
  1378. self.assertEqual(output.status_code, 200)
  1379. data = json.loads(output.get_data(as_text=True))
  1380. data['date_created'] = '1496338274'
  1381. data['date_modified'] = '1496338274'
  1382. expected_output = {
  1383. "access_groups": {
  1384. "admin": [],
  1385. "commit": [],
  1386. "ticket": []
  1387. },
  1388. "access_users": {
  1389. "admin": [
  1390. "pingou"
  1391. ],
  1392. "commit": [],
  1393. "owner": [
  1394. "foo"
  1395. ],
  1396. "ticket": []
  1397. },
  1398. "close_status": [
  1399. "Invalid",
  1400. "Insufficient data",
  1401. "Fixed",
  1402. "Duplicate"
  1403. ],
  1404. "custom_keys": [],
  1405. "date_created": "1496338274",
  1406. "date_modified": "1496338274",
  1407. "description": "test project #1",
  1408. "fullname": "test",
  1409. "url_path": "test",
  1410. "id": 1,
  1411. "milestones": {},
  1412. "name": "test",
  1413. "namespace": None,
  1414. "parent": None,
  1415. "priorities": {},
  1416. "tags": [],
  1417. "user": {
  1418. "default_email": "foo@bar.com",
  1419. "emails": [
  1420. "foo@bar.com"
  1421. ],
  1422. "fullname": "foo bar",
  1423. "name": "foo"
  1424. }
  1425. }
  1426. self.assertEqual(data, expected_output)
  1427. def test_api_modify_project_main_admin_retain_access_already_user(self):
  1428. """ Test the api_modify_project method of the flask api when the
  1429. request is to change the main_admin of the project and retain_access
  1430. is true and the user becoming the main_admin already has access. """
  1431. tests.create_projects(self.session)
  1432. tests.create_tokens(self.session, project_id=None)
  1433. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1434. headers = {'Authorization': 'token aaabbbcccddd'}
  1435. project = pagure.lib.query._get_project(self.session, 'test')
  1436. pagure.lib.query.add_user_to_project(
  1437. self.session, project,
  1438. new_user='foo',
  1439. user='pingou',
  1440. access='commit'
  1441. )
  1442. self.session.commit()
  1443. output = self.app.patch(
  1444. '/api/0/test', headers=headers,
  1445. data={'main_admin': 'foo', 'retain_access': True})
  1446. self.assertEqual(output.status_code, 200)
  1447. data = json.loads(output.get_data(as_text=True))
  1448. data['date_created'] = '1496338274'
  1449. data['date_modified'] = '1496338274'
  1450. expected_output = {
  1451. "access_groups": {
  1452. "admin": [],
  1453. "commit": [],
  1454. "ticket": []
  1455. },
  1456. "access_users": {
  1457. "admin": [
  1458. "pingou"
  1459. ],
  1460. "commit": [],
  1461. "owner": [
  1462. "foo"
  1463. ],
  1464. "ticket": []
  1465. },
  1466. "close_status": [
  1467. "Invalid",
  1468. "Insufficient data",
  1469. "Fixed",
  1470. "Duplicate"
  1471. ],
  1472. "custom_keys": [],
  1473. "date_created": "1496338274",
  1474. "date_modified": "1496338274",
  1475. "description": "test project #1",
  1476. "fullname": "test",
  1477. "url_path": "test",
  1478. "id": 1,
  1479. "milestones": {},
  1480. "name": "test",
  1481. "namespace": None,
  1482. "parent": None,
  1483. "priorities": {},
  1484. "tags": [],
  1485. "user": {
  1486. "default_email": "foo@bar.com",
  1487. "emails": [
  1488. "foo@bar.com"
  1489. ],
  1490. "fullname": "foo bar",
  1491. "name": "foo"
  1492. }
  1493. }
  1494. self.assertEqual(data, expected_output)
  1495. def test_api_modify_project_main_admin_json(self):
  1496. """ Test the api_modify_project method of the flask api when the
  1497. request is to change the main_admin of the project using JSON. """
  1498. tests.create_projects(self.session)
  1499. tests.create_tokens(self.session, project_id=None)
  1500. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1501. headers = {'Authorization': 'token aaabbbcccddd',
  1502. 'Content-Type': 'application/json'}
  1503. output = self.app.patch(
  1504. '/api/0/test', headers=headers,
  1505. data=json.dumps({'main_admin': 'foo'}))
  1506. self.assertEqual(output.status_code, 200)
  1507. data = json.loads(output.get_data(as_text=True))
  1508. data['date_created'] = '1496338274'
  1509. data['date_modified'] = '1496338274'
  1510. expected_output = {
  1511. "access_groups": {
  1512. "admin": [],
  1513. "commit": [],
  1514. "ticket": []
  1515. },
  1516. "access_users": {
  1517. "admin": [],
  1518. "commit": [],
  1519. "owner": [
  1520. "foo"
  1521. ],
  1522. "ticket": []
  1523. },
  1524. "close_status": [
  1525. "Invalid",
  1526. "Insufficient data",
  1527. "Fixed",
  1528. "Duplicate"
  1529. ],
  1530. "custom_keys": [],
  1531. "date_created": "1496338274",
  1532. "date_modified": "1496338274",
  1533. "description": "test project #1",
  1534. "fullname": "test",
  1535. "url_path": "test",
  1536. "id": 1,
  1537. "milestones": {},
  1538. "name": "test",
  1539. "namespace": None,
  1540. "parent": None,
  1541. "priorities": {},
  1542. "tags": [],
  1543. "user": {
  1544. "default_email": "foo@bar.com",
  1545. "emails": [
  1546. "foo@bar.com"
  1547. ],
  1548. "fullname": "foo bar",
  1549. "name": "foo"
  1550. }
  1551. }
  1552. self.assertEqual(data, expected_output)
  1553. @patch.dict('pagure.config.config', {'PAGURE_ADMIN_USERS': 'foo'})
  1554. def test_api_modify_project_main_admin_as_site_admin(self):
  1555. """ Test the api_modify_project method of the flask api when the
  1556. request is to change the main_admin of the project and the user is a
  1557. Pagure site admin. """
  1558. tests.create_projects(self.session)
  1559. tests.create_tokens(self.session, user_id=2, project_id=None)
  1560. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1561. headers = {'Authorization': 'token aaabbbcccddd'}
  1562. # date before:
  1563. project = pagure.lib.query.get_authorized_project(
  1564. self.session, 'test')
  1565. date_before = project.date_modified
  1566. self.assertIsNotNone(date_before)
  1567. output = self.app.patch(
  1568. '/api/0/test', headers=headers,
  1569. data={'main_admin': 'foo'})
  1570. self.assertEqual(output.status_code, 200)
  1571. data = json.loads(output.get_data(as_text=True))
  1572. data['date_created'] = '1496338274'
  1573. data['date_modified'] = '1496338274'
  1574. expected_output = {
  1575. "access_groups": {
  1576. "admin": [],
  1577. "commit": [],
  1578. "ticket": []
  1579. },
  1580. "access_users": {
  1581. "admin": [],
  1582. "commit": [],
  1583. "owner": [
  1584. "foo"
  1585. ],
  1586. "ticket": []
  1587. },
  1588. "close_status": [
  1589. "Invalid",
  1590. "Insufficient data",
  1591. "Fixed",
  1592. "Duplicate"
  1593. ],
  1594. "custom_keys": [],
  1595. "date_created": "1496338274",
  1596. "date_modified": "1496338274",
  1597. "description": "test project #1",
  1598. "fullname": "test",
  1599. "url_path": "test",
  1600. "id": 1,
  1601. "milestones": {},
  1602. "name": "test",
  1603. "namespace": None,
  1604. "parent": None,
  1605. "priorities": {},
  1606. "tags": [],
  1607. "user": {
  1608. "default_email": "foo@bar.com",
  1609. "emails": [
  1610. "foo@bar.com"
  1611. ],
  1612. "fullname": "foo bar",
  1613. "name": "foo"
  1614. }
  1615. }
  1616. self.assertEqual(data, expected_output)
  1617. # date after:
  1618. self.session = pagure.lib.query.create_session(self.dbpath)
  1619. project = pagure.lib.query.get_authorized_project(
  1620. self.session, 'test')
  1621. self.assertNotEqual(date_before, project.date_modified)
  1622. def test_api_modify_project_main_admin_not_main_admin(self):
  1623. """ Test the api_modify_project method of the flask api when the
  1624. requester is not the main_admin of the project and requests to change
  1625. the main_admin.
  1626. """
  1627. tests.create_projects(self.session)
  1628. project_user = pagure.lib.query.model.ProjectUser(
  1629. project_id=1,
  1630. user_id=2,
  1631. access='admin',
  1632. )
  1633. self.session.add(project_user)
  1634. self.session.commit()
  1635. tests.create_tokens(self.session, project_id=None, user_id=2)
  1636. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1637. headers = {'Authorization': 'token aaabbbcccddd'}
  1638. output = self.app.patch(
  1639. '/api/0/test', headers=headers,
  1640. data={'main_admin': 'foo'})
  1641. self.assertEqual(output.status_code, 401)
  1642. expected_error = {
  1643. 'error': ('Only the main admin can set the main admin of a '
  1644. 'project'),
  1645. 'error_code': 'ENOTMAINADMIN'
  1646. }
  1647. self.assertEqual(
  1648. json.loads(output.get_data(as_text=True)), expected_error)
  1649. def test_api_modify_project_not_admin(self):
  1650. """ Test the api_modify_project method of the flask api when the
  1651. requester is not an admin of the project.
  1652. """
  1653. tests.create_projects(self.session)
  1654. tests.create_tokens(self.session, project_id=None, user_id=2)
  1655. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1656. headers = {'Authorization': 'token aaabbbcccddd'}
  1657. output = self.app.patch(
  1658. '/api/0/test', headers=headers,
  1659. data={'main_admin': 'foo'})
  1660. self.assertEqual(output.status_code, 401)
  1661. expected_error = {
  1662. 'error': 'You are not allowed to modify this project',
  1663. 'error_code': 'EMODIFYPROJECTNOTALLOWED'
  1664. }
  1665. self.assertEqual(
  1666. json.loads(output.get_data(as_text=True)), expected_error)
  1667. def test_api_modify_project_invalid_request(self):
  1668. """ Test the api_modify_project method of the flask api when the
  1669. request data is invalid.
  1670. """
  1671. tests.create_projects(self.session)
  1672. tests.create_tokens(self.session, project_id=None)
  1673. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1674. headers = {'Authorization': 'token aaabbbcccddd'}
  1675. output = self.app.patch(
  1676. '/api/0/test', headers=headers,
  1677. data='invalid')
  1678. self.assertEqual(output.status_code, 400)
  1679. expected_error = {
  1680. 'error': 'Invalid or incomplete input submitted',
  1681. 'error_code': 'EINVALIDREQ'
  1682. }
  1683. self.assertEqual(
  1684. json.loads(output.get_data(as_text=True)), expected_error)
  1685. def test_api_modify_project_invalid_keys(self):
  1686. """ Test the api_modify_project method of the flask api when the
  1687. request data contains an invalid key.
  1688. """
  1689. tests.create_projects(self.session)
  1690. tests.create_tokens(self.session, project_id=None)
  1691. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1692. headers = {'Authorization': 'token aaabbbcccddd'}
  1693. output = self.app.patch(
  1694. '/api/0/test', headers=headers,
  1695. data={'invalid': 'invalid'})
  1696. self.assertEqual(output.status_code, 400)
  1697. expected_error = {
  1698. 'error': 'Invalid or incomplete input submitted',
  1699. 'error_code': 'EINVALIDREQ'
  1700. }
  1701. self.assertEqual(
  1702. json.loads(output.get_data(as_text=True)), expected_error)
  1703. def test_api_modify_project_invalid_new_main_admin(self):
  1704. """ Test the api_modify_project method of the flask api when the
  1705. request is to change the main_admin of the project to a main_admin
  1706. that doesn't exist.
  1707. """
  1708. tests.create_projects(self.session)
  1709. tests.create_tokens(self.session, project_id=None)
  1710. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1711. headers = {'Authorization': 'token aaabbbcccddd'}
  1712. output = self.app.patch(
  1713. '/api/0/test', headers=headers,
  1714. data={'main_admin': 'tbrady'})
  1715. self.assertEqual(output.status_code, 400)
  1716. expected_error = {
  1717. 'error': 'No such user found',
  1718. 'error_code': 'ENOUSER'
  1719. }
  1720. self.assertEqual(
  1721. json.loads(output.get_data(as_text=True)), expected_error)
  1722. def test_api_project_watchers(self):
  1723. """ Test the api_project_watchers method of the flask api. """
  1724. tests.create_projects(self.session)
  1725. # The user is not logged in and the owner is watching issues implicitly
  1726. output = self.app.get('/api/0/test/watchers')
  1727. self.assertEqual(output.status_code, 200)
  1728. expected_data = {
  1729. "total_watchers": 1,
  1730. "watchers": {
  1731. "pingou": [
  1732. "issues"
  1733. ]
  1734. }
  1735. }
  1736. self.assertDictEqual(json.loads(output.get_data(as_text=True)), expected_data)
  1737. user = tests.FakeUser(username='pingou')
  1738. with tests.user_set(self.app.application, user):
  1739. # Non-existing project
  1740. output = self.app.get('/api/0/random/watchers')
  1741. self.assertEqual(output.status_code, 404)
  1742. data = json.loads(output.get_data(as_text=True))
  1743. self.assertDictEqual(
  1744. data,
  1745. {'error_code': 'ENOPROJECT', 'error': 'Project not found'}
  1746. )
  1747. # The owner is watching issues implicitly
  1748. output = self.app.get('/api/0/test/watchers')
  1749. self.assertEqual(output.status_code, 200)
  1750. expected_data = {
  1751. "total_watchers": 1,
  1752. "watchers": {
  1753. "pingou": [
  1754. "issues"
  1755. ]
  1756. }
  1757. }
  1758. self.assertDictEqual(json.loads(output.get_data(as_text=True)), expected_data)
  1759. project = pagure.lib.query.get_authorized_project(self.session, 'test')
  1760. # The owner is watching issues and commits explicitly
  1761. pagure.lib.query.update_watch_status(
  1762. self.session, project, 'pingou', '3')
  1763. self.session.commit()
  1764. output = self.app.get('/api/0/test/watchers')
  1765. self.assertEqual(output.status_code, 200)
  1766. expected_data = {
  1767. "total_watchers": 1,
  1768. "watchers": {
  1769. "pingou": [
  1770. "issues",
  1771. "commits"
  1772. ]
  1773. }
  1774. }
  1775. self.assertDictEqual(json.loads(output.get_data(as_text=True)), expected_data)
  1776. # The owner is watching issues explicitly
  1777. pagure.lib.query.update_watch_status(
  1778. self.session, project, 'pingou', '1')
  1779. self.session.commit()
  1780. output = self.app.get('/api/0/test/watchers')
  1781. self.assertEqual(output.status_code, 200)
  1782. expected_data = {
  1783. "total_watchers": 1,
  1784. "watchers": {
  1785. "pingou": [
  1786. "issues"
  1787. ]
  1788. }
  1789. }
  1790. self.assertDictEqual(json.loads(output.get_data(as_text=True)), expected_data)
  1791. # The owner is watching commits explicitly
  1792. pagure.lib.query.update_watch_status(
  1793. self.session, project, 'pingou', '2')
  1794. self.session.commit()
  1795. output = self.app.get('/api/0/test/watchers')
  1796. self.assertEqual(output.status_code, 200)
  1797. expected_data = {
  1798. "total_watchers": 1,
  1799. "watchers": {
  1800. "pingou": [
  1801. "commits"
  1802. ]
  1803. }
  1804. }
  1805. self.assertDictEqual(json.loads(output.get_data(as_text=True)), expected_data)
  1806. # The owner is watching commits explicitly and foo is watching
  1807. # issues implicitly
  1808. project_user = pagure.lib.model.ProjectUser(
  1809. project_id=project.id,
  1810. user_id=2,
  1811. access='commit',
  1812. )
  1813. pagure.lib.query.update_watch_status(
  1814. self.session, project, 'pingou', '2')
  1815. self.session.add(project_user)
  1816. self.session.commit()
  1817. output = self.app.get('/api/0/test/watchers')
  1818. self.assertEqual(output.status_code, 200)
  1819. expected_data = {
  1820. "total_watchers": 2,
  1821. "watchers": {
  1822. "foo": ["issues"],
  1823. "pingou": ["commits"]
  1824. }
  1825. }
  1826. self.assertDictEqual(json.loads(output.get_data(as_text=True)), expected_data)
  1827. # The owner and foo are watching issues implicitly
  1828. pagure.lib.query.update_watch_status(
  1829. self.session, project, 'pingou', '-1')
  1830. self.session.commit()
  1831. output = self.app.get('/api/0/test/watchers')
  1832. self.assertEqual(output.status_code, 200)
  1833. expected_data = {
  1834. "total_watchers": 2,
  1835. "watchers": {
  1836. "foo": ["issues"],
  1837. "pingou": ["issues"]
  1838. }
  1839. }
  1840. self.assertDictEqual(json.loads(output.get_data(as_text=True)), expected_data)
  1841. # The owner and foo through group membership are watching issues
  1842. # implicitly
  1843. pagure.lib.query.update_watch_status(
  1844. self.session, project, 'pingou', '-1')
  1845. project_membership = self.session.query(
  1846. pagure.lib.model.ProjectUser).filter_by(
  1847. user_id=2, project_id=project.id).one()
  1848. self.session.delete(project_membership)
  1849. self.session.commit()
  1850. msg = pagure.lib.query.add_group(
  1851. self.session,
  1852. group_name='some_group',
  1853. display_name='Some Group',
  1854. description=None,
  1855. group_type='bar',
  1856. user='pingou',
  1857. is_admin=False,
  1858. blacklist=[],
  1859. )
  1860. self.session.commit()
  1861. project = pagure.lib.query.get_authorized_project(self.session, 'test')
  1862. group = pagure.lib.query.search_groups(
  1863. self.session, group_name='some_group')
  1864. pagure.lib.query.add_user_to_group(
  1865. self.session, 'foo', group, 'pingou', False)
  1866. pagure.lib.query.add_group_to_project(
  1867. self.session,
  1868. project,
  1869. new_group='some_group',
  1870. user='pingou',
  1871. access='commit',
  1872. create=False,
  1873. is_admin=True
  1874. )
  1875. self.session.commit()
  1876. output = self.app.get('/api/0/test/watchers')
  1877. self.assertEqual(output.status_code, 200)
  1878. expected_data = {
  1879. "total_watchers": 2,
  1880. "watchers": {
  1881. "@some_group": ["issues"],
  1882. "pingou": ["issues"]
  1883. }
  1884. }
  1885. self.assertDictEqual(json.loads(output.get_data(as_text=True)), expected_data)
  1886. # The owner is watching issues implicitly and foo will be watching
  1887. # commits explicitly but is in a group with commit access
  1888. pagure.lib.query.update_watch_status(
  1889. self.session, project, 'pingou', '-1')
  1890. pagure.lib.query.update_watch_status(
  1891. self.session, project, 'foo', '2')
  1892. self.session.commit()
  1893. output = self.app.get('/api/0/test/watchers')
  1894. self.assertEqual(output.status_code, 200)
  1895. expected_data = {
  1896. "total_watchers": 3,
  1897. "watchers": {
  1898. "@some_group": ["issues"],
  1899. "foo": ["commits"],
  1900. "pingou": ["issues"]
  1901. }
  1902. }
  1903. self.assertDictEqual(json.loads(output.get_data(as_text=True)), expected_data)
  1904. def test_api_new_project(self):
  1905. """ Test the api_new_project method of the flask api. """
  1906. tests.create_projects(self.session)
  1907. tests.create_projects_git(os.path.join(self.path, 'tickets'))
  1908. tests.create_tokens(self.session)
  1909. tests.create_tokens_acl(self.session)
  1910. headers = {'Authorization': 'token foo_token'}
  1911. # Invalid token
  1912. output = self.app.post('/api/0/new', headers=headers)
  1913. self.assertEqual(output.status_code, 401)
  1914. data = json.loads(output.get_data(as_text=True))
  1915. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  1916. self.assertEqual(
  1917. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  1918. self.assertEqual(
  1919. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  1920. headers = {'Authorization': 'token aaabbbcccddd'}
  1921. # No input
  1922. output = self.app.post('/api/0/new', headers=headers)
  1923. self.assertEqual(output.status_code, 400)
  1924. data = json.loads(output.get_data(as_text=True))
  1925. self.assertDictEqual(
  1926. data,
  1927. {
  1928. "error": "Invalid or incomplete input submitted",
  1929. "error_code": "EINVALIDREQ",
  1930. "errors": {
  1931. "name": ["This field is required."],
  1932. "description": ["This field is required."]
  1933. }
  1934. }
  1935. )
  1936. data = {
  1937. 'name': 'test',
  1938. }
  1939. # Incomplete request
  1940. output = self.app.post(
  1941. '/api/0/new', data=data, headers=headers)
  1942. self.assertEqual(output.status_code, 400)
  1943. data = json.loads(output.get_data(as_text=True))
  1944. self.assertDictEqual(
  1945. data,
  1946. {
  1947. "error": "Invalid or incomplete input submitted",
  1948. "error_code": "EINVALIDREQ",
  1949. "errors": {"description": ["This field is required."]}
  1950. }
  1951. )
  1952. data = {
  1953. 'name': 'test',
  1954. 'description': 'Just a small test project',
  1955. }
  1956. # Valid request but repo already exists
  1957. output = self.app.post(
  1958. '/api/0/new/', data=data, headers=headers)
  1959. self.assertEqual(output.status_code, 400)
  1960. data = json.loads(output.get_data(as_text=True))
  1961. self.assertDictEqual(
  1962. data,
  1963. {
  1964. "error": "It is not possible to create the repo \"test\"",
  1965. "error_code": "ENOCODE"
  1966. }
  1967. )
  1968. data = {
  1969. 'name': 'api1',
  1970. 'description': 'Mighty mighty description',
  1971. 'avatar_email': 123
  1972. }
  1973. # invalid avatar_email - number
  1974. output = self.app.post(
  1975. '/api/0/new/', data=data, headers=headers)
  1976. self.assertEqual(output.status_code, 400)
  1977. data = json.loads(output.get_data(as_text=True))
  1978. self.assertDictEqual(data,
  1979. {"error": "Invalid or incomplete input submitted",
  1980. "error_code": "EINVALIDREQ",
  1981. "errors":
  1982. {"avatar_email": ['avatar_email must be an email']}
  1983. }
  1984. )
  1985. data = {
  1986. 'name': 'api1',
  1987. 'description': 'Mighty mighty description',
  1988. 'avatar_email': [1,2,3]
  1989. }
  1990. # invalid avatar_email - list
  1991. output = self.app.post(
  1992. '/api/0/new/', data=data, headers=headers)
  1993. self.assertEqual(output.status_code, 400)
  1994. data = json.loads(output.get_data(as_text=True))
  1995. self.assertDictEqual(data,
  1996. {"error": "Invalid or incomplete input submitted",
  1997. "error_code": "EINVALIDREQ",
  1998. "errors":
  1999. {"avatar_email": ['avatar_email must be an email']}
  2000. }
  2001. )
  2002. data = {
  2003. 'name': 'api1',
  2004. 'description': 'Mighty mighty description',
  2005. 'avatar_email': True
  2006. }
  2007. # invalid avatar_email - boolean
  2008. output = self.app.post(
  2009. '/api/0/new/', data=data, headers=headers)
  2010. self.assertEqual(output.status_code, 400)
  2011. data = json.loads(output.get_data(as_text=True))
  2012. self.assertDictEqual(data,
  2013. {"error": "Invalid or incomplete input submitted",
  2014. "error_code": "EINVALIDREQ",
  2015. "errors":
  2016. {"avatar_email": ['avatar_email must be an email']}
  2017. }
  2018. )
  2019. data = {
  2020. 'name': 'api1',
  2021. 'description': 'Mighty mighty description',
  2022. 'avatar_email': 'mighty@email.com'
  2023. }
  2024. # valid avatar_email
  2025. output = self.app.post(
  2026. '/api/0/new/', data=data, headers=headers)
  2027. self.assertEqual(output.status_code, 200)
  2028. data = json.loads(output.get_data(as_text=True))
  2029. self.assertDictEqual(
  2030. data,
  2031. {'message': 'Project "api1" created'})
  2032. data = {
  2033. 'name': 'test_42',
  2034. 'description': 'Just another small test project',
  2035. }
  2036. # Valid request
  2037. output = self.app.post(
  2038. '/api/0/new/', data=data, headers=headers)
  2039. self.assertEqual(output.status_code, 200)
  2040. data = json.loads(output.get_data(as_text=True))
  2041. self.assertDictEqual(
  2042. data,
  2043. {'message': 'Project "test_42" created'}
  2044. )
  2045. @patch.dict('pagure.config.config', {'PAGURE_ADMIN_USERS': ['pingou'],
  2046. 'ALLOW_ADMIN_IGNORE_EXISTING_REPOS': True})
  2047. def test_adopt_repos(self):
  2048. """ Test the new_project endpoint with existing git repo. """
  2049. # Before
  2050. projects = pagure.lib.query.search_projects(self.session)
  2051. self.assertEqual(len(projects), 0)
  2052. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  2053. tests.add_content_git_repo(os.path.join(self.path, 'repos', 'test.git'))
  2054. item = pagure.lib.model.Token(
  2055. id='aaabbbcccddd',
  2056. user_id=1,
  2057. project_id=None,
  2058. expiration=datetime.datetime.utcnow() + datetime.timedelta(days=10)
  2059. )
  2060. self.session.add(item)
  2061. self.session.commit()
  2062. tests.create_tokens_acl(self.session)
  2063. headers = {'Authorization': 'token aaabbbcccddd'}
  2064. user = tests.FakeUser(username='pingou')
  2065. with tests.user_set(self.app.application, user):
  2066. input_data = {
  2067. 'name': 'test',
  2068. 'description': 'Project #1',
  2069. }
  2070. # Valid request
  2071. output = self.app.post(
  2072. '/api/0/new/', data=input_data, headers=headers)
  2073. self.assertEqual(output.status_code, 400)
  2074. data = json.loads(output.get_data(as_text=True))
  2075. self.assertDictEqual(
  2076. data,
  2077. {
  2078. 'error': 'The main repo test.git already exists',
  2079. 'error_code': 'ENOCODE'
  2080. }
  2081. )
  2082. input_data['ignore_existing_repos'] = 'y'
  2083. # Valid request
  2084. output = self.app.post(
  2085. '/api/0/new/', data=input_data, headers=headers)
  2086. self.assertEqual(output.status_code, 200)
  2087. data = json.loads(output.get_data(as_text=True))
  2088. self.assertDictEqual(
  2089. data,
  2090. {'message': 'Project "test" created'}
  2091. )
  2092. @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
  2093. def test_api_new_project_private(self):
  2094. """ Test the api_new_project method of the flask api to create
  2095. a private project. """
  2096. tests.create_projects(self.session)
  2097. tests.create_projects_git(os.path.join(self.path, 'tickets'))
  2098. tests.create_tokens(self.session)
  2099. tests.create_tokens_acl(self.session)
  2100. headers = {'Authorization': 'token aaabbbcccddd'}
  2101. data = {
  2102. 'name': 'test',
  2103. 'description': 'Just a small test project',
  2104. 'private': True,
  2105. }
  2106. # Valid request
  2107. output = self.app.post(
  2108. '/api/0/new/', data=data, headers=headers)
  2109. self.assertEqual(output.status_code, 200)
  2110. data = json.loads(output.get_data(as_text=True))
  2111. self.assertDictEqual(
  2112. data,
  2113. {'message': 'Project "pingou/test" created'}
  2114. )
  2115. def test_api_new_project_user_token(self):
  2116. """ Test the api_new_project method of the flask api. """
  2117. tests.create_projects(self.session)
  2118. tests.create_projects_git(os.path.join(self.path, 'tickets'))
  2119. tests.create_tokens(self.session, project_id=None)
  2120. tests.create_tokens_acl(self.session)
  2121. headers = {'Authorization': 'token foo_token'}
  2122. # Invalid token
  2123. output = self.app.post('/api/0/new', headers=headers)
  2124. self.assertEqual(output.status_code, 401)
  2125. data = json.loads(output.get_data(as_text=True))
  2126. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  2127. self.assertEqual(
  2128. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  2129. self.assertEqual(
  2130. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  2131. headers = {'Authorization': 'token aaabbbcccddd'}
  2132. # No input
  2133. output = self.app.post('/api/0/new', headers=headers)
  2134. self.assertEqual(output.status_code, 400)
  2135. data = json.loads(output.get_data(as_text=True))
  2136. self.assertDictEqual(
  2137. data,
  2138. {
  2139. "error": "Invalid or incomplete input submitted",
  2140. "error_code": "EINVALIDREQ",
  2141. "errors": {
  2142. "name": ["This field is required."],
  2143. "description": ["This field is required."]
  2144. }
  2145. }
  2146. )
  2147. data = {
  2148. 'name': 'test',
  2149. }
  2150. # Incomplete request
  2151. output = self.app.post(
  2152. '/api/0/new', data=data, headers=headers)
  2153. self.assertEqual(output.status_code, 400)
  2154. data = json.loads(output.get_data(as_text=True))
  2155. self.assertDictEqual(
  2156. data,
  2157. {
  2158. "error": "Invalid or incomplete input submitted",
  2159. "error_code": "EINVALIDREQ",
  2160. "errors": {"description": ["This field is required."]}
  2161. }
  2162. )
  2163. data = {
  2164. 'name': 'test',
  2165. 'description': 'Just a small test project',
  2166. }
  2167. # Valid request but repo already exists
  2168. output = self.app.post(
  2169. '/api/0/new/', data=data, headers=headers)
  2170. self.assertEqual(output.status_code, 400)
  2171. data = json.loads(output.get_data(as_text=True))
  2172. self.assertDictEqual(
  2173. data,
  2174. {
  2175. "error": "It is not possible to create the repo \"test\"",
  2176. "error_code": "ENOCODE"
  2177. }
  2178. )
  2179. data = {
  2180. 'name': 'test_42',
  2181. 'description': 'Just another small test project',
  2182. }
  2183. # Valid request
  2184. output = self.app.post(
  2185. '/api/0/new/', data=data, headers=headers)
  2186. self.assertEqual(output.status_code, 200)
  2187. data = json.loads(output.get_data(as_text=True))
  2188. self.assertDictEqual(
  2189. data,
  2190. {'message': 'Project "test_42" created'}
  2191. )
  2192. # Project with a namespace
  2193. pagure.config.config['ALLOWED_PREFIX'] = ['rpms']
  2194. data = {
  2195. 'name': 'test_42',
  2196. 'namespace': 'pingou',
  2197. 'description': 'Just another small test project',
  2198. }
  2199. # Invalid namespace
  2200. output = self.app.post(
  2201. '/api/0/new/', data=data, headers=headers)
  2202. self.assertEqual(output.status_code, 400)
  2203. data = json.loads(output.get_data(as_text=True))
  2204. self.assertDictEqual(
  2205. data,
  2206. {
  2207. "error": "Invalid or incomplete input submitted",
  2208. "error_code": "EINVALIDREQ",
  2209. "errors": {
  2210. "namespace": [
  2211. "Not a valid choice"
  2212. ]
  2213. }
  2214. }
  2215. )
  2216. data = {
  2217. 'name': 'test_42',
  2218. 'namespace': 'rpms',
  2219. 'description': 'Just another small test project',
  2220. }
  2221. # All good
  2222. output = self.app.post(
  2223. '/api/0/new/', data=data, headers=headers)
  2224. self.assertEqual(output.status_code, 200)
  2225. data = json.loads(output.get_data(as_text=True))
  2226. self.assertDictEqual(
  2227. data,
  2228. {'message': 'Project "rpms/test_42" created'}
  2229. )
  2230. @patch.dict('pagure.config.config', {'USER_NAMESPACE': True})
  2231. def test_api_new_project_user_ns(self):
  2232. """ Test the api_new_project method of the flask api. """
  2233. tests.create_projects(self.session)
  2234. tests.create_projects_git(os.path.join(self.path, 'tickets'))
  2235. tests.create_tokens(self.session)
  2236. tests.create_tokens_acl(self.session)
  2237. headers = {'Authorization': 'token aaabbbcccddd'}
  2238. # Create a project with the user namespace feature on
  2239. data = {
  2240. 'name': 'testproject',
  2241. 'description': 'Just another small test project',
  2242. }
  2243. # Valid request
  2244. output = self.app.post(
  2245. '/api/0/new/', data=data, headers=headers)
  2246. self.assertEqual(output.status_code, 200)
  2247. data = json.loads(output.get_data(as_text=True))
  2248. self.assertDictEqual(
  2249. data,
  2250. {'message': 'Project "pingou/testproject" created'}
  2251. )
  2252. # Create a project with a namespace and the user namespace feature on
  2253. data = {
  2254. 'name': 'testproject2',
  2255. 'namespace': 'testns',
  2256. 'description': 'Just another small test project',
  2257. }
  2258. # Valid request
  2259. with patch.dict('pagure.config.config', {'ALLOWED_PREFIX': ['testns']}):
  2260. output = self.app.post(
  2261. '/api/0/new/', data=data, headers=headers)
  2262. self.assertEqual(output.status_code, 200)
  2263. data = json.loads(output.get_data(as_text=True))
  2264. self.assertDictEqual(
  2265. data,
  2266. {'message': 'Project "testns/testproject2" created'}
  2267. )
  2268. def test_api_fork_project(self):
  2269. """ Test the api_fork_project method of the flask api. """
  2270. tests.create_projects(self.session)
  2271. for folder in ['docs', 'tickets', 'requests', 'repos']:
  2272. tests.create_projects_git(
  2273. os.path.join(self.path, folder), bare=True)
  2274. tests.create_tokens(self.session)
  2275. tests.create_tokens_acl(self.session)
  2276. headers = {'Authorization': 'token foo_token'}
  2277. # Invalid token
  2278. output = self.app.post('/api/0/fork', headers=headers)
  2279. self.assertEqual(output.status_code, 401)
  2280. data = json.loads(output.get_data(as_text=True))
  2281. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  2282. self.assertEqual(
  2283. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  2284. self.assertEqual(
  2285. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  2286. headers = {'Authorization': 'token aaabbbcccddd'}
  2287. # No input
  2288. output = self.app.post('/api/0/fork', headers=headers)
  2289. self.assertEqual(output.status_code, 400)
  2290. data = json.loads(output.get_data(as_text=True))
  2291. self.assertDictEqual(
  2292. data,
  2293. {
  2294. "error": "Invalid or incomplete input submitted",
  2295. "error_code": "EINVALIDREQ",
  2296. "errors": {"repo": ["This field is required."]}
  2297. }
  2298. )
  2299. data = {
  2300. 'name': 'test',
  2301. }
  2302. # Incomplete request
  2303. output = self.app.post(
  2304. '/api/0/fork', data=data, headers=headers)
  2305. self.assertEqual(output.status_code, 400)
  2306. data = json.loads(output.get_data(as_text=True))
  2307. self.assertDictEqual(
  2308. data,
  2309. {
  2310. "error": "Invalid or incomplete input submitted",
  2311. "error_code": "EINVALIDREQ",
  2312. "errors": {"repo": ["This field is required."]}
  2313. }
  2314. )
  2315. data = {
  2316. 'repo': 'test',
  2317. }
  2318. # Valid request
  2319. output = self.app.post(
  2320. '/api/0/fork/', data=data, headers=headers)
  2321. self.assertEqual(output.status_code, 200)
  2322. data = json.loads(output.get_data(as_text=True))
  2323. self.assertDictEqual(
  2324. data,
  2325. {
  2326. "message": "Repo \"test\" cloned to \"pingou/test\""
  2327. }
  2328. )
  2329. data = {
  2330. 'repo': 'test',
  2331. }
  2332. # project already forked
  2333. output = self.app.post(
  2334. '/api/0/fork/', data=data, headers=headers)
  2335. self.assertEqual(output.status_code, 400)
  2336. data = json.loads(output.get_data(as_text=True))
  2337. self.assertDictEqual(
  2338. data,
  2339. {
  2340. "error": "Repo \"forks/pingou/test\" already exists",
  2341. "error_code": "ENOCODE"
  2342. }
  2343. )
  2344. data = {
  2345. 'repo': 'test',
  2346. 'username': 'pingou',
  2347. }
  2348. # Fork already exists
  2349. output = self.app.post(
  2350. '/api/0/fork/', data=data, headers=headers)
  2351. self.assertEqual(output.status_code, 400)
  2352. data = json.loads(output.get_data(as_text=True))
  2353. self.assertDictEqual(
  2354. data,
  2355. {
  2356. "error": "Repo \"forks/pingou/test\" already exists",
  2357. "error_code": "ENOCODE"
  2358. }
  2359. )
  2360. data = {
  2361. 'repo': 'test',
  2362. 'namespace': 'pingou',
  2363. }
  2364. # Repo does not exists
  2365. output = self.app.post(
  2366. '/api/0/fork/', data=data, headers=headers)
  2367. self.assertEqual(output.status_code, 404)
  2368. data = json.loads(output.get_data(as_text=True))
  2369. self.assertDictEqual(
  2370. data,
  2371. {
  2372. "error": "Project not found",
  2373. "error_code": "ENOPROJECT"
  2374. }
  2375. )
  2376. def test_api_fork_project_user_token(self):
  2377. """ Test the api_fork_project method of the flask api. """
  2378. tests.create_projects(self.session)
  2379. for folder in ['docs', 'tickets', 'requests', 'repos']:
  2380. tests.create_projects_git(
  2381. os.path.join(self.path, folder), bare=True)
  2382. tests.create_tokens(self.session, project_id=None)
  2383. tests.create_tokens_acl(self.session)
  2384. headers = {'Authorization': 'token foo_token'}
  2385. # Invalid token
  2386. output = self.app.post('/api/0/fork', headers=headers)
  2387. self.assertEqual(output.status_code, 401)
  2388. data = json.loads(output.get_data(as_text=True))
  2389. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  2390. self.assertEqual(
  2391. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  2392. self.assertEqual(
  2393. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  2394. headers = {'Authorization': 'token aaabbbcccddd'}
  2395. # No input
  2396. output = self.app.post('/api/0/fork', headers=headers)
  2397. self.assertEqual(output.status_code, 400)
  2398. data = json.loads(output.get_data(as_text=True))
  2399. self.assertDictEqual(
  2400. data,
  2401. {
  2402. "error": "Invalid or incomplete input submitted",
  2403. "error_code": "EINVALIDREQ",
  2404. "errors": {"repo": ["This field is required."]}
  2405. }
  2406. )
  2407. data = {
  2408. 'name': 'test',
  2409. }
  2410. # Incomplete request
  2411. output = self.app.post(
  2412. '/api/0/fork', data=data, headers=headers)
  2413. self.assertEqual(output.status_code, 400)
  2414. data = json.loads(output.get_data(as_text=True))
  2415. self.assertDictEqual(
  2416. data,
  2417. {
  2418. "error": "Invalid or incomplete input submitted",
  2419. "error_code": "EINVALIDREQ",
  2420. "errors": {"repo": ["This field is required."]}
  2421. }
  2422. )
  2423. data = {
  2424. 'repo': 'test',
  2425. }
  2426. # Valid request
  2427. output = self.app.post(
  2428. '/api/0/fork/', data=data, headers=headers)
  2429. self.assertEqual(output.status_code, 200)
  2430. data = json.loads(output.get_data(as_text=True))
  2431. self.assertDictEqual(
  2432. data,
  2433. {
  2434. "message": "Repo \"test\" cloned to \"pingou/test\""
  2435. }
  2436. )
  2437. data = {
  2438. 'repo': 'test',
  2439. }
  2440. # project already forked
  2441. output = self.app.post(
  2442. '/api/0/fork/', data=data, headers=headers)
  2443. self.assertEqual(output.status_code, 400)
  2444. data = json.loads(output.get_data(as_text=True))
  2445. self.assertDictEqual(
  2446. data,
  2447. {
  2448. "error": "Repo \"forks/pingou/test\" already exists",
  2449. "error_code": "ENOCODE"
  2450. }
  2451. )
  2452. data = {
  2453. 'repo': 'test',
  2454. 'username': 'pingou',
  2455. }
  2456. # Fork already exists
  2457. output = self.app.post(
  2458. '/api/0/fork/', data=data, headers=headers)
  2459. self.assertEqual(output.status_code, 400)
  2460. data = json.loads(output.get_data(as_text=True))
  2461. self.assertDictEqual(
  2462. data,
  2463. {
  2464. "error": "Repo \"forks/pingou/test\" already exists",
  2465. "error_code": "ENOCODE"
  2466. }
  2467. )
  2468. data = {
  2469. 'repo': 'test',
  2470. 'namespace': 'pingou',
  2471. }
  2472. # Repo does not exists
  2473. output = self.app.post(
  2474. '/api/0/fork/', data=data, headers=headers)
  2475. self.assertEqual(output.status_code, 404)
  2476. data = json.loads(output.get_data(as_text=True))
  2477. self.assertDictEqual(
  2478. data,
  2479. {
  2480. "error": "Project not found",
  2481. "error_code": "ENOPROJECT"
  2482. }
  2483. )
  2484. def test_api_generate_acls(self):
  2485. """ Test the api_generate_acls method of the flask api """
  2486. tests.create_projects(self.session)
  2487. tests.create_tokens(self.session, project_id=None)
  2488. tests.create_tokens_acl(
  2489. self.session, 'aaabbbcccddd', 'generate_acls_project')
  2490. headers = {'Authorization': 'token aaabbbcccddd'}
  2491. user = pagure.lib.query.get_user(self.session, 'pingou')
  2492. output = self.app.post(
  2493. '/api/0/test/git/generateacls', headers=headers,
  2494. data={'wait': False})
  2495. self.assertEqual(output.status_code, 200)
  2496. data = json.loads(output.get_data(as_text=True))
  2497. expected_output = {
  2498. 'message': 'Project ACL generation queued',
  2499. 'taskid': 'abc-1234'
  2500. }
  2501. self.assertEqual(data, expected_output)
  2502. self.mock_gen_acls.assert_called_once_with(
  2503. name='test', namespace=None, user=None, group=None)
  2504. def test_api_generate_acls_json(self):
  2505. """ Test the api_generate_acls method of the flask api using JSON """
  2506. tests.create_projects(self.session)
  2507. tests.create_tokens(self.session, project_id=None)
  2508. tests.create_tokens_acl(
  2509. self.session, 'aaabbbcccddd', 'generate_acls_project')
  2510. headers = {'Authorization': 'token aaabbbcccddd',
  2511. 'Content-Type': 'application/json'}
  2512. user = pagure.lib.query.get_user(self.session, 'pingou')
  2513. output = self.app.post(
  2514. '/api/0/test/git/generateacls', headers=headers,
  2515. data=json.dumps({'wait': False}))
  2516. self.assertEqual(output.status_code, 200)
  2517. data = json.loads(output.get_data(as_text=True))
  2518. expected_output = {
  2519. 'message': 'Project ACL generation queued',
  2520. 'taskid': 'abc-1234'
  2521. }
  2522. self.assertEqual(data, expected_output)
  2523. self.mock_gen_acls.assert_called_once_with(
  2524. name='test', namespace=None, user=None, group=None)
  2525. def test_api_generate_acls_wait_true(self):
  2526. """ Test the api_generate_acls method of the flask api when wait is
  2527. set to True """
  2528. tests.create_projects(self.session)
  2529. tests.create_tokens(self.session, project_id=None)
  2530. tests.create_tokens_acl(
  2531. self.session, 'aaabbbcccddd', 'generate_acls_project')
  2532. headers = {'Authorization': 'token aaabbbcccddd'}
  2533. task_result = Mock()
  2534. task_result.id = 'abc-1234'
  2535. self.mock_gen_acls.return_value = task_result
  2536. user = pagure.lib.query.get_user(self.session, 'pingou')
  2537. output = self.app.post(
  2538. '/api/0/test/git/generateacls', headers=headers,
  2539. data={'wait': True})
  2540. self.assertEqual(output.status_code, 200)
  2541. data = json.loads(output.get_data(as_text=True))
  2542. expected_output = {
  2543. 'message': 'Project ACLs generated',
  2544. }
  2545. self.assertEqual(data, expected_output)
  2546. self.mock_gen_acls.assert_called_once_with(
  2547. name='test', namespace=None, user=None, group=None)
  2548. self.assertTrue(task_result.get.called)
  2549. def test_api_generate_acls_no_project(self):
  2550. """ Test the api_generate_acls method of the flask api when the project
  2551. doesn't exist """
  2552. tests.create_projects(self.session)
  2553. tests.create_tokens(self.session, project_id=None)
  2554. tests.create_tokens_acl(
  2555. self.session, 'aaabbbcccddd', 'generate_acls_project')
  2556. headers = {'Authorization': 'token aaabbbcccddd'}
  2557. user = pagure.lib.query.get_user(self.session, 'pingou')
  2558. output = self.app.post(
  2559. '/api/0/test12345123/git/generateacls', headers=headers,
  2560. data={'wait': False})
  2561. self.assertEqual(output.status_code, 404)
  2562. data = json.loads(output.get_data(as_text=True))
  2563. expected_output = {
  2564. 'error_code': 'ENOPROJECT',
  2565. 'error': 'Project not found'
  2566. }
  2567. self.assertEqual(data, expected_output)
  2568. def test_api_new_git_branch(self):
  2569. """ Test the api_new_branch method of the flask api """
  2570. tests.create_projects(self.session)
  2571. repo_path = os.path.join(self.path, 'repos')
  2572. tests.create_projects_git(repo_path, bare=True)
  2573. tests.add_content_git_repo(os.path.join(repo_path, 'test.git'))
  2574. tests.create_tokens(self.session, project_id=None)
  2575. tests.create_tokens_acl(
  2576. self.session, 'aaabbbcccddd', 'create_branch')
  2577. headers = {'Authorization': 'token aaabbbcccddd'}
  2578. args = {'branch': 'test123'}
  2579. output = self.app.post('/api/0/test/git/branch', headers=headers,
  2580. data=args)
  2581. self.assertEqual(output.status_code, 200)
  2582. data = json.loads(output.get_data(as_text=True))
  2583. expected_output = {
  2584. 'message': 'Project branch was created',
  2585. }
  2586. self.assertEqual(data, expected_output)
  2587. git_path = os.path.join(self.path, 'repos', 'test.git')
  2588. repo_obj = pygit2.Repository(git_path)
  2589. self.assertIn('test123', repo_obj.listall_branches())
  2590. def test_api_new_git_branch_json(self):
  2591. """ Test the api_new_branch method of the flask api """
  2592. tests.create_projects(self.session)
  2593. repo_path = os.path.join(self.path, 'repos')
  2594. tests.create_projects_git(repo_path, bare=True)
  2595. tests.add_content_git_repo(os.path.join(repo_path, 'test.git'))
  2596. tests.create_tokens(self.session, project_id=None)
  2597. tests.create_tokens_acl(
  2598. self.session, 'aaabbbcccddd', 'create_branch')
  2599. headers = {'Authorization': 'token aaabbbcccddd',
  2600. 'Content-Type': 'application/json'}
  2601. args = {'branch': 'test123'}
  2602. output = self.app.post('/api/0/test/git/branch', headers=headers,
  2603. data=json.dumps(args))
  2604. self.assertEqual(output.status_code, 200)
  2605. data = json.loads(output.get_data(as_text=True))
  2606. expected_output = {
  2607. 'message': 'Project branch was created',
  2608. }
  2609. self.assertEqual(data, expected_output)
  2610. git_path = os.path.join(self.path, 'repos', 'test.git')
  2611. repo_obj = pygit2.Repository(git_path)
  2612. self.assertIn('test123', repo_obj.listall_branches())
  2613. def test_api_new_git_branch_from_branch(self):
  2614. """ Test the api_new_branch method of the flask api """
  2615. tests.create_projects(self.session)
  2616. repo_path = os.path.join(self.path, 'repos')
  2617. tests.create_projects_git(repo_path, bare=True)
  2618. tests.add_content_git_repo(os.path.join(repo_path, 'test.git'))
  2619. tests.create_tokens(self.session, project_id=None)
  2620. tests.create_tokens_acl(
  2621. self.session, 'aaabbbcccddd', 'create_branch')
  2622. git_path = os.path.join(self.path, 'repos', 'test.git')
  2623. repo_obj = pygit2.Repository(git_path)
  2624. parent = pagure.lib.git.get_branch_ref(repo_obj, 'master').peel()
  2625. repo_obj.create_branch('dev123', parent)
  2626. headers = {'Authorization': 'token aaabbbcccddd'}
  2627. args = {'branch': 'test123', 'from_branch': 'dev123'}
  2628. output = self.app.post('/api/0/test/git/branch', headers=headers,
  2629. data=args)
  2630. self.assertEqual(output.status_code, 200)
  2631. data = json.loads(output.get_data(as_text=True))
  2632. expected_output = {
  2633. 'message': 'Project branch was created',
  2634. }
  2635. self.assertEqual(data, expected_output)
  2636. self.assertIn('test123', repo_obj.listall_branches())
  2637. def test_api_new_git_branch_already_exists(self):
  2638. """ Test the api_new_branch method of the flask api when branch already
  2639. exists """
  2640. tests.create_projects(self.session)
  2641. repo_path = os.path.join(self.path, 'repos')
  2642. tests.create_projects_git(repo_path, bare=True)
  2643. tests.add_content_git_repo(os.path.join(repo_path, 'test.git'))
  2644. tests.create_tokens(self.session, project_id=None)
  2645. tests.create_tokens_acl(
  2646. self.session, 'aaabbbcccddd', 'create_branch')
  2647. headers = {'Authorization': 'token aaabbbcccddd'}
  2648. args = {'branch': 'master'}
  2649. output = self.app.post('/api/0/test/git/branch', headers=headers,
  2650. data=args)
  2651. self.assertEqual(output.status_code, 400)
  2652. data = json.loads(output.get_data(as_text=True))
  2653. expected_output = {
  2654. 'error': 'The branch "master" already exists',
  2655. 'error_code': 'ENOCODE'
  2656. }
  2657. self.assertEqual(data, expected_output)
  2658. def test_api_new_git_branch_from_commit(self):
  2659. """ Test the api_new_branch method of the flask api """
  2660. tests.create_projects(self.session)
  2661. repos_path = os.path.join(self.path, 'repos')
  2662. tests.create_projects_git(repos_path, bare=True)
  2663. git_path = os.path.join(repos_path, 'test.git')
  2664. tests.add_content_git_repo(git_path)
  2665. tests.create_tokens(self.session, project_id=None)
  2666. tests.create_tokens_acl(
  2667. self.session, 'aaabbbcccddd', 'create_branch')
  2668. repo_obj = pygit2.Repository(git_path)
  2669. from_commit = repo_obj.revparse_single('HEAD').oid.hex
  2670. headers = {'Authorization': 'token aaabbbcccddd'}
  2671. args = {'branch': 'test123', 'from_commit': from_commit}
  2672. output = self.app.post('/api/0/test/git/branch', headers=headers,
  2673. data=args)
  2674. self.assertEqual(output.status_code, 200)
  2675. data = json.loads(output.get_data(as_text=True))
  2676. expected_output = {
  2677. 'message': 'Project branch was created',
  2678. }
  2679. self.assertEqual(data, expected_output)
  2680. self.assertIn('test123', repo_obj.listall_branches())
  2681. class PagureFlaskApiProjectFlagtests(tests.Modeltests):
  2682. """ Tests for the flask API of pagure for flagging commit in project
  2683. """
  2684. def setUp(self):
  2685. """ Set up the environnment, ran before every tests. """
  2686. super(PagureFlaskApiProjectFlagtests, self).setUp()
  2687. tests.create_projects(self.session)
  2688. repo_path = os.path.join(self.path, 'repos')
  2689. self.git_path = os.path.join(repo_path, 'test.git')
  2690. tests.create_projects_git(repo_path, bare=True)
  2691. tests.add_content_git_repo(self.git_path)
  2692. tests.create_tokens(self.session, project_id=None)
  2693. tests.create_tokens_acl(
  2694. self.session, 'aaabbbcccddd', 'commit_flag')
  2695. def test_flag_commit_missing_status(self):
  2696. """ Test flagging a commit with missing precentage. """
  2697. repo_obj = pygit2.Repository(self.git_path)
  2698. commit = repo_obj.revparse_single('HEAD')
  2699. headers = {'Authorization': 'token aaabbbcccddd'}
  2700. data = {
  2701. 'username': 'Jenkins',
  2702. 'comment': 'Tests passed',
  2703. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2704. 'uid': 'jenkins_build_pagure_100+seed',
  2705. }
  2706. output = self.app.post(
  2707. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2708. headers=headers, data=data)
  2709. self.assertEqual(output.status_code, 400)
  2710. data = json.loads(output.get_data(as_text=True))
  2711. expected_output = {
  2712. "error": "Invalid or incomplete input submitted",
  2713. "error_code": "EINVALIDREQ",
  2714. "errors": {
  2715. "status": [
  2716. "Not a valid choice"
  2717. ]
  2718. }
  2719. }
  2720. self.assertEqual(data, expected_output)
  2721. def test_flag_commit_missing_username(self):
  2722. """ Test flagging a commit with missing username. """
  2723. repo_obj = pygit2.Repository(self.git_path)
  2724. commit = repo_obj.revparse_single('HEAD')
  2725. headers = {'Authorization': 'token aaabbbcccddd'}
  2726. data = {
  2727. 'percent': 100,
  2728. 'comment': 'Tests passed',
  2729. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2730. 'uid': 'jenkins_build_pagure_100+seed',
  2731. 'status': 'success',
  2732. }
  2733. output = self.app.post(
  2734. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2735. headers=headers, data=data)
  2736. self.assertEqual(output.status_code, 400)
  2737. data = json.loads(output.get_data(as_text=True))
  2738. expected_output = {
  2739. "error": "Invalid or incomplete input submitted",
  2740. "error_code": "EINVALIDREQ",
  2741. "errors": {
  2742. "username": [
  2743. "This field is required."
  2744. ]
  2745. }
  2746. }
  2747. self.assertEqual(data, expected_output)
  2748. def test_flag_commit_missing_comment(self):
  2749. """ Test flagging a commit with missing comment. """
  2750. repo_obj = pygit2.Repository(self.git_path)
  2751. commit = repo_obj.revparse_single('HEAD')
  2752. headers = {'Authorization': 'token aaabbbcccddd'}
  2753. data = {
  2754. 'username': 'Jenkins',
  2755. 'percent': 100,
  2756. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2757. 'uid': 'jenkins_build_pagure_100+seed',
  2758. 'status': 'success',
  2759. }
  2760. output = self.app.post(
  2761. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2762. headers=headers, data=data)
  2763. self.assertEqual(output.status_code, 400)
  2764. data = json.loads(output.get_data(as_text=True))
  2765. expected_output = {
  2766. "error": "Invalid or incomplete input submitted",
  2767. "error_code": "EINVALIDREQ",
  2768. "errors": {
  2769. "comment": [
  2770. "This field is required."
  2771. ]
  2772. }
  2773. }
  2774. self.assertEqual(data, expected_output)
  2775. def test_flag_commit_missing_url(self):
  2776. """ Test flagging a commit with missing url. """
  2777. repo_obj = pygit2.Repository(self.git_path)
  2778. commit = repo_obj.revparse_single('HEAD')
  2779. headers = {'Authorization': 'token aaabbbcccddd'}
  2780. data = {
  2781. 'username': 'Jenkins',
  2782. 'percent': 100,
  2783. 'comment': 'Tests passed',
  2784. 'uid': 'jenkins_build_pagure_100+seed',
  2785. 'status': 'success',
  2786. }
  2787. output = self.app.post(
  2788. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2789. headers=headers, data=data)
  2790. self.assertEqual(output.status_code, 400)
  2791. data = json.loads(output.get_data(as_text=True))
  2792. expected_output = {
  2793. "error": "Invalid or incomplete input submitted",
  2794. "error_code": "EINVALIDREQ",
  2795. "errors": {
  2796. "url": [
  2797. "This field is required."
  2798. ]
  2799. }
  2800. }
  2801. self.assertEqual(data, expected_output)
  2802. def test_flag_commit_invalid_token(self):
  2803. """ Test flagging a commit with missing info. """
  2804. repo_obj = pygit2.Repository(self.git_path)
  2805. commit = repo_obj.revparse_single('HEAD')
  2806. headers = {'Authorization': 'token 123'}
  2807. data = {
  2808. 'username': 'Jenkins',
  2809. 'percent': 100,
  2810. 'comment': 'Tests passed',
  2811. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2812. 'uid': 'jenkins_build_pagure_100+seed',
  2813. }
  2814. output = self.app.post(
  2815. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2816. headers=headers, data=data)
  2817. self.assertEqual(output.status_code, 401)
  2818. data = json.loads(output.get_data(as_text=True))
  2819. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  2820. self.assertEqual(
  2821. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  2822. self.assertEqual(
  2823. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  2824. def test_flag_commit_invalid_status(self):
  2825. """ Test flagging a commit with an invalid status. """
  2826. repo_obj = pygit2.Repository(self.git_path)
  2827. commit = repo_obj.revparse_single('HEAD')
  2828. headers = {'Authorization': 'token aaabbbcccddd'}
  2829. data = {
  2830. 'username': 'Jenkins',
  2831. 'percent': 100,
  2832. 'comment': 'Tests passed',
  2833. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2834. 'status': 'foobar',
  2835. }
  2836. output = self.app.post(
  2837. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2838. headers=headers, data=data)
  2839. self.assertEqual(output.status_code, 400)
  2840. data = json.loads(output.get_data(as_text=True))
  2841. self.assertEqual(
  2842. data,
  2843. {
  2844. 'errors': {'status': ['Not a valid choice']},
  2845. 'error_code': 'EINVALIDREQ',
  2846. 'error': 'Invalid or incomplete input submitted'
  2847. }
  2848. )
  2849. def test_flag_commit_with_uid(self):
  2850. """ Test flagging a commit with provided uid. """
  2851. repo_obj = pygit2.Repository(self.git_path)
  2852. commit = repo_obj.revparse_single('HEAD')
  2853. headers = {'Authorization': 'token aaabbbcccddd'}
  2854. data = {
  2855. 'username': 'Jenkins',
  2856. 'percent': 100,
  2857. 'comment': 'Tests passed',
  2858. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2859. 'uid': 'jenkins_build_pagure_100+seed',
  2860. 'status': 'success',
  2861. }
  2862. output = self.app.post(
  2863. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2864. headers=headers, data=data)
  2865. self.assertEqual(output.status_code, 200)
  2866. data = json.loads(output.get_data(as_text=True))
  2867. data['flag']['date_created'] = '1510742565'
  2868. data['flag']['date_updated'] = '1510742565'
  2869. data['flag']['commit_hash'] = '62b49f00d489452994de5010565fab81'
  2870. expected_output = {
  2871. 'flag': {
  2872. 'comment': 'Tests passed',
  2873. 'commit_hash': '62b49f00d489452994de5010565fab81',
  2874. 'date_created': '1510742565',
  2875. 'date_updated': '1510742565',
  2876. 'percent': 100,
  2877. 'status': 'success',
  2878. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2879. 'user': {
  2880. 'default_email': 'bar@pingou.com',
  2881. 'emails': ['bar@pingou.com', 'foo@pingou.com'],
  2882. 'fullname': 'PY C',
  2883. 'name': 'pingou'},
  2884. 'username': 'Jenkins'
  2885. },
  2886. 'message': 'Flag added',
  2887. 'uid': 'jenkins_build_pagure_100+seed'
  2888. }
  2889. self.assertEqual(data, expected_output)
  2890. @patch('pagure.lib.notify.send_email')
  2891. def test_flag_commit_without_uid(self, mock_email):
  2892. """ Test flagging a commit with missing info.
  2893. Also ensure notifications aren't sent when they are not asked for.
  2894. """
  2895. repo_obj = pygit2.Repository(self.git_path)
  2896. commit = repo_obj.revparse_single('HEAD')
  2897. headers = {'Authorization': 'token aaabbbcccddd'}
  2898. data = {
  2899. 'username': 'Jenkins',
  2900. 'percent': 100,
  2901. 'comment': 'Tests passed',
  2902. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2903. 'status': 'success',
  2904. }
  2905. output = self.app.post(
  2906. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2907. headers=headers, data=data)
  2908. self.assertEqual(output.status_code, 200)
  2909. data = json.loads(output.get_data(as_text=True))
  2910. self.assertNotEqual(
  2911. data['uid'],
  2912. 'jenkins_build_pagure_100+seed'
  2913. )
  2914. data['flag']['date_created'] = '1510742565'
  2915. data['flag']['date_updated'] = '1510742565'
  2916. data['uid'] = 'b1de8f80defd4a81afe2e09f39678087'
  2917. expected_output = {
  2918. 'flag': {
  2919. 'comment': 'Tests passed',
  2920. 'commit_hash': commit.oid.hex,
  2921. 'date_created': '1510742565',
  2922. 'date_updated': '1510742565',
  2923. 'percent': 100,
  2924. 'status': 'success',
  2925. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2926. 'user': {
  2927. 'default_email': 'bar@pingou.com',
  2928. 'emails': ['bar@pingou.com', 'foo@pingou.com'],
  2929. 'fullname': 'PY C',
  2930. 'name': 'pingou'},
  2931. 'username': 'Jenkins'
  2932. },
  2933. 'message': 'Flag added',
  2934. 'uid': 'b1de8f80defd4a81afe2e09f39678087'
  2935. }
  2936. self.assertEqual(data, expected_output)
  2937. mock_email.assert_not_called()
  2938. @patch('pagure.lib.notify.send_email')
  2939. def test_flag_commit_with_notification(self, mock_email):
  2940. """ Test flagging a commit with notification enabled. """
  2941. # Enable commit notifications
  2942. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  2943. settings = repo.settings
  2944. settings['notify_on_commit_flag'] = True
  2945. repo.settings = settings
  2946. self.session.add(repo)
  2947. self.session.commit()
  2948. repo_obj = pygit2.Repository(self.git_path)
  2949. commit = repo_obj.revparse_single('HEAD')
  2950. headers = {'Authorization': 'token aaabbbcccddd'}
  2951. data = {
  2952. 'username': 'Jenkins',
  2953. 'percent': 100,
  2954. 'comment': 'Tests passed',
  2955. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2956. 'status': 'success',
  2957. }
  2958. output = self.app.post(
  2959. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2960. headers=headers, data=data)
  2961. self.assertEqual(output.status_code, 200)
  2962. data = json.loads(output.get_data(as_text=True))
  2963. self.assertNotEqual(
  2964. data['uid'],
  2965. 'jenkins_build_pagure_100+seed'
  2966. )
  2967. data['flag']['date_created'] = '1510742565'
  2968. data['flag']['date_updated'] = '1510742565'
  2969. data['uid'] = 'b1de8f80defd4a81afe2e09f39678087'
  2970. expected_output = {
  2971. 'flag': {
  2972. 'comment': 'Tests passed',
  2973. 'commit_hash': commit.oid.hex,
  2974. 'date_created': '1510742565',
  2975. 'date_updated': '1510742565',
  2976. 'percent': 100,
  2977. 'status': 'success',
  2978. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2979. 'user': {
  2980. 'default_email': 'bar@pingou.com',
  2981. 'emails': ['bar@pingou.com', 'foo@pingou.com'],
  2982. 'fullname': 'PY C',
  2983. 'name': 'pingou'},
  2984. 'username': 'Jenkins'
  2985. },
  2986. 'message': 'Flag added',
  2987. 'uid': 'b1de8f80defd4a81afe2e09f39678087'
  2988. }
  2989. self.assertEqual(data, expected_output)
  2990. mock_email.assert_called_once_with(
  2991. '\nJenkins flagged the commit '
  2992. '`' + commit.oid.hex + '` as success: '
  2993. 'Tests passed\n\n'
  2994. 'http://localhost.localdomain/test/c/' + commit.oid.hex + '\n',
  2995. 'Coommit #' + commit.oid.hex + ' - Jenkins: success',
  2996. 'bar@pingou.com',
  2997. in_reply_to='test-project-1',
  2998. mail_id='test-commit-1-1',
  2999. project_name='test',
  3000. user_from='Jenkins'
  3001. )
  3002. @patch.dict('pagure.config.config',
  3003. {
  3004. 'FLAG_STATUSES_LABELS':
  3005. {
  3006. 'pend!': 'label-info',
  3007. 'succeed!': 'label-success',
  3008. 'fail!': 'label-danger',
  3009. 'what?': 'label-warning',
  3010. },
  3011. 'FLAG_PENDING': 'pend!',
  3012. 'FLAG_SUCCESS': 'succeed!',
  3013. 'FLAG_FAILURE': 'fail!',
  3014. })
  3015. def test_flag_commit_with_custom_flags(self):
  3016. """ Test flagging when custom flags are set up
  3017. """
  3018. repo_obj = pygit2.Repository(self.git_path)
  3019. commit = repo_obj.revparse_single('HEAD')
  3020. headers = {'Authorization': 'token aaabbbcccddd'}
  3021. send_data = {
  3022. 'username': 'Jenkins',
  3023. 'percent': 100,
  3024. 'comment': 'Tests passed',
  3025. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  3026. 'status': 'succeed!',
  3027. }
  3028. output = self.app.post(
  3029. '/api/0/test/c/%s/flag' % commit.oid.hex,
  3030. headers=headers, data=send_data)
  3031. self.assertEqual(output.status_code, 200)
  3032. data = json.loads(output.get_data(as_text=True))
  3033. self.assertEqual(data['flag']['status'], 'succeed!')
  3034. # Try invalid flag status
  3035. send_data['status'] = 'nooooo....'
  3036. output = self.app.post(
  3037. '/api/0/test/c/%s/flag' % commit.oid.hex,
  3038. headers=headers, data=send_data)
  3039. self.assertEqual(output.status_code, 400)
  3040. data = json.loads(output.get_data(as_text=True))
  3041. self.assertEqual(
  3042. data,
  3043. {
  3044. 'errors': {'status': ['Not a valid choice']},
  3045. 'error_code': 'EINVALIDREQ',
  3046. 'error': 'Invalid or incomplete input submitted'
  3047. }
  3048. )
  3049. def test_commit_flags(self):
  3050. """ Test retrieving commit flags. """
  3051. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  3052. repo_obj = pygit2.Repository(self.git_path)
  3053. commit = repo_obj.revparse_single('HEAD')
  3054. # test with no flags
  3055. output = self.app.get('/api/0/test/c/%s/flag' % commit.oid.hex)
  3056. self.assertEqual(json.loads(output.get_data(as_text=True)), {'total_flags': 0, 'flags': []})
  3057. self.assertEqual(output.status_code, 200)
  3058. # add some flags and retrieve them
  3059. pagure.lib.query.add_commit_flag(
  3060. session=self.session,
  3061. repo=repo,
  3062. commit_hash=commit.oid.hex,
  3063. username='simple-koji-ci',
  3064. status='pending',
  3065. percent=None,
  3066. comment='Build is running',
  3067. url='https://koji.fp.o/koji...',
  3068. uid='uid',
  3069. user='foo',
  3070. token='aaabbbcccddd'
  3071. )
  3072. pagure.lib.query.add_commit_flag(
  3073. session=self.session,
  3074. repo=repo,
  3075. commit_hash=commit.oid.hex,
  3076. username='complex-koji-ci',
  3077. status='success',
  3078. percent=None,
  3079. comment='Build succeeded',
  3080. url='https://koji.fp.o/koji...',
  3081. uid='uid2',
  3082. user='foo',
  3083. token='aaabbbcccddd'
  3084. )
  3085. self.session.commit()
  3086. output = self.app.get('/api/0/test/c/%s/flag' % commit.oid.hex)
  3087. data = json.loads(output.get_data(as_text=True))
  3088. for f in data['flags']:
  3089. f['date_created'] = '1510742565'
  3090. f['date_updated'] = '1510742565'
  3091. f['commit_hash'] = '62b49f00d489452994de5010565fab81'
  3092. expected_output = {
  3093. "flags": [
  3094. {
  3095. "comment": "Build is running",
  3096. "commit_hash": "62b49f00d489452994de5010565fab81",
  3097. "date_created": "1510742565",
  3098. 'date_updated': '1510742565',
  3099. "percent": None,
  3100. "status": "pending",
  3101. "url": "https://koji.fp.o/koji...",
  3102. "user": {
  3103. "fullname": "foo bar",
  3104. "name": "foo"
  3105. },
  3106. "username": "simple-koji-ci"
  3107. },
  3108. {
  3109. "comment": "Build succeeded",
  3110. "commit_hash": "62b49f00d489452994de5010565fab81",
  3111. "date_created": "1510742565",
  3112. 'date_updated': '1510742565',
  3113. "percent": None,
  3114. "status": "success",
  3115. "url": "https://koji.fp.o/koji...",
  3116. "user": {
  3117. "fullname": "foo bar",
  3118. "name": "foo"
  3119. },
  3120. "username": "complex-koji-ci"
  3121. }
  3122. ],
  3123. "total_flags": 2
  3124. }
  3125. self.assertEqual(data, expected_output)
  3126. class PagureFlaskApiProjectModifyAclTests(tests.Modeltests):
  3127. """ Tests for the flask API of pagure for modifying ACLs in a project
  3128. """
  3129. maxDiff = None
  3130. def setUp(self):
  3131. """ Set up the environnment, ran before every tests. """
  3132. super(PagureFlaskApiProjectModifyAclTests, self).setUp()
  3133. tests.create_projects(self.session)
  3134. tests.create_tokens(self.session, project_id=None)
  3135. tests.create_tokens_acl(
  3136. self.session, 'aaabbbcccddd', 'modify_project')
  3137. project = pagure.lib.query._get_project(self.session, 'test')
  3138. self.assertEquals(
  3139. project.access_users,
  3140. {u'admin': [], u'commit': [], u'ticket': []}
  3141. )
  3142. def test_api_modify_acls_no_project(self):
  3143. """ Test the api_modify_acls method of the flask api when the project
  3144. doesn't exist """
  3145. headers = {'Authorization': 'token aaabbbcccddd'}
  3146. data = {
  3147. 'user_type': 'user',
  3148. 'name': 'bar',
  3149. 'acl': 'commit'
  3150. }
  3151. output = self.app.post(
  3152. '/api/0/test12345123/git/modifyacls',
  3153. headers=headers, data=data)
  3154. self.assertEqual(output.status_code, 404)
  3155. data = json.loads(output.get_data(as_text=True))
  3156. expected_output = {
  3157. 'error_code': 'ENOPROJECT',
  3158. 'error': 'Project not found'
  3159. }
  3160. self.assertEqual(data, expected_output)
  3161. def test_api_modify_acls_no_user(self):
  3162. """ Test the api_modify_acls method of the flask api when the user
  3163. doesn't exist """
  3164. headers = {'Authorization': 'token aaabbbcccddd'}
  3165. data = {
  3166. 'user_type': 'user',
  3167. 'name': 'nosuchuser',
  3168. 'acl': 'commit'
  3169. }
  3170. output = self.app.post(
  3171. '/api/0/test/git/modifyacls',
  3172. headers=headers, data=data)
  3173. self.assertEqual(output.status_code, 404)
  3174. data = json.loads(output.get_data(as_text=True))
  3175. expected_output = {
  3176. 'error': 'No such user found',
  3177. 'error_code': u'ENOUSER'
  3178. }
  3179. self.assertEqual(data, expected_output)
  3180. def test_api_modify_acls_no_group(self):
  3181. """ Test the api_modify_acls method of the flask api when the group
  3182. doesn't exist """
  3183. headers = {'Authorization': 'token aaabbbcccddd'}
  3184. data = {
  3185. 'user_type': 'group',
  3186. 'name': 'nosuchgroup',
  3187. 'acl': 'commit'
  3188. }
  3189. output = self.app.post(
  3190. '/api/0/test/git/modifyacls',
  3191. headers=headers, data=data)
  3192. self.assertEqual(output.status_code, 404)
  3193. data = json.loads(output.get_data(as_text=True))
  3194. expected_output = {
  3195. 'error': 'Group not found',
  3196. 'error_code': 'ENOGROUP'
  3197. }
  3198. self.assertEqual(data, expected_output)
  3199. def test_api_modify_acls_no_permission(self):
  3200. """ Test the api_modify_acls method of the flask api when the user
  3201. doesn't have permissions """
  3202. item = pagure.lib.model.Token(
  3203. id='foo_token2',
  3204. user_id=2,
  3205. project_id=None,
  3206. expiration=datetime.datetime.utcnow()
  3207. + datetime.timedelta(days=30)
  3208. )
  3209. self.session.add(item)
  3210. self.session.commit()
  3211. tests.create_tokens_acl(
  3212. self.session, 'foo_token2', 'modify_project')
  3213. headers = {'Authorization': 'token foo_token2'}
  3214. data = {
  3215. 'user_type': 'user',
  3216. 'name': 'foo',
  3217. 'acl': 'commit'
  3218. }
  3219. output = self.app.post(
  3220. '/api/0/test/git/modifyacls',
  3221. headers=headers, data=data)
  3222. self.assertEqual(output.status_code, 401)
  3223. data = json.loads(output.get_data(as_text=True))
  3224. expected_output = {
  3225. 'error': 'You are not allowed to modify this project',
  3226. 'error_code': 'EMODIFYPROJECTNOTALLOWED'
  3227. }
  3228. self.assertEqual(data, expected_output)
  3229. def test_api_modify_acls_neither_user_nor_group(self):
  3230. """ Test the api_modify_acls method of the flask api when neither
  3231. user nor group was set """
  3232. headers = {'Authorization': 'token aaabbbcccddd'}
  3233. data = {
  3234. 'acl': 'commit'
  3235. }
  3236. output = self.app.post(
  3237. '/api/0/test/git/modifyacls',
  3238. headers=headers, data=data)
  3239. self.assertEqual(output.status_code, 400)
  3240. data = json.loads(output.get_data(as_text=True))
  3241. expected_output = {
  3242. 'error': 'Invalid or incomplete input submitted',
  3243. 'error_code': 'EINVALIDREQ',
  3244. 'errors': {'name': ['This field is required.'],
  3245. 'user_type': ['Not a valid choice']}
  3246. }
  3247. self.assertEqual(data, expected_output)
  3248. def test_api_modify_acls_invalid_acl(self):
  3249. """ Test the api_modify_acls method of the flask api when the ACL
  3250. doesn't exist. Must be one of ticket, commit or admin. """
  3251. headers = {'Authorization': 'token aaabbbcccddd'}
  3252. data = {
  3253. 'user_type': 'user',
  3254. 'name': 'bar',
  3255. 'acl': 'invalidacl'
  3256. }
  3257. output = self.app.post(
  3258. '/api/0/test/git/modifyacls',
  3259. headers=headers, data=data)
  3260. self.assertEqual(output.status_code, 400)
  3261. data = json.loads(output.get_data(as_text=True))
  3262. expected_output = {
  3263. 'error': 'Invalid or incomplete input submitted',
  3264. 'error_code': 'EINVALIDREQ',
  3265. 'errors': {
  3266. 'acl': ['Not a valid choice']
  3267. }
  3268. }
  3269. self.assertEqual(data, expected_output)
  3270. def test_api_modify_acls_user(self):
  3271. """ Test the api_modify_acls method of the flask api for
  3272. setting an ACL for a user. """
  3273. headers = {'Authorization': 'token aaabbbcccddd'}
  3274. data = {
  3275. 'user_type': 'user',
  3276. 'name': 'foo',
  3277. 'acl': 'commit'
  3278. }
  3279. output = self.app.post(
  3280. '/api/0/test/git/modifyacls',
  3281. headers=headers, data=data)
  3282. self.assertEqual(output.status_code, 200)
  3283. data = json.loads(output.get_data(as_text=True))
  3284. data['date_created'] = '1510742565'
  3285. data['date_modified'] = '1510742566'
  3286. expected_output = {
  3287. 'access_groups': {'admin': [], 'commit': [], 'ticket': []},
  3288. 'access_users': {'admin': [],
  3289. 'commit': ['foo'],
  3290. 'owner': ['pingou'],
  3291. 'ticket': []},
  3292. 'close_status':
  3293. ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate'],
  3294. 'custom_keys': [],
  3295. 'date_created': '1510742565',
  3296. 'date_modified': '1510742566',
  3297. 'description': 'test project #1',
  3298. 'fullname': 'test',
  3299. 'id': 1,
  3300. 'milestones': {},
  3301. 'name': 'test',
  3302. 'namespace': None,
  3303. 'parent': None,
  3304. 'priorities': {},
  3305. 'tags': [],
  3306. 'url_path': 'test',
  3307. 'user': {'fullname': 'PY C', 'name': 'pingou'}
  3308. }
  3309. self.assertEqual(data, expected_output)
  3310. def test_api_modify_acls_group(self):
  3311. """ Test the api_modify_acls method of the flask api for
  3312. setting an ACL for a group. """
  3313. headers = {'Authorization': 'token aaabbbcccddd'}
  3314. # Create a group
  3315. msg = pagure.lib.query.add_group(
  3316. self.session,
  3317. group_name='baz',
  3318. display_name='baz group',
  3319. description=None,
  3320. group_type='bar',
  3321. user='foo',
  3322. is_admin=False,
  3323. blacklist=[],
  3324. )
  3325. self.session.commit()
  3326. self.assertEqual(msg, 'User `foo` added to the group `baz`.')
  3327. data = {
  3328. 'user_type': 'group',
  3329. 'name': 'baz',
  3330. 'acl': 'ticket'
  3331. }
  3332. output = self.app.post(
  3333. '/api/0/test/git/modifyacls',
  3334. headers=headers, data=data)
  3335. self.assertEqual(output.status_code, 200)
  3336. data = json.loads(output.get_data(as_text=True))
  3337. data['date_created'] = '1510742565'
  3338. data['date_modified'] = '1510742566'
  3339. expected_output = {
  3340. 'access_groups': {
  3341. 'admin': [],
  3342. 'commit': [],
  3343. 'ticket': ['baz']
  3344. },
  3345. 'access_users': {
  3346. 'admin': [],
  3347. 'commit': [],
  3348. 'owner': ['pingou'],
  3349. 'ticket': []
  3350. },
  3351. 'close_status': [
  3352. 'Invalid',
  3353. 'Insufficient data',
  3354. 'Fixed',
  3355. 'Duplicate'
  3356. ],
  3357. 'custom_keys': [],
  3358. 'date_created': '1510742565',
  3359. 'date_modified': '1510742566',
  3360. 'description': 'test project #1',
  3361. 'fullname': 'test',
  3362. 'id': 1,
  3363. 'milestones': {},
  3364. 'name': 'test',
  3365. 'namespace': None,
  3366. 'parent': None,
  3367. 'priorities': {},
  3368. 'tags': [],
  3369. 'url_path': 'test',
  3370. 'user': {'fullname': 'PY C', 'name': 'pingou'}
  3371. }
  3372. self.assertEqual(data, expected_output)
  3373. def test_api_modify_acls_no_acl(self):
  3374. """ Test the api_modify_acls method of the flask api when no ACL
  3375. are specified. """
  3376. headers = {'Authorization': 'token aaabbbcccddd'}
  3377. project = pagure.lib.query._get_project(self.session, 'test')
  3378. self.assertEquals(
  3379. project.access_users,
  3380. {u'admin': [], u'commit': [], u'ticket': []}
  3381. )
  3382. data = {
  3383. 'user_type': 'user',
  3384. 'name': 'foo',
  3385. }
  3386. output = self.app.post(
  3387. '/api/0/test/git/modifyacls', headers=headers, data=data)
  3388. self.assertEqual(output.status_code, 400)
  3389. data = json.loads(output.get_data(as_text=True))
  3390. expected_output = {
  3391. "error": "Invalid or incomplete input submitted",
  3392. "error_code": "EINVALIDREQ",
  3393. "errors": "User does not have any access on the repo"
  3394. }
  3395. self.assertEqual(data, expected_output)
  3396. def test_api_modify_acls_remove_own_acl_no_access(self):
  3397. """ Test the api_modify_acls method of the flask api when no ACL
  3398. are specified, so the user tries to remove their own access but the
  3399. user is the project owner. """
  3400. headers = {'Authorization': 'token aaabbbcccddd'}
  3401. data = {
  3402. 'user_type': 'user',
  3403. 'name': 'pingou',
  3404. }
  3405. output = self.app.post(
  3406. '/api/0/test/git/modifyacls', headers=headers, data=data)
  3407. self.assertEqual(output.status_code, 400)
  3408. data = json.loads(output.get_data(as_text=True))
  3409. expected_output = {
  3410. "error": "Invalid or incomplete input submitted",
  3411. "error_code": "EINVALIDREQ",
  3412. "errors": "User does not have any access on the repo"
  3413. }
  3414. self.assertEqual(data, expected_output)
  3415. def test_api_modify_acls_remove_own_acl_(self):
  3416. """ Test the api_modify_acls method of the flask api when no ACL
  3417. are specified, so the user tries to remove their own access but the
  3418. user is the project owner. """
  3419. # Add the user `foo` to the project
  3420. self.test_api_modify_acls_user()
  3421. # Ensure `foo` was properly added:
  3422. project = pagure.lib.query._get_project(self.session, 'test')
  3423. user_foo = pagure.lib.query.search_user(self.session, username='foo')
  3424. self.assertEquals(
  3425. project.access_users,
  3426. {u'admin': [], u'commit': [user_foo], u'ticket': []}
  3427. )
  3428. # Create an API token for `foo` for the project `test`
  3429. item = pagure.lib.model.Token(
  3430. id='foo_test_token',
  3431. user_id=2, # foo
  3432. project_id=1, # test
  3433. expiration=datetime.datetime.utcnow() + datetime.timedelta(days=10)
  3434. )
  3435. self.session.add(item)
  3436. self.session.commit()
  3437. tests.create_tokens_acl(
  3438. self.session, 'foo_test_token', 'modify_project')
  3439. headers = {'Authorization': 'token foo_test_token'}
  3440. data = {
  3441. 'user_type': 'user',
  3442. 'name': 'foo',
  3443. }
  3444. output = self.app.post(
  3445. '/api/0/test/git/modifyacls', headers=headers, data=data)
  3446. self.assertEqual(output.status_code, 200)
  3447. data = json.loads(output.get_data(as_text=True))
  3448. data['date_created'] = '1510742565'
  3449. data['date_modified'] = '1510742566'
  3450. expected_output = {
  3451. "access_groups": {
  3452. "admin": [],
  3453. "commit": [],
  3454. "ticket": []
  3455. },
  3456. "access_users": {
  3457. "admin": [],
  3458. "commit": [],
  3459. "owner": [
  3460. "pingou"
  3461. ],
  3462. "ticket": []
  3463. },
  3464. "close_status": [
  3465. "Invalid",
  3466. "Insufficient data",
  3467. "Fixed",
  3468. "Duplicate"
  3469. ],
  3470. "custom_keys": [],
  3471. "date_created": "1510742565",
  3472. "date_modified": "1510742566",
  3473. "description": "test project #1",
  3474. "fullname": "test",
  3475. "id": 1,
  3476. "milestones": {},
  3477. "name": "test",
  3478. "namespace": None,
  3479. "parent": None,
  3480. "priorities": {},
  3481. "tags": [],
  3482. "url_path": "test",
  3483. "user": {
  3484. "fullname": "PY C",
  3485. "name": "pingou"
  3486. }
  3487. }
  3488. self.assertEqual(data, expected_output)
  3489. # Ensure `foo` was properly removed
  3490. self.session = pagure.lib.query.create_session(self.dbpath)
  3491. project = pagure.lib.query._get_project(self.session, 'test')
  3492. self.assertEquals(
  3493. project.access_users,
  3494. {u'admin': [], u'commit': [], u'ticket': []}
  3495. )
  3496. def test_api_modify_acls_remove_someone_else_acl(self):
  3497. """ Test the api_modify_acls method of the flask api an admin tries
  3498. to remove access from someone else. """
  3499. # Add the user `foo` to the project
  3500. self.test_api_modify_acls_user()
  3501. # Ensure `foo` was properly added:
  3502. project = pagure.lib.query._get_project(self.session, 'test')
  3503. user_foo = pagure.lib.query.search_user(self.session, username='foo')
  3504. self.assertEquals(
  3505. project.access_users,
  3506. {u'admin': [], u'commit': [user_foo], u'ticket': []}
  3507. )
  3508. headers = {'Authorization': 'token aaabbbcccddd'}
  3509. data = {
  3510. 'user_type': 'user',
  3511. 'name': 'foo',
  3512. }
  3513. output = self.app.post(
  3514. '/api/0/test/git/modifyacls', headers=headers, data=data)
  3515. self.assertEqual(output.status_code, 200)
  3516. data = json.loads(output.get_data(as_text=True))
  3517. data['date_created'] = '1510742565'
  3518. data['date_modified'] = '1510742566'
  3519. expected_output = {
  3520. "access_groups": {
  3521. "admin": [],
  3522. "commit": [],
  3523. "ticket": []
  3524. },
  3525. "access_users": {
  3526. "admin": [],
  3527. "commit": [],
  3528. "owner": [
  3529. "pingou"
  3530. ],
  3531. "ticket": []
  3532. },
  3533. "close_status": [
  3534. "Invalid",
  3535. "Insufficient data",
  3536. "Fixed",
  3537. "Duplicate"
  3538. ],
  3539. "custom_keys": [],
  3540. "date_created": "1510742565",
  3541. "date_modified": "1510742566",
  3542. "description": "test project #1",
  3543. "fullname": "test",
  3544. "id": 1,
  3545. "milestones": {},
  3546. "name": "test",
  3547. "namespace": None,
  3548. "parent": None,
  3549. "priorities": {},
  3550. "tags": [],
  3551. "url_path": "test",
  3552. "user": {
  3553. "fullname": "PY C",
  3554. "name": "pingou"
  3555. }
  3556. }
  3557. self.assertEqual(data, expected_output)
  3558. # Ensure `foo` was properly removed
  3559. self.session = pagure.lib.query.create_session(self.dbpath)
  3560. project = pagure.lib.query._get_project(self.session, 'test')
  3561. self.assertEquals(
  3562. project.access_users,
  3563. {u'admin': [], u'commit': [], u'ticket': []}
  3564. )
  3565. class PagureFlaskApiProjectOptionsTests(tests.Modeltests):
  3566. """ Tests for the flask API of pagure for modifying options ofs a project
  3567. """
  3568. maxDiff = None
  3569. def setUp(self):
  3570. """ Set up the environnment, ran before every tests. """
  3571. super(PagureFlaskApiProjectOptionsTests, self).setUp()
  3572. tests.create_projects(self.session)
  3573. tests.create_tokens(self.session, project_id=None)
  3574. tests.create_tokens_acl(
  3575. self.session, 'aaabbbcccddd', 'modify_project')
  3576. project = pagure.lib.query._get_project(self.session, 'test')
  3577. self.assertEquals(
  3578. project.access_users,
  3579. {u'admin': [], u'commit': [], u'ticket': []}
  3580. )
  3581. def test_api_get_project_options_wrong_project(self):
  3582. """ Test accessing api_get_project_options w/o auth header. """
  3583. headers = {'Authorization': 'token aaabbbcccddd'}
  3584. output = self.app.get('/api/0/unknown/options', headers=headers)
  3585. self.assertEqual(output.status_code, 404)
  3586. data = json.loads(output.get_data(as_text=True))
  3587. self.assertEqual(
  3588. data,
  3589. {u'error': u'Project not found', u'error_code': u'ENOPROJECT'}
  3590. )
  3591. def test_api_get_project_options_wo_header(self):
  3592. """ Test accessing api_get_project_options w/o auth header. """
  3593. output = self.app.get('/api/0/test/options')
  3594. self.assertEqual(output.status_code, 401)
  3595. data = json.loads(output.get_data(as_text=True))
  3596. self.assertEqual(
  3597. data,
  3598. {
  3599. u'error': u'Invalid or expired token. Please visit '
  3600. 'http://localhost.localdomain/settings#api-keys to get '
  3601. 'or renew your API token.',
  3602. u'error_code': u'EINVALIDTOK'
  3603. }
  3604. )
  3605. def test_api_get_project_options_w_header(self):
  3606. """ Test accessing api_get_project_options w/ auth header. """
  3607. headers = {'Authorization': 'token aaabbbcccddd'}
  3608. output = self.app.get('/api/0/test/options', headers=headers)
  3609. self.assertEqual(output.status_code, 200)
  3610. data = json.loads(output.get_data(as_text=True))
  3611. self.assertEqual(
  3612. data,
  3613. {
  3614. "settings": {
  3615. "Enforce_signed-off_commits_in_pull-request": False,
  3616. "Minimum_score_to_merge_pull-request": -1,
  3617. "Only_assignee_can_merge_pull-request": False,
  3618. "Web-hooks": None,
  3619. "always_merge": False,
  3620. "disable_non_fast-forward_merges": False,
  3621. "fedmsg_notifications": True,
  3622. "issue_tracker": True,
  3623. "issue_tracker_read_only": False,
  3624. "issues_default_to_private": False,
  3625. "mqtt_notifications": True,
  3626. "notify_on_commit_flag": False,
  3627. "notify_on_pull-request_flag": False,
  3628. "open_metadata_access_to_all": False,
  3629. "project_documentation": False,
  3630. "pull_request_access_only": False,
  3631. "pull_requests": True,
  3632. "stomp_notifications": True
  3633. },
  3634. "status": "ok"
  3635. }
  3636. )
  3637. def test_api_modify_project_options_wrong_project(self):
  3638. """ Test accessing api_modify_project_options w/ an invalid project.
  3639. """
  3640. headers = {'Authorization': 'token aaabbbcccddd'}
  3641. output = self.app.post('/api/0/unknown/options/update', headers=headers)
  3642. self.assertEqual(output.status_code, 404)
  3643. data = json.loads(output.get_data(as_text=True))
  3644. self.assertEqual(
  3645. data,
  3646. {u'error': u'Project not found', u'error_code': u'ENOPROJECT'}
  3647. )
  3648. def test_api_modify_project_options_wo_header(self):
  3649. """ Test accessing api_modify_project_options w/o auth header. """
  3650. output = self.app.post('/api/0/test/options/update')
  3651. self.assertEqual(output.status_code, 401)
  3652. data = json.loads(output.get_data(as_text=True))
  3653. self.assertEqual(
  3654. data,
  3655. {
  3656. u'error': u'Invalid or expired token. Please visit '
  3657. 'http://localhost.localdomain/settings#api-keys to get '
  3658. 'or renew your API token.',
  3659. u'error_code': u'EINVALIDTOK'
  3660. }
  3661. )
  3662. def test_api_modify_project_options_no_data(self):
  3663. """ Test accessing api_modify_project_options w/ auth header. """
  3664. # check before
  3665. headers = {'Authorization': 'token aaabbbcccddd'}
  3666. output = self.app.get('/api/0/test/options', headers=headers)
  3667. self.assertEqual(output.status_code, 200)
  3668. before = json.loads(output.get_data(as_text=True))
  3669. self.assertEqual(
  3670. before,
  3671. {
  3672. "settings": {
  3673. "Enforce_signed-off_commits_in_pull-request": False,
  3674. "Minimum_score_to_merge_pull-request": -1,
  3675. "Only_assignee_can_merge_pull-request": False,
  3676. "Web-hooks": None,
  3677. "always_merge": False,
  3678. "disable_non_fast-forward_merges": False,
  3679. "fedmsg_notifications": True,
  3680. "issue_tracker": True,
  3681. "issue_tracker_read_only": False,
  3682. "issues_default_to_private": False,
  3683. "mqtt_notifications": True,
  3684. "notify_on_commit_flag": False,
  3685. "notify_on_pull-request_flag": False,
  3686. "open_metadata_access_to_all": False,
  3687. "project_documentation": False,
  3688. "pull_request_access_only": False,
  3689. "pull_requests": True,
  3690. "stomp_notifications": True
  3691. },
  3692. "status": "ok"
  3693. }
  3694. )
  3695. # Do not update anything
  3696. data = {}
  3697. output = self.app.post(
  3698. '/api/0/test/options/update', headers=headers, data=data)
  3699. self.assertEqual(output.status_code, 200)
  3700. data = json.loads(output.get_data(as_text=True))
  3701. self.assertEqual(
  3702. data,
  3703. {
  3704. u'message': u'No settings to change',
  3705. u'status': u'ok'
  3706. }
  3707. )
  3708. # check after
  3709. headers = {'Authorization': 'token aaabbbcccddd'}
  3710. output = self.app.get('/api/0/test/options', headers=headers)
  3711. self.assertEqual(output.status_code, 200)
  3712. after = json.loads(output.get_data(as_text=True))
  3713. self.assertEqual(after, before)
  3714. def test_api_modify_project_options(self):
  3715. """ Test accessing api_modify_project_options w/ auth header. """
  3716. # check before
  3717. headers = {'Authorization': 'token aaabbbcccddd'}
  3718. output = self.app.get('/api/0/test/options', headers=headers)
  3719. self.assertEqual(output.status_code, 200)
  3720. before = json.loads(output.get_data(as_text=True))
  3721. self.assertEqual(
  3722. before,
  3723. {
  3724. "settings": {
  3725. "Enforce_signed-off_commits_in_pull-request": False,
  3726. "Minimum_score_to_merge_pull-request": -1,
  3727. "Only_assignee_can_merge_pull-request": False,
  3728. "Web-hooks": None,
  3729. "always_merge": False,
  3730. "disable_non_fast-forward_merges": False,
  3731. "fedmsg_notifications": True,
  3732. "issue_tracker": True,
  3733. "issue_tracker_read_only": False,
  3734. "issues_default_to_private": False,
  3735. "mqtt_notifications": True,
  3736. "notify_on_commit_flag": False,
  3737. "notify_on_pull-request_flag": False,
  3738. "open_metadata_access_to_all": False,
  3739. "project_documentation": False,
  3740. "pull_request_access_only": False,
  3741. "pull_requests": True,
  3742. "stomp_notifications": True
  3743. },
  3744. "status": "ok"
  3745. }
  3746. )
  3747. # Update: `issues_default_to_private`.
  3748. data = {"issues_default_to_private": True}
  3749. output = self.app.post(
  3750. '/api/0/test/options/update', headers=headers, data=data)
  3751. self.assertEqual(output.status_code, 200)
  3752. data = json.loads(output.get_data(as_text=True))
  3753. self.assertEqual(
  3754. data,
  3755. {
  3756. u'message': u'Edited successfully settings of repo: test',
  3757. u'status': u'ok'
  3758. }
  3759. )
  3760. # check after
  3761. headers = {'Authorization': 'token aaabbbcccddd'}
  3762. output = self.app.get('/api/0/test/options', headers=headers)
  3763. self.assertEqual(output.status_code, 200)
  3764. after = json.loads(output.get_data(as_text=True))
  3765. self.assertNotEqual(before, after)
  3766. before["settings"]["issues_default_to_private"] = True
  3767. self.assertEqual(after, before)
  3768. class PagureFlaskApiProjectCreateAPITokenTests(tests.Modeltests):
  3769. """ Tests for the flask API of pagure for creating user project API token
  3770. """
  3771. maxDiff = None
  3772. def setUp(self):
  3773. """ Set up the environnment, ran before every tests. """
  3774. super(PagureFlaskApiProjectCreateAPITokenTests, self).setUp()
  3775. tests.create_projects(self.session)
  3776. tests.create_tokens(self.session, project_id=None)
  3777. tests.create_tokens_acl(
  3778. self.session, 'aaabbbcccddd', 'modify_project')
  3779. def test_api_createapitoken_as_owner(self):
  3780. """ Test accessing api_project_create_token as owner. """
  3781. headers = {'Authorization': 'token aaabbbcccddd'}
  3782. project = pagure.lib.query._get_project(self.session, 'test')
  3783. tdescription = 'my new token'
  3784. # Call the api with pingou user token and verify content
  3785. data = {
  3786. 'description': tdescription,
  3787. 'acls': ['pull_request_merge', 'pull_request_comment']
  3788. }
  3789. output = self.app.post('/api/0/test/token/new',
  3790. headers=headers, data=data)
  3791. self.assertEqual(output.status_code, 200)
  3792. data = json.loads(output.get_data(as_text=True))
  3793. tid = pagure.lib.query.search_token(
  3794. self.session, None, description=tdescription)[0].id
  3795. self.assertEqual(
  3796. data,
  3797. {"token": {
  3798. "description": tdescription,
  3799. "id": tid
  3800. }
  3801. }
  3802. )
  3803. # Create a second token but with faulty acl
  3804. # Call the api with pingou user token and error code
  3805. data = {
  3806. 'description': tdescription,
  3807. 'acl': ['foo', 'bar']
  3808. }
  3809. output = self.app.post('/api/0/test/token/new',
  3810. headers=headers, data=data)
  3811. self.assertEqual(output.status_code, 400)
  3812. def test_api_createapitoken_as_admin(self):
  3813. """ Test accessing api_project_create_token as admin. """
  3814. project = pagure.lib.query._get_project(self.session, 'test')
  3815. # Set the foo user as test project admin
  3816. pagure.lib.query.add_user_to_project(
  3817. self.session, project,
  3818. new_user='foo',
  3819. user='pingou',
  3820. access='admin'
  3821. )
  3822. self.session.commit()
  3823. # Create modify_project token for foo user
  3824. token = pagure.lib.query.add_token_to_user(
  3825. self.session,
  3826. project=None,
  3827. acls=['modify_project'],
  3828. username='foo')
  3829. # Call the connector with foo user token and verify content
  3830. headers = {'Authorization': 'token %s' % token.id}
  3831. tdescription = 'my new token'
  3832. # Call the api with pingou user token and verify content
  3833. data = {
  3834. 'description': tdescription,
  3835. 'acls': ['pull_request_merge', 'pull_request_comment']
  3836. }
  3837. output = self.app.post('/api/0/test/token/new',
  3838. headers=headers, data=data)
  3839. self.assertEqual(output.status_code, 200)
  3840. data = json.loads(output.get_data(as_text=True))
  3841. tid = pagure.lib.query.search_token(
  3842. self.session, None, user='foo', description=tdescription)[0].id
  3843. self.assertEqual(
  3844. data,
  3845. {"token": {
  3846. "description": tdescription,
  3847. "id": tid
  3848. }
  3849. }
  3850. )
  3851. def test_api_createapitoken_as_unauthorized(self):
  3852. """ Test accessing api_project_create_token as project admin
  3853. but with unauthorized token ACL.
  3854. """
  3855. project = pagure.lib.query._get_project(self.session, 'test')
  3856. # Set the foo user as test project admin
  3857. pagure.lib.query.add_user_to_project(
  3858. self.session, project,
  3859. new_user='foo',
  3860. user='pingou',
  3861. access='admin'
  3862. )
  3863. self.session.commit()
  3864. # Create modify_project token for foo user
  3865. pagure.lib.query.add_token_to_user(
  3866. self.session,
  3867. project=None,
  3868. acls=['create_branch'],
  3869. username='foo')
  3870. mtoken = pagure.lib.query.search_token(
  3871. self.session, ['create_branch'], user='foo')[0]
  3872. # Call the connector with foo user token and verify content
  3873. headers = {'Authorization': 'token %s' % mtoken.id}
  3874. tdescription = 'my new token'
  3875. # Call the api with pingou user token and verify content
  3876. data = {
  3877. 'description': tdescription,
  3878. 'acls': ['pull_request_merge', 'pull_request_comment']
  3879. }
  3880. output = self.app.post('/api/0/test/token/new',
  3881. headers=headers, data=data)
  3882. self.assertEqual(output.status_code, 401)
  3883. def test_api_createapitoken_as_unauthorized_2(self):
  3884. """ Test accessing api_project_create_token as project user
  3885. with unauthorized token ACL.
  3886. """
  3887. project = pagure.lib.query._get_project(self.session, 'test')
  3888. # Set the foo user as test project admin
  3889. pagure.lib.query.add_user_to_project(
  3890. self.session, project,
  3891. new_user='foo',
  3892. user='pingou',
  3893. access='commit'
  3894. )
  3895. self.session.commit()
  3896. # Create modify_project token for foo user
  3897. pagure.lib.query.add_token_to_user(
  3898. self.session,
  3899. project=None,
  3900. acls=['modify_project'],
  3901. username='foo')
  3902. mtoken = pagure.lib.query.search_token(
  3903. self.session, ['modify_project'], user='foo')[0]
  3904. # Call the connector with foo user token and verify content
  3905. headers = {'Authorization': 'token %s' % mtoken.id}
  3906. tdescription = 'my new token'
  3907. # Call the api with pingou user token and verify content
  3908. data = {
  3909. 'description': tdescription,
  3910. 'acls': ['pull_request_merge', 'pull_request_comment']
  3911. }
  3912. output = self.app.post('/api/0/test/token/new',
  3913. headers=headers, data=data)
  3914. self.assertEqual(output.status_code, 401)
  3915. class PagureFlaskApiProjectConnectorTests(tests.Modeltests):
  3916. """ Tests for the flask API of pagure for getting connector of a project
  3917. """
  3918. maxDiff = None
  3919. def setUp(self):
  3920. """ Set up the environnment, ran before every tests. """
  3921. super(PagureFlaskApiProjectConnectorTests, self).setUp()
  3922. tests.create_projects(self.session)
  3923. tests.create_tokens(self.session, project_id=None)
  3924. tests.create_tokens_acl(
  3925. self.session, 'aaabbbcccddd', 'modify_project')
  3926. def test_api_get_project_connector_as_owner(self):
  3927. """ Test accessing api_get_project_connector as project owner. """
  3928. project = pagure.lib.query._get_project(self.session, 'test')
  3929. # Create witness project Token for pingou user
  3930. pagure.lib.query.add_token_to_user(
  3931. self.session,
  3932. project=project,
  3933. acls=['pull_request_merge'],
  3934. username='pingou')
  3935. ctokens = pagure.lib.query.search_token(
  3936. self.session, ['pull_request_merge'], user='pingou')
  3937. self.assertEqual(len(ctokens), 1)
  3938. # Call the connector with pingou user token and verify content
  3939. headers = {'Authorization': 'token aaabbbcccddd'}
  3940. output = self.app.get('/api/0/test/connector', headers=headers)
  3941. self.assertEqual(output.status_code, 200)
  3942. data = json.loads(output.get_data(as_text=True))
  3943. self.assertEqual(
  3944. data,
  3945. {"connector": {
  3946. "hook_token": project.hook_token,
  3947. "api_tokens": [
  3948. {'description': t.description,
  3949. 'id': t.id,
  3950. 'expired': False} for t in ctokens]
  3951. },
  3952. "status": "ok"
  3953. }
  3954. )
  3955. def test_api_get_project_connector_as_admin(self):
  3956. """ Test accessing api_get_project_connector as project admin """
  3957. project = pagure.lib.query._get_project(self.session, 'test')
  3958. # Set the foo user as test project admin
  3959. pagure.lib.query.add_user_to_project(
  3960. self.session, project,
  3961. new_user='foo',
  3962. user='pingou',
  3963. access='admin'
  3964. )
  3965. self.session.commit()
  3966. # Create modify_project token for foo user
  3967. pagure.lib.query.add_token_to_user(
  3968. self.session,
  3969. project=None,
  3970. acls=['modify_project'],
  3971. username='foo')
  3972. mtoken = pagure.lib.query.search_token(
  3973. self.session, ['modify_project'], user='foo')[0]
  3974. # Create witness project Token for foo user
  3975. pagure.lib.query.add_token_to_user(
  3976. self.session,
  3977. project=project,
  3978. acls=['pull_request_merge'],
  3979. username='foo')
  3980. ctokens = pagure.lib.query.search_token(
  3981. self.session, ['pull_request_merge'], user='foo')
  3982. self.assertEqual(len(ctokens), 1)
  3983. # Call the connector with foo user token and verify content
  3984. headers = {'Authorization': 'token %s' % mtoken.id}
  3985. output = self.app.get('/api/0/test/connector', headers=headers)
  3986. self.assertEqual(output.status_code, 200)
  3987. data = json.loads(output.get_data(as_text=True))
  3988. self.assertEqual(
  3989. data,
  3990. {"connector": {
  3991. "hook_token": project.hook_token,
  3992. "api_tokens": [
  3993. {'description': t.description,
  3994. 'id': t.id,
  3995. 'expired': False} for t in ctokens]
  3996. },
  3997. "status": "ok"
  3998. }
  3999. )
  4000. def test_api_get_project_connector_as_unauthorized(self):
  4001. """ Test accessing api_get_project_connector as project admin
  4002. but with unauthorized token ACL
  4003. """
  4004. project = pagure.lib.query._get_project(self.session, 'test')
  4005. # Set the foo user as test project admin
  4006. pagure.lib.query.add_user_to_project(
  4007. self.session, project,
  4008. new_user='foo',
  4009. user='pingou',
  4010. access='admin'
  4011. )
  4012. self.session.commit()
  4013. # Create modify_project token for foo user
  4014. pagure.lib.query.add_token_to_user(
  4015. self.session,
  4016. project=None,
  4017. acls=['create_project'],
  4018. username='foo')
  4019. mtoken = pagure.lib.query.search_token(
  4020. self.session, ['create_project'], user='foo')[0]
  4021. # Call the connector with foo user token and verify unauthorized
  4022. headers = {'Authorization': 'token %s' % mtoken.id}
  4023. output = self.app.get('/api/0/test/connector', headers=headers)
  4024. self.assertEqual(output.status_code, 401)
  4025. def test_api_get_project_connector_as_unauthorized_2(self):
  4026. """ Test accessing api_get_project_connector as project
  4027. but with unauthorized token ACL
  4028. """
  4029. project = pagure.lib.query._get_project(self.session, 'test')
  4030. # Set the foo user as test project admin
  4031. pagure.lib.query.add_user_to_project(
  4032. self.session, project,
  4033. new_user='foo',
  4034. user='pingou',
  4035. access='commit'
  4036. )
  4037. self.session.commit()
  4038. # Create modify_project token for foo user
  4039. pagure.lib.query.add_token_to_user(
  4040. self.session,
  4041. project=None,
  4042. acls=['modify_project'],
  4043. username='foo')
  4044. mtoken = pagure.lib.query.search_token(
  4045. self.session, ['modify_project'], user='foo')[0]
  4046. # Call the connector with foo user token and verify unauthorized
  4047. headers = {'Authorization': 'token %s' % mtoken.id}
  4048. output = self.app.get('/api/0/test/connector', headers=headers)
  4049. self.assertEqual(output.status_code, 401)
  4050. if __name__ == '__main__':
  4051. unittest.main(verbosity=2)